Custom GUI List in Inspector Went Wrong Need Help!

Hi, I wanted to create a custom GUI List but it went wrong.
I want it like this
image

But instead it become like this
image

Please Help!!!

Here’s the script:

using System.Text.RegularExpressions;
using NaughtyAttributes;
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(SequenceDialogueMultiLanguage))]
public class SequenceDialogueMultiLanguageEditor : Editor
{
    private SerializedProperty languageProp;
    private SerializedProperty dialogueListProp;
    private SerializedProperty dialogueIndonesianProp;
    private SerializedProperty dialogueEnglishProp;

    private void OnEnable()
    {
        languageProp = serializedObject.FindProperty("language");
        dialogueListProp = serializedObject.FindProperty("dialogueList");
        dialogueIndonesianProp = serializedObject.FindProperty("dialogueIndonesian");
        dialogueEnglishProp = serializedObject.FindProperty("dialogueEnglish");
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        EditorGUILayout.PropertyField(languageProp);

        Languages selectedLanguage = (Languages)languageProp.enumValueIndex;

        EditorGUILayout.LabelField("Dialogue List:");

        EditorGUI.indentLevel++;

        if (selectedLanguage == Languages.Indonesian)
        {
            EditorGUILayout.PropertyField(dialogueIndonesianProp, true);
            if (dialogueIndonesianProp != null && dialogueIndonesianProp.isArray)
            {
                // Iterate through the dialogue list and draw individual elements
                for (int i = 0; i < dialogueIndonesianProp.arraySize; i++)
                {
                    SerializedProperty dialogueElementProp = dialogueIndonesianProp.GetArrayElementAtIndex(i);

                    SerializedProperty characterSpriteProp = dialogueElementProp.FindPropertyRelative("characterSprite");
                    SerializedProperty dialogueProp = dialogueElementProp.FindPropertyRelative("dialogue");
                    SerializedProperty dialogueSpriteProp = dialogueElementProp.FindPropertyRelative("dialogueSprite");

                    EditorGUILayout.PropertyField(characterSpriteProp, true);
                    EditorGUILayout.PropertyField(dialogueProp, true);
                    EditorGUILayout.PropertyField(dialogueSpriteProp, true);
                }
            }
        }
        else if (selectedLanguage == Languages.English)
        {
            EditorGUILayout.PropertyField(dialogueEnglishProp, true);
        }

        EditorGUI.indentLevel--;

        EditorGUILayout.Space();

        // Display the previous inspector GUI
        DrawDefaultInspectorExcept(dialogueListProp, dialogueIndonesianProp, dialogueEnglishProp);
        // Display the [Button] attributes from SequenceBaseModel
        DrawButtonAttributes();

        serializedObject.ApplyModifiedProperties();
    }

    private void DrawButtonAttributes()
    {
        // Access the target object to get the actual instance of SequenceBaseModel
        SequenceBaseModel sequenceBaseModel = (SequenceBaseModel)target;

        // Use reflection to find all methods with the [Button] attribute
        var methods = sequenceBaseModel.GetType().GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
        foreach (var method in methods)
        {
            var buttonAttributes = method.GetCustomAttributes(typeof(ButtonAttribute), true);
            if (buttonAttributes.Length > 0)
            {
                string formattedName = FormatMethodName(method.Name);
                if (GUILayout.Button(formattedName))
                {
                    method.Invoke(sequenceBaseModel, null);
                }
            }
        }
    }

    private string FormatMethodName(string methodName)
    {
        // Use regular expression to split method name by capital letters and keep acronyms together
        return Regex.Replace(methodName, "(?<!^)([A-Z][a-z]|(?<=[a-z])[A-Z])", " $1");
    }

    // Draw the default inspector GUI except for specified properties
    private void DrawDefaultInspectorExcept(params SerializedProperty[] exceptions)
    {
        SerializedProperty iterator = serializedObject.GetIterator();
        bool enterChildren = true;

        while (iterator.NextVisible(enterChildren))
        {
            enterChildren = false;

            if (!ShouldExcludeProperty(iterator, exceptions))
            {
                EditorGUILayout.PropertyField(iterator, true);
            }
        }
    }

    // Check if a property should be excluded from the default inspector GUI
    private bool ShouldExcludeProperty(SerializedProperty property, SerializedProperty[] exceptions)
    {
        foreach (SerializedProperty exception in exceptions)
        {
            if (property == exception)
            {
                return true;
            }
        }
        return false;
    }
}

Because it won’t serialized, I decided to create a custom List instead.

Here’s the code:


    private void DrawDialogueList(SerializedProperty dialogueListProp)
    {
        //EditorGUILayout.PropertyField(dialogueListProp, true);
        EditorGUILayout.BeginHorizontal();

        dialogueListProp.isExpanded = EditorGUILayout.Foldout(dialogueListProp.isExpanded, "Dialogue List");
        SerializedProperty arraySizeProp = dialogueListProp.FindPropertyRelative("Array.size");
        arraySizeProp.intValue = EditorGUILayout.IntField(arraySizeProp.intValue, GUILayout.Width(60));

        EditorGUILayout.EndHorizontal();
   
        if (dialogueListProp.isExpanded)
        {
            EditorGUI.indentLevel++;

            Color backgroundColor = Color.grey;
            backgroundColor.a = 0.25f;

            Rect rect = EditorGUILayout.BeginVertical();
            EditorGUI.DrawRect(rect, backgroundColor);
            EditorGUILayout.Space();

            // Draw a border around the box
            Color borderColor = Color.black; // Adjust border color
            EditorGUI.DrawRect(new Rect(rect.x, rect.y, rect.width, 1), borderColor); // Top border
            EditorGUI.DrawRect(new Rect(rect.x, rect.y, 1, rect.height), borderColor); // Left border
            EditorGUI.DrawRect(new Rect(rect.xMax - 1, rect.y, 1, rect.height), borderColor); // Right border
            EditorGUI.DrawRect(new Rect(rect.x, rect.yMax - 1, rect.width, 1), borderColor); // Bottom border
            
            for (int i = 0; i < arraySizeProp.intValue; i++)
            {
                SerializedProperty elementProp = dialogueListProp.GetArrayElementAtIndex(i);
                DrawDialogueElement(elementProp, i);
                EditorGUILayout.Space();
            }
            
            EditorGUILayout.EndVertical();
            EditorGUI.indentLevel--;
        }
        EditorGUILayout.BeginHorizontal();
        
        // Add a button to add a new element
        if (GUILayout.Button("+", GUILayout.Width(20)))
            AddNewDialogueElement(dialogueListProp);

        // Add a button to remove the last element
        if (GUILayout.Button("-", GUILayout.Width(20)))
            RemoveLastDialogueElement(dialogueListProp);

        EditorGUILayout.EndHorizontal();
    }

    private void DrawDialogueElement(SerializedProperty elementProp, int index)
    {
        elementProp.isExpanded = EditorGUILayout.Foldout(elementProp.isExpanded, "Dialogue " + index);
        if (elementProp.isExpanded)
        {
            EditorGUI.indentLevel++;

            SerializedProperty characterSpriteProp = elementProp.FindPropertyRelative("characterSprite");
            SerializedProperty dialogueProp = elementProp.FindPropertyRelative("dialogue");
            SerializedProperty dialogueSpriteProp = elementProp.FindPropertyRelative("dialogueSprite");
            EditorGUILayout.PropertyField(characterSpriteProp);
            EditorGUILayout.PropertyField(dialogueProp);
            EditorGUILayout.PropertyField(dialogueSpriteProp);

            // Add other properties of the dialogue element here
            // For example:
            // SerializedProperty speakerProp = elementProp.FindPropertyRelative("speaker");
            // EditorGUILayout.PropertyField(speakerProp);

            EditorGUI.indentLevel--;
        }
    }

    private void AddNewDialogueElement(SerializedProperty dialogueListProp)
    {
        dialogueListProp.isExpanded = true;
        dialogueListProp.arraySize++;
        serializedObject.ApplyModifiedProperties();

        SerializedProperty prevElementProp = dialogueListProp.GetArrayElementAtIndex(dialogueListProp.arraySize - 2);
        SerializedProperty newElementProp = dialogueListProp.GetArrayElementAtIndex(dialogueListProp.arraySize - 1);
        InitializeNewDialogueElement(newElementProp, prevElementProp);
    }

    private void InitializeNewDialogueElement(SerializedProperty elementProp, SerializedProperty prevElementProp)
    {
        SerializedProperty prevCharacterSpriteProp = prevElementProp.FindPropertyRelative("characterSprite");
        SerializedProperty prevDialogueProp = prevElementProp.FindPropertyRelative("dialogue");
        SerializedProperty prevDialogueSpriteProp = prevElementProp.FindPropertyRelative("dialogueSprite");

        SerializedProperty characterSpriteProp = elementProp.FindPropertyRelative("characterSprite");
        SerializedProperty dialogueProp = elementProp.FindPropertyRelative("dialogue");
        SerializedProperty dialogueSpriteProp = elementProp.FindPropertyRelative("dialogueSprite");

        characterSpriteProp.objectReferenceValue = prevCharacterSpriteProp.objectReferenceValue;
        dialogueProp.stringValue = prevDialogueProp.stringValue;
        dialogueSpriteProp.objectReferenceValue = prevDialogueSpriteProp.objectReferenceValue;

        serializedObject.ApplyModifiedProperties();
    }

    private void RemoveLastDialogueElement(SerializedProperty dialogueListProp)
    {
        if (dialogueListProp.arraySize > 0)
        {
            dialogueListProp.arraySize--;
            serializedObject.ApplyModifiedProperties();
        }
    }