Search Unity

Multiple PropertyDrawers Not Drawing As Expected

Discussion in 'Immediate Mode GUI (IMGUI)' started by kromenak, Sep 4, 2015.

  1. kromenak

    kromenak

    Joined:
    Feb 9, 2011
    Posts:
    270
    For convenience, I've created two PropertyDrawers to allow me to modify the display of some data in the Inspector without having to create a full-blown Editor. One property drawer allows me to "lock" a field, so that it won't be edited, and the other allows me to display a HelpBox above the field.

    The problem I'm encountering is that when I use both of these PropertyDrawer attributes on a single inspector variable, only one of them is actually applied. That isn't the case with the built-in attributes, so I'm trying to determine what I'm doing wrong. Here is the code for the two property drawers:

    Lockable Property Drawer:
    Code (CSharp):
    1. [CustomPropertyDrawer(typeof(LockableAttribute))]
    2. public class LockablePropertyDrawer : PropertyDrawer
    3. {
    4.     // Whether the property is locked for editing. Always true at first.
    5.     private bool locked = true;
    6.  
    7.     public override float GetPropertyHeight(SerializedProperty property,
    8.                                             GUIContent label)
    9.     {
    10.         return EditorGUI.GetPropertyHeight(property, label, true);
    11.     }
    12.  
    13.     public override void OnGUI(Rect position,
    14.                                SerializedProperty property,
    15.                                GUIContent label)
    16.     {
    17.         // Locked toggle.
    18.         Rect lockedRect = new Rect(position.width, position.y, 20.0f, EditorGUIUtility.singleLineHeight);
    19.         locked = !EditorGUI.Toggle(lockedRect, !locked);
    20.  
    21.         // If locked, disable GUI for the property.
    22.         if(locked) { GUI.enabled = false; }
    23.  
    24.         // Draw the actual property.
    25.         position.width -= lockedRect.width;
    26.         EditorGUI.PropertyField(position, property, label, true);
    27.  
    28.         // Re-enable GUI.
    29.         GUI.enabled = true;
    30.     }
    31. }
    HelpBox Property Drawer:
    Code (CSharp):
    1. [CustomPropertyDrawer(typeof(HelpBoxAttribute))]
    2. public class HelpBoxPropertyDrawer : PropertyDrawer
    3. {
    4.     private const int helpBoxHeight = 20;
    5.  
    6.     public override float GetPropertyHeight(SerializedProperty property,
    7.                                             GUIContent label)
    8.     {
    9.         return EditorGUI.GetPropertyHeight(property, label, false) + helpBoxHeight;
    10.     }
    11.  
    12.     public override void OnGUI(Rect position,
    13.                                SerializedProperty property,
    14.                                GUIContent label)
    15.     {
    16.         HelpBoxAttribute helpBoxAttribute = attribute as HelpBoxAttribute;
    17.         EditorGUI.HelpBox(position, helpBoxAttribute.message, MessageType.Info);
    18.     }
    19. }
    Using both at the same time:
    Code (CSharp):
    1. [Lockable]
    2. [HelpBox("This is a help message.")]
    3. public string uniqueId = string.Empty;
    An interesting thing is that whichever one is first will be drawn, while the other won't be drawn. If I flip the order of the Lockable and Helpbox attributes on the variable, the Helpbox will draw, but not the lockable stuff. Adding log messages in the OnGUI functions shows that only one of the OnGUI functions is actually being called.
     
  2. SanityIsOverrated

    SanityIsOverrated

    Joined:
    Dec 22, 2013
    Posts:
    31
    Hello kromenak,

    Only one PropertyDrawer is considered for each attribute. It is intended to completely replace the default display of a field, and a field is only drawn once.

    When you are saying "That isn't the case with the built-in attributes, so I'm trying to determine what I'm doing wrong." you are probably thinking about attributes which are derived from DecoratorDrawer.

    I'm gonna be lazy here and cite the description of there reference (bold formatting from me):
    Note that DecoratorDrawer on the other hand will not replace the default inspector field.

    I think what you want to do is have LockablePropertyDrawer derive from PropertyDrawer as is, because it actually displays a modified field and is responsible for the data.
    Then have HelpBoxPropertyDrawer derive from DecoratorDrawer - it is a picture-book example of something decorating a field.
     
    kromenak likes this.
  3. kromenak

    kromenak

    Joined:
    Feb 9, 2011
    Posts:
    270
    Ah, I see. Thanks for the clarification! Makes sense to me.