Search Unity

Trouble drawing Unity Event In Property Drawer

Discussion in 'UGUI & TextMesh Pro' started by norilalatoli, May 10, 2020.

  1. norilalatoli

    norilalatoli

    Joined:
    Aug 9, 2018
    Posts:
    12
    Hello all. I have a property draw called ConditionalHide that hides fields depending on an inspector attribute. My trouble is that I can't seem to draw UnityEvents properly. Here is what the UnityEvent looks like in the inspector.

    upload_2020-5-10_15-53-59.png

    when it should like

    upload_2020-5-10_15-54-53.png

    here is the property drawer that draws the properties.

    Code (CSharp):
    1.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    2.     {
    3.         /*Get Attribute Data */
    4.         ConditionalHideAttribute cha = (ConditionalHideAttribute)attribute;
    5.  
    6.         /* Get if Property is True or False */
    7.         bool enabled = GetConditionalHideAttributeResult(cha, property);
    8.  
    9.         /* Draw the Property If NOT Hidden */
    10.         if (cha.hideInInspector != enabled)
    11.         {
    12.  
    13.             EditorGUI.PropertyField(position, property, label, true);
    14.  
    15.         }    
    16.     }
    Any help is appreciated.
     
  2. norilalatoli

    norilalatoli

    Joined:
    Aug 9, 2018
    Posts:
    12
  3. thepinkfedora

    thepinkfedora

    Joined:
    Mar 7, 2020
    Posts:
    1
  4. Chrisi12er

    Chrisi12er

    Joined:
    Sep 7, 2014
    Posts:
    9
    I have the exact same problem. Calling PropertyField inside the OnInspectorGUI method of a custom editor works just fine but using it inside OnGUI of a PropertyDrawer it just provides a raw view of all the data.
     
  5. Chrisi12er

    Chrisi12er

    Joined:
    Sep 7, 2014
    Posts:
    9
    I actually found a solution if anyone is interested. Under normal circumstances unity uses the class "UnityEventDrawer" to draw the Event. It derives from PropertyDrawer just like our own class. (This seems to be the reason its not working properly, because now we have two PropertyDrawers for the same thing)
    Knowing this we can create a UnityEventDrawer inside our own drawer and then just call its methods GetPropertyHeight and OnGUI inside our own ones.

    Here a little example code for the use case mentioned above:

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor;
    4. using UnityEditorInternal; // <- Contains the UnityEventDrawer class
    5.  
    6. public class ConditionalHideAttribute : PropertyAttribute
    7. {
    8.     public bool hideInInspector;
    9.  
    10.     public ConditionalHideAttribute(bool hide)
    11.     {
    12.         hideInInspector = hide;
    13.     }
    14. }
    15.  
    16. [CustomPropertyDrawer(typeof(ConditionalHideAttribute), true)]
    17. public class ConditionalHideDrawer : PropertyDrawer
    18. {
    19.     private UnityEventDrawer eventDrawer;
    20.  
    21.     public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    22.     {
    23.         if (((ConditionalHideAttribute)attribute).hideInInspector)
    24.             return 0;
    25.  
    26.         if (eventDrawer == null)
    27.             eventDrawer = new UnityEventDrawer();
    28.  
    29.         return eventDrawer.GetPropertyHeight(property, label);
    30.     }
    31.  
    32.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    33.     {
    34.         if (((ConditionalHideAttribute)attribute).hideInInspector)
    35.             return;
    36.  
    37.         if (eventDrawer == null)
    38.             eventDrawer = new UnityEventDrawer();
    39.  
    40.         eventDrawer.OnGUI(position, property, label);
    41.     }
    42. }
    43.  
     
  6. Nianyi_Wang

    Nianyi_Wang

    Joined:
    Sep 9, 2021
    Posts:
    17
    Bump. It seems like in 2021.3.14f1c1, EditorGUI.PropertyField can indeed draw the event GUI properly, but it is not responsive to mouse operations like adding a listener. If I use EditorGUI.BeginChangeCheck to check, it will get triggered when I click on the plus button, but it just doesn't work.
     
  7. Dubitrubi

    Dubitrubi

    Joined:
    Jan 31, 2020
    Posts:
    5
    So if you have a class Foo containing a Unity Event...

    Code (CSharp):
    1. [System.Serializable]
    2. public class Foo
    3. {
    4.     [SerializeField] UnityEvent unityEvent = new UnityEvent();
    5. }
    ... and use that in a component like this...

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class FooComponent : MonoBehaviour
    4. {
    5.     [SerializeField] Foo fooEventOne = new Foo();
    6.     [SerializeField] Foo fooEventTwo = new Foo();
    7. }
    ... you can display and check for modifications with the following PropertyDrawer:

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3.  
    4. [CustomPropertyDrawer(typeof(Foo))]
    5. public class FooDrawer : PropertyDrawer
    6. {
    7.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    8.     {
    9.         EditorGUI.BeginProperty(position, label, property);
    10.  
    11.         EditorGUI.BeginChangeCheck();
    12.  
    13.         /// Label Field
    14.         position.height = EditorGUIUtility.singleLineHeight;
    15.         EditorGUI.LabelField(position, label);
    16.  
    17.         /// Property Field
    18.         SerializedProperty unityEventProp = property.FindPropertyRelative("unityEvent");
    19.         position.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
    20.         position.height = EditorGUI.GetPropertyHeight(unityEventProp);
    21.         EditorGUI.PropertyField(position, unityEventProp);
    22.  
    23.         if (EditorGUI.EndChangeCheck())
    24.             property.serializedObject.ApplyModifiedProperties();
    25.  
    26.         EditorGUI.EndProperty();
    27.     }
    28.  
    29.     public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    30.     {
    31.         /// Height of the label
    32.         float height = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
    33.  
    34.         /// Height of the property
    35.         height += EditorGUI.GetPropertyHeight(property.FindPropertyRelative("unityEvent"));
    36.         return height;
    37.     }
    38. }
    Here the result in the Inspector:
    upload_2023-3-7_14-55-50.png
     
    TwoBitMachines likes this.