Search Unity

Question Using custom editor for an inherited class

Discussion in 'Scripting' started by Alaadel, Jul 20, 2020.

  1. Alaadel

    Alaadel

    Joined:
    Apr 6, 2013
    Posts:
    30
    Hello,

    I have a class A, with its own variables. I made a FoldoutGroup for it and it works:
    Code (CSharp):
    1. using UnityEditor;
    2. // ....
    3. [CustomEditor(typeof(A))]
    4. [CanEditMultipleObjects]
    5. public class AEditor : Editor
    6. {
    7.     public bool state = true;
    8.     public override void OnInspectorGUI()
    9.     {
    10.         state = EditorGUILayout.BeginFoldoutHeaderGroup(state, "A Stuff");
    11.         if (state)
    12.             base.OnInspectorGUI();
    13.         EditorGUILayout.EndFoldoutHeaderGroup();
    14.     }
    15. }
    I made a second class B that inherits from A. What I want to achieve:
    In the Inspector, B shows 2 foldout groups: "A Stuff" which contains the public members of A, and "B Stuff" which contains the public members of B (without the members of A).

    I know it is complex (I managed to crash the Editor trying to do it!), but is there is a way?
    I could make B use a FoldoutGroup, but because I am calling "base" it calls its parent (A) and calls its OnInspectorGUI(), which results in drawing the members of A inside B.
    The good about base.OnInspectorGUI(); is that I don't have to build a full custom editor, I can only build the Foldout my self and call base.OnInspectorGUI(); to handle the normal stuff;

    Is there a simpler way?
     
  2. WarmedxMints

    WarmedxMints

    Joined:
    Feb 6, 2017
    Posts:
    1,035
    Your Inherited class would just need to derive from the base class editor, like so
    Code (CSharp):
    1. public class ClassA : MonoBehaviour
    2. {
    3. }
    4.  
    5. [CustomEditor(typeof(ClassA),true)]
    6. public class ClassAEditor : Editor
    7. {
    8.     public override void OnInspectorGUI()
    9.     {
    10.         EditorGUILayout.LabelField("I'm a Label From Class A");
    11.     }
    12. }
    Code (CSharp):
    1. public class ClassB : ClassA
    2. {
    3. }
    4.  
    5. [CustomEditor(typeof(ClassB))]
    6. public class ClassBEditor : ClassAEditor
    7. {
    8.     private bool ShowA;
    9.  
    10.     public override void OnInspectorGUI()
    11.     {
    12.         ShowA = EditorGUILayout.BeginFoldoutHeaderGroup(ShowA, "A Stuff");
    13.         if (ShowA)
    14.             base.OnInspectorGUI();
    15.         EditorGUILayout.EndFoldoutHeaderGroup();
    16.  
    17.         EditorGUILayout.LabelField("I'm a Label From Class B");
    18.     }
    19. }
     
    Alaadel likes this.
  3. Alaadel

    Alaadel

    Joined:
    Apr 6, 2013
    Posts:
    30
    With a mix from this answer and C# reflection, I managed to make 2 Foldouts in the child Inspector: one for the parent members and one for the child members:
    Parent Code:
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using System.Reflection;
    4. using System.Collections.Generic;
    5.  
    6. public class A : MonoBehaviour
    7. {
    8.     public int A1 = 0;
    9.     public Texture A2;
    10.     public Vector3 V3;
    11. }
    12.  
    13. [CustomEditor(typeof(A), true)]
    14. [CanEditMultipleObjects]
    15. public class AEditor : Editor
    16. {
    17.     bool s1 = true;
    18.     List<SerializedProperty> sp;
    19.  
    20.     protected void OnEnable()
    21.     {
    22.         sp = new List<SerializedProperty>();
    23.         A x = new A();
    24.         MemberInfo[] mi = x.GetType().GetFields();
    25.         foreach(MemberInfo m in mi)
    26.         {
    27.             sp.Add(serializedObject.FindProperty(m.Name));
    28.         }
    29.     }
    30.  
    31.     public override void OnInspectorGUI()
    32.     {
    33.         serializedObject.Update();
    34.  
    35.         s1 = EditorGUILayout.BeginFoldoutHeaderGroup(s1, "A Stuff");
    36.         if (s1)
    37.             foreach (SerializedProperty s in sp)
    38.                 EditorGUILayout.PropertyField(s);
    39.         EditorGUILayout.EndFoldoutHeaderGroup();
    40.     }
    41. }
    Child Code:
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using System.Reflection;
    4. using System.Collections.Generic;
    5.  
    6. public class B : A
    7. {
    8.     public int B1 = 50;
    9.     public Animator B2;
    10. }
    11.  
    12. [CustomEditor(typeof(B))]
    13. [CanEditMultipleObjects]
    14. public class BEditor : AEditor
    15. {
    16.     bool s2 = true;
    17.     List<SerializedProperty> sp;
    18.  
    19.     private new void OnEnable()
    20.     {
    21.         base.OnEnable();
    22.  
    23.         sp = new List<SerializedProperty>();
    24.         // Get members
    25.         A a = new A(); MemberInfo[] ma = a.GetType().GetFields();
    26.         B b = new B(); MemberInfo[] mb = b.GetType().GetFields();
    27.         foreach (MemberInfo m in mb)
    28.         {
    29.             // Exclude parent members
    30.             if (ArrayUtility.Find(ma, e => e.Name == m.Name) == null)
    31.                 sp.Add(serializedObject.FindProperty(m.Name));
    32.         }
    33.     }
    34.  
    35.     public override void OnInspectorGUI()
    36.     {
    37.         base.OnInspectorGUI();
    38.  
    39.         s2 = EditorGUILayout.BeginFoldoutHeaderGroup(s2, "B Stuff");
    40.         if (s2)
    41.             foreach (SerializedProperty s in sp)
    42.                 EditorGUILayout.PropertyField(s);
    43.         EditorGUILayout.EndFoldoutHeaderGroup();
    44.     }
    45. }
     
    Last edited: Jul 20, 2020
  4. Alaadel

    Alaadel

    Joined:
    Apr 6, 2013
    Posts:
    30
    Thanks, this solves the inheritance issue.
    Adding labels for members one by one would not scale, so using
    EditorGUILayout.PropertyField(s);
    was better.