Change only PrefixLabel with Property drawer, use default drawing for rest of property.

I have a class with its first field an enum not a string. I would like an list of these classes to appear in the inspect with the the enum value as the PrefixLabel similar to the this would happen if it was a string. I can make this happen with the following ProperyDrawer code.

[CustomPropertyDrawer (typeof (TempleIdleGenerator.SlotItemFreq))]
public class SlotItemFreq : PropertyDrawer {
	public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
		// Using BeginProperty / EndProperty on the parent property means that
		// prefab override logic works on the entire property.
		EditorGUI.BeginProperty (position, label, property);

		// Draw label
		int index = property.FindPropertyRelative ("slotID").enumValueIndex;
		label.text = property.FindPropertyRelative ("slotID").enumDisplayNames [index];
		position = EditorGUI.PrefixLabel (position, GUIUtility.GetControlID (FocusType.Passive), label);
           //What goes here?
		EditorGUI.EndProperty ();
          // or maybe here?
	}
}

the class code is

	[System.Serializable]
	public class SlotItemFreq{
		public SlotID slotID;
		public List<ItemFreq> itemFreqs;
	}

II would like everything after the initial field to display in the inspector the same as would if I did not have a custom ProperyDrawer. What code do I need where the "//what goes here " or the “//maybe here?” comments are?

Cheers,
Grant

@Bunny83 wrote:

Unfortunately you can’t use
EditorGUI.PropertyField as it would
call your property drawer again so you
would crash due to an endless
recursion.

Actually this is not correct. Unity has a PropertyDrawer stack internally, so it is perfectly valid to simply do something like this:

public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
      int index = property.FindPropertyRelative ("slotID").enumValueIndex;
      label.text = property.FindPropertyRelative ("slotID").enumDisplayNames [index];
      EditorGUI.PropertyField(position, property, label, true);
  }

You can see this done in the new scripting example for SerializedProperty.isExpanded in the 5.6.0 documentation.

Well, that’s a problem. You would need to use EditorGUI.DefaultPropertyField which however is an internal method. If you want to replicate it manually, good luck ^^. Unfortunately you can’t use EditorGUI.PropertyFieldas it would call your property drawer again so you would crash due to an endless recursion.

Actually the PropertyDrawer default implementation does call EditorGUI.DefaultPropertyField automatically, however they made that horrible decision to implement it like this:

public virtual void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
    EditorGUI.DefaultPropertyField(position, property, label);
    EditorGUI.LabelField(position, label, EditorGUIUtility.TempContent("No GUI Implemented"));
}

So it displays this additional “warning”. So your solution could have been as easy as:

 public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
     int index = property.FindPropertyRelative ("slotID").enumValueIndex;
     label.text = property.FindPropertyRelative ("slotID").enumDisplayNames [index];
     base.OnGUI(position, property, label);
 }

But it’s not possible because they “think” it would be convenient to tell the user that he implemented a PropertyDrawer and did not override the OnGUI method …

So one option is to actually replicate what DefaultPropertyField does or to use reflection to call that internal method yourself ^^. Replicating is difficult since most methods DefaultPropertyField uses are internal or private as well. So the easiest option is to use reflection.

I quickly wrote this extension:

namespace B83.EditorExtensions
{
    using System.Reflection;
    public static class RefEditorGUI
    {
        public delegate bool DefaultPropertyFieldDelegate(Rect position, SerializedProperty property, GUIContent label);
        public static DefaultPropertyFieldDelegate DefaultPropertyField;
        static RefEditorGUI()
        {
            var t = typeof(EditorGUI);
            var delegateType = typeof(DefaultPropertyFieldDelegate);
            var m = t.GetMethod("DefaultPropertyField", BindingFlags.Static | BindingFlags.NonPublic);
            DefaultPropertyField = (DefaultPropertyFieldDelegate)System.Delegate.CreateDelegate(delegateType, m);
        }
    }
}

Simply place it in an editor script somewhere. Instead of EditorGUI.DefaultPropertyField you should be able to simply use RefEditorGUI.DefaultPropertyField. Of course you need to put a using on top of your script where you use it or remove the namespace.

Note: I haven’t tested the class. So if you use it would be nice to get feedback. If it doesn’t work i will look into it.

edit
I had a bad feeling something could be wrong so i did a quick check and yes i messed something up ^^. I’ve fixed the code above. Now it works just fine.