Getting Default SerializedProperty Drawing within a PropertyDrawer

I wanted to make a PropertyDrawer that added a little spacing, so that I could space out sections of variables in the Editor.

I tried using the base OnGUI to do this, but writes something like No GUI Implemented or something. I tried using EditorGUI.PropertyField, but this calls the PropertyDrawers OnGUI functions, causing a stack overflow and never getting to any drawing.

I used .NET Reflector to take a look at EditorGUI.PropertyField, and saw that in EditorGUI.SinglePropertyField, the drawer is obtained via PropertyDrawer.GetDrawer. Their is a private static dictionary, s_PropertyDrawers.

This was my solution for getting the behavior I wanted.

[CustomPropertyDrawer(typeof(SeperatorAttribute))]
public class SeperatorDrawer : PropertyDrawer
{

    //OnGUI / GetPropertyHeight

    void DrawDefaultProperty(Rect position, SerializedProperty property, GUIContent label,bool includeChildren = true)
    {
        Dictionary<string, PropertyDrawer> s_dictionary =
            typeof(PropertyDrawer).GetField("s_PropertyDrawers", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null) as Dictionary<string, PropertyDrawer>;

        foreach (var entry in s_dictionary)
        {
            if (entry.Value == this)
            {
                s_dictionary[entry.Key] = null;
                EditorGUI.PropertyField(position, property, label, true);
                s_dictionary[entry.Key] = this;
                return;
            }
        }
        
        EditorGUI.PropertyField(position, property, label, true);
    }
}

I was wondering if there was a better solution that I was just overlooking, that’s preferably less intrusive.

There has been one issue with this solution:
Whenever the property is on a AnimationCurve, and the animation curve is edited, the seperation stop working for that property(no others).

Thoughts?

Hi,

I have the same issue, but your code seems to work.

There should be a way to disable custom property drawers for displaying default PropertyFields.

Thanks!

Just a note to say thanks - that this code was quite useful to me too.

I’m using this code to implement a RequiredAttribute that won’t let me enable a script if any of it’s public “required” fields are null (i.e. a replacement for the RequireComponent attribute that auto-adds components). I use public fields a lot as links between objects that I set up with drag’n’drop (avoiding issues around singletons/managers/GetComponent() calls).

Seems to work fine, except if I use the popup dialog to select the contents of the field (the litte dot-inside-a-circle icon on the right) - then Unity seems to “forget” about the custom PropertyDrawer (the field still gets drawn properly, but I’m fairly certain my custom PropertyDrawer logic is not being called).

I can “reset” the field so that my custom PropertyDrawer starts firing again quite easily, by doing such things as :

  • running the project
  • causing a re-compile from Monodev
  • or the easiest, just switch to a different object in the Hierarchy tab, then switch back to the object I care about and my custom PropertyDrawer will start firing again

I think this is likely the same problem Avaista was seeing with editing animation curves.

This code won’t work for me seems like s_PropertyDrawers doesn’t exisit. Does anyone have any ideas? Maybe the way this class works changed in Unity 4.5?

I would REALLY like to be able to do this.

I was looking for the solution of another problem. Things have changed since. I am curious to here if there is similar way to do the same kind of technique that the author used.

As for the original problem. That is history:

Now you can do it by inherenting from the DecoratorDrawer class instead.

Ofcourse there is a SpaceAttribute now as well. Which you can use like so:

   [Space(10f)]
public int SpaceBeforeMe = 0;

Those are the functions unity uses internally to draw default fields, this does not account for children properties, wo you would have to do the calculations and the drawing manually.

// internal static bool DefaultPropertyField(Rect position, SerializedProperty property, GUIContent label)
protected static readonly MethodInfo EditorGUI_DefaultPropertyField = typeof(EditorGUI).GetMethod("DefaultPropertyField", BindingFlags.Static | BindingFlags.NonPublic);
// internal static float GetSinglePropertyHeight(SerializedProperty property, GUIContent label)
protected static readonly MethodInfo EditorGUI_GetSinglePropertyHeight = typeof(EditorGUI).GetMethod("GetSinglePropertyHeight", BindingFlags.Static | BindingFlags.NonPublic);

Then to call them

EditorGUI_DefaultPropertyField.Invoke(null, new object[]{ position, property, label }); // You can cast it to bool if you need the result
(float)EditorGUI_GetSinglePropertyHeight.Invoke(null, new object[] { property, label });

I’m wondering why Unity does not expose these functions…