Innat3
Innat3

Reputation: 3576

Custom Unity C# Script Editor with dynamic Enum Field

Let's say we have the following Enums

public enum Section
{
    A,
    B
}

public enum SectionA
{
    A1,
    A2,
    A3
}

public enum SectionB
{
    B1,
    B2,
    B3
}

I would like to make a script with two public Enum fields, with selectable values as dropdowns from the Unity Editor. The first one serves to select the Section (A or B), while the second one should be an Enum of type SectionA or SectionB depending what the selected value on the first field is.

I made the following scripts for this:

public class Item : MonoBehaviour
{
    [HideInInspector]
    public Section Section;

    [HideInInspector]
    public System.Enum Value;
}


[CustomEditor(typeof(Item))]
public class ItemEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        Item item = target as Item;

        item.Section = (Section)EditorGUILayout.EnumPopup(item.Section);

        switch (item.Section)
        {
            case Section.A:
                item.Value = (SectionA)EditorGUILayout.EnumPopup(item.Value);
                break;
            case Section.B:
                item.Value = (SectionB)EditorGUILayout.EnumPopup(item.Value);
                break;
        }
    }
}

But it triggers an Exception stating that item.Value is null.

I also tried replacing

item.Value = (SectionA)EditorGUILayout.EnumPopup(item.Value);

with

item.Value = (SectionA)EditorGUILayout.EnumPopup(item.Value ?? SectionA.A1);

to try to give it an "Initial Value" but then the value A1 overrides the selected one when I press Play. Any ideas?

Upvotes: 3

Views: 7817

Answers (1)

Innat3
Innat3

Reputation: 3576

I fixed it by adding a placeholder field to store the enum value.

public class Item : MonoBehaviour
{
    [HideInInspector]
    public Section Section;

    [HideInInspector]
    public System.Enum Value;

    [HideInInspector]
    public SectionA a;

    [HideInInspector]
    public SectionB b;
}

switch (item.Section)
{
    case Section.A:
        item.Value = EditorGUILayout.EnumPopup(item.a = (SectionA)(item.Value ?? item.a));
        break;
    case Section.B:
        item.Value = EditorGUILayout.EnumPopup(item.b = (SectionB)(item.Value ?? item.b));
        break;
}

The previous solution often fails to save values when you switch scenes. This works properly.

public class Item : MonoBehaviour
{ 
    public Section section;
    public SectionA sectionA;
    public SectionB sectionB;

    public System.Enum Value
    {
        get
        {
            switch(section)
            {
                case Section.A:
                    return sectionA;
                case Section.B:
                    return sectionB;
                default:
                    return null;
            }
        }
    }
}

[CustomEditor(typeof(Item))]
public class ItemEditor : Editor
{
    SerializedProperty section;
    SerializedProperty sectionA;
    SerializedProperty sectionB;

    void OnEnable()
    {
        section = serializedObject.FindProperty("section");
        sectionA = serializedObject.FindProperty("sectionA");
        sectionB = serializedObject.FindProperty("sectionB");
    }

    public override void OnInspectorGUI()
    {        
        serializedObject.Update();
        EditorGUILayout.PropertyField(section);
        switch ((Section)section.enumValueIndex)
        {
            case Section.A:
                EditorGUILayout.PropertyField(sectionA);
                break;
            case Section.B:
                EditorGUILayout.PropertyField(sectionB);
                break;
        }   
        serializedObject.ApplyModifiedProperties();
    }
}

Upvotes: 3

Related Questions