Property Drawer Overlapping Anything Underneath It

I keep going around and around with this property drawer I have been working on. I have it working the way I want but I cannot stop it from overlapping anything that comes after it in the inspector. I found one person in the forums that overrode GetPropertyHeight but I couldn’t get that to work. Here is a simplified version of the code I am using…

SampleClass.js

#pragma strict
class SampleClass extends Object{
var first : float;
var second : float;
var third : float;
}

SampleDrawer.js

#pragma strict
@CustomPropertyDrawer (SampleClass)
class SampleDrawer extends PropertyDrawer {
    var min : float = 0;
    var max : float = 1;
    var unfolded : boolean;
    
    // Draw the property inside the given rect
    function OnGUI (position : Rect, property : SerializedProperty, label : GUIContent) {
    	
       	var first : SerializedProperty = property.FindPropertyRelative ("first");
       	var second : SerializedProperty = property.FindPropertyRelative ("second");
       	var third : SerializedProperty = property.FindPropertyRelative ("third");

       	// Using BeginProperty / EndProperty on the parent property means that
        // prefab override logic works on the entire property.
        // Draw label

        EditorGUI.BeginProperty (position, label, property);
        unfolded = EditorGUI.Foldout(position,unfolded,label);
		
		if(unfolded){
	        EditorGUI.Slider (new Rect(position.x,position.y+20,position.width,position.height),first, min, max, GUIContent("first"));
	        EditorGUI.Slider (new Rect(position.x,position.y+40,position.width,position.height),second, min, max, GUIContent("second"));
	        EditorGUI.Slider (new Rect(position.x,position.y+60,position.width,position.height),third, min, max, GUIContent("third"));
       }
        EditorGUI.EndProperty ();
    }

}

here is a pic of what it looks like
1261370--55385--$propDrawer2.jpg

Keeping the class serializable so it can fold and unfold would be nice, but if i can stop the overlap problem I could live without it. Anyone have any thoughts? THANKS :slight_smile:

This is because you are not using the layout version of the editor GUI controls. If you want to do this then you could use GUILayout.Space with sufficient spacing (specified in pixels). Though I would recommend just using EditorGUILayout instead of EditorGUI :slight_smile:

2 Likes

Thanks! I was under the impression that GUILayout didn’t work in property drawers. I will check it out and report back.

I don’t think GUILayout has anything to do with this.

Can you show the version of the code you tried with GetPropertyHeight implemented? It’s supposed to handle stuff like this, I think perhaps you implemented it wrongly.

Yes, you are right. I am incorrectly confusing them with the way in which PlayMaker has implemented their property drawers which just use GUILayout. The solution is literally to just override GetPropertyHeight. Sorry for any confusion!

@numberkruncher Thanks for the quick reply anyway I really appreciate it!

Richard, it seems like a few others have solved the problem with overrriding GetPropertyHeight. I found this very succinct way to do it but I am having trouble switching the code over to Javascript because of the usage of “base” Do you know if there is any way for JS to refer back to the original function like this? Here is the code…

	function GetPropertyHeight (property, label) 
	
	{
	   float extraHeight = 20.0;  
	   return base.GetPropertyHeight(prop, label) + extraHeight;
	}

KeirMeikle originally posted this solution in this thread http://forum.unity3d.com/threads/158808-PropertyDrawer-Compact-for-Vector2-Vector3

If I can at least get that part going there shouldn’t be any trouble making it dynamic for the situation

Or, I could just rewrite the whole script in C# (which I am planning on learning as soon as this project is done)

This should translate something like follows:

function GetPropertyHeight(property, label):float {
    var extraHeight = 20;
    return super.GetPropertyHeight(property, label) + extraHeight;
}

Hey thanks numberkruncher that was what I needed. Unfortunately I think I am implementing something incorrectly because the override of the GetPropertyHeight function isn’t doing anything. Here is the SampleDrawer.js script as I have it written now…

#pragma strict
@CustomPropertyDrawer (SampleClass)
class SampleDrawer extends PropertyDrawer {
    var min : float = 0;
    var max : float = 1;
    var unfolded : boolean;
    
    // Draw the property inside the given rect
    function OnGUI (position : Rect, property : SerializedProperty, label : GUIContent) {
    	
       	var first : SerializedProperty = property.FindPropertyRelative ("first");
       	var second : SerializedProperty = property.FindPropertyRelative ("second");
       	var third : SerializedProperty = property.FindPropertyRelative ("third");

       	// Using BeginProperty / EndProperty on the parent property means that
        // prefab override logic works on the entire property.
        // Draw label

        EditorGUI.BeginProperty (position, label, property);
        unfolded = EditorGUI.Foldout(position,unfolded,label);
		
		if(unfolded){
	        EditorGUI.Slider (new Rect(position.x,position.y+20,position.width,position.height),first, min, max, GUIContent("first"));
	        EditorGUI.Slider (new Rect(position.x,position.y+40,position.width,position.height),second, min, max, GUIContent("second"));
	        EditorGUI.Slider (new Rect(position.x,position.y+60,position.width,position.height),third, min, max, GUIContent("third"));
       }
        EditorGUI.EndProperty ();
    }
	
	//override this function to add space below the new property drawer
	function GetPropertyHeight(property, label) {
	    var extraHeight = 100;
	    return super.GetPropertyHeight(property, label) + extraHeight;
	}
}

I am clearly in way over my head here because I don’t really know why this will or won’t work :slight_smile:

Do I need to call the new GetPropertyHeight function inside my OnGUI to get it to work maybe?

Thanks for all the help!

Ah, okay I found the problem you are experiencing, it seems that in UnityScript you need to be explicit with your types when overriding the function:

function GetPropertyHeight(property:SerializedProperty, label:GUIContent):float {
    var extraHeight = 20;
    return super.GetPropertyHeight(property, label) + extraHeight;
}

Thanks so much! I really appreciate all of your help on this. If there is ever a possibility I can buy you a beer, consider it yours :slight_smile:

This works.

[CustomPropertyDrawer (typeof (Custom))]
public class CustomDrawer : PropertyDrawer {
	const float rows = 2;  // total number of rows
	
	public override void OnGUI (Rect pos, SerializedProperty prop, GUIContent label) {		
		// first row
               Object target = EditorGUI.ObjectField (
			new Rect (pos.x, pos.y, pos.width, pos.height/rows),
			label,
			null,
			typeof(Object),
			true
		);
		
               // second row
		EditorGUI.LabelField(
			new Rect (pos.x, pos.y += pos.height/rows, pos.width, pos.height/rows),
			"Routine",
			pos.height.ToString()
		);
	}
	
	public override float GetPropertyHeight (SerializedProperty property, GUIContent label) {
		return base.GetPropertyHeight (property, label) * rows;  // assuming original is one row
	}
}
1 Like

I know the thread is old but for the sake or prosperity for others, I’d like to contribute since I had a hard time myself with the overlap problem.

I added the check to property expanded to adjust the height dynamically.

public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return base.GetPropertyHeight(property, label) * (property.isExpanded ? rows : 1);  // assuming original is one row
    }

Stupid question (maybe) but why use PropertyDrawer over Editor? GUILayout and EditorGUILayout sounds too big of a feature to skip. What does a PropertyDrawer gives over an Editor?

i started with propertydrawer in the past few days, and it was a frustrating experience due to lack of tutorials/topics on it…specially the overlapping thingi :frowning: … anyway…

that’s not a stupid question…i personally need enlightenment on this by someone…
i tried using GUILayout/EditorGUILayout on list of classes like (List or class[ ]) but they didn’t seem to work with me ( no changes on unity GUI) and am not sure if i did something wrong… but i found propertydrawer works fine with lists and arrays regardless where they are…

@LightStriker

You can implement a custom property drawer to provide a custom user interface for one single field when using the default inspector. In many cases this avoids needing to implement an entire inspector. One of the biggest advantages with custom property drawers is that they can be associated with a custom attribute allowing additional context to be passed into the custom drawer.

For example, you could associate a custom property drawer with the attribute “HeroPowerFilter”. Your property drawer could then display a popup interface where options are filtered as specified.

public class Hero : MonoBehaviour {
    [HeroPowerFilter(PowerSelectionFilter.SuperPower)]
    public int power;
    [HeroPowerFilter(PowerSelectionFilter.BasicPower)]
    public int basicPower;

    [Range(0, 1)]
    public float speed;

    public Vector2 direction;
}

Note that you can take advantage of custom property drawers within regular Editor’s and EditorWindow’s by using EditorGUI.PropertyField.

@mangax
You might be interested in my custom reorderable list control which supports custom property drawers:
https://bitbucket.org/rotorz/reorderable-list-editor-field-for-unity

The download includes a user guide (Support/User Guide.pdf) and more importantly the API Reference (Support/API Reference.chm) where the latter includes various usage examples.

I hope that this helps guys :slight_smile:

2 Likes

I’m not sure why you say “passing an attribute” is a feature of PropertyDrawer. I pass attributes (multiples) around all the time. Often, a single attribute is not enough. I also read somewhere that PD are limited to a single Attribute. (Weird?)

Frankly, it feels like every Inspector “system” has its pros and cons. Being unable to use GUILayout in PD is an obvious con.

As for using an “Inspector-in-EditorWindow”… I guess I wrote my own. :stuck_out_tongue:

The main benefit of PropertyDrawer that I’ve seen is that you can define how a custom type is represented in the Inspector view, and Unity will then present it that way regardless of which scripts the type is used in.

For example I made a class to contain some Lua script text (just a Serializable class with a public string field), and a PropertyDrawer for it that customizes the presentation, and now any instance of this LuaScript class in a MonoBehaviour or ScriptableObject gets presented this way, without needing one Editor class per MonoBehaviour. It’s a bit like how Unity has a specific way to present Color fields - including a pop-out selector window - without scripts that use Colors needing to worry about dealing with the Inspector.

So it’s a field-level customization rather than a script-level customization, and it’s probably most appealing to library authors.

I guess I also ended up writing my own system that does just that… But with support for GUILayout/EditorGUILayout. But on top of having it per “type”, I can also flag it per “field”.

@numberkruncher:

May I ask which drawers are you referring to within PlayMaker?

In PlayMaker you are able to use GUILayout in their variation of custom property drawers which are known as “ObjectPropertyDrawer”. You can find out more about these in their documentation:

https://hutonggames.fogbugz.com/default.asp?W1105

Here is an example of one which I wrote which internally utilizes the Unity GUILayout engine:
https://bitbucket.org/rotorz/rtsplaymakeractions/src/2dead466e50a784424ab6edda80d8bb48a17326f/Editor/RtsBrushPropertyDrawer_PlayMaker.cs?at=master