Organizing Recursive EditorGUI elements

I am trying to make a dialog editor for my Dialog class, and after getting my dialog initially instantiated and visible in the editor, I hit a wall. I could not conceive of how to organize it without creating a bool inside the dialog class itself.
Here is what I have so far, any ideas? Whatever it takes to organize this crap, preferably without adding extra crap to my Dialog class.

This is the Dialog Class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace SpaceScoundrels
{
    public class Dialog : ScriptableObject
    {
        public string Entry;
        public Dialog[] Responses;
        public Dialog Next(int choice)
        {
            return Responses[choice];
        }
        public virtual string GetEntry()
        {
            return Entry;
        }
    }
}

A section from my Editor class, it is like 1k lines of code so I onl took out the dialog part.

        if (ActiveState == WindowState.DialogEditor)
        {
            if (activeDialog == null)
            {
                if (GUILayout.Button("Create Dialog"))
                {
                    activeDialog = CreateInstance<Dialog>();
                }
            }
            else
            {
                activeDialog.name = EditorGUILayout.TextField("Name", activeDialog.name);
                activeDialog.Entry = EditorGUILayout.TextArea(activeDialog.Entry, GUILayout.Height(100));
                dialogCount = EditorGUILayout.IntField("Dialog Options", dialogCount);
                if (GUILayout.Button("Add Dialogs") && dialogCount > 0)
                {
                    activeDialog.Responses = new Dialog[dialogCount];
                    for (int i = 0; i < activeDialog.Responses.Length; i++)
                    {
                        activeDialog.Responses *= CreateInstance<Dialog>();*

}
}
dialogHierarchy = 1;
IterateDialog(activeDialog);
if (GUILayout.Button(“Save Dialog”))
{
AssetDatabase.CreateAsset(activeDialog, “Assets/GameKit/Dialog/” + activeDialog.name + “.asset”);
newItem = null;
}

}
}
The recursion method.
void IterateDialog(Dialog dialog)
{
if (dialog.Responses != null)
{
foreach (Dialog section in dialog.Responses)
{
if (section != null)
{

EditorGUILayout.BeginHorizontal();
GUILayout.Space(10 * dialogHierarchy);
section.Entry = EditorGUILayout.TextField(“Entry”, section.Entry);
if (GUILayout.Button(“Add Dialogs”))
{
section.Responses = new Dialog[3];
for (int i = 0; i < section.Responses.Length; i++)
{
section.Responses = CreateInstance();
}
}
EditorGUILayout.EndHorizontal();
IterateDialog(section);
dialogHierarchy += 1;
}
}
}
}
Finally… my result.
[86955-results.png|86955]_
_

Well, it’s not really clear how you want it to be organised. The boolean you talked about, what is it for? Just for expanding / collapsing child dialogs? You can “store” those booleans inside the editor class itself. Of course when you close the editor the settings would be gone.

As of how to improve the layout, there are several things you might change:

First use a fix size for things that have a fix-sized content, like your “Add Dialogs” button

if (GUILayout.Button("Add Dialogs", GUILayout.Width(80))); // 80 might be tweaked to get the best result

Doing this will preserve as much of the flexible space as possible for the dynamic elements. Personally i wouldn’t use the auto-labelled version of “TextField”. Just using a seperate Label and a simple TextField. That way you can better control the size of each element.

Next problem is that the way you handle your indention makes not much sense. You only increase dialogHierarchy but never decrease it. So elements on the same layer wouldn’t be at the same indent-level since your recursive method might increase the value for it’s childs but when it returns you stay at that level.

So you either do this:

dialogHierarchy ++;
IterateDialog(section);
dialogHierarchy --;

inside your recursive method, or, what would be the better solution, pass the depth on as parameter

IterateDialog(section, depth + 1);

That way you don’t need a class variable for information that is only relevant during the iteration.

To store additional information for each Dialog, you might use a Dictionary<Dialog, "AdditionalStuff">. So you can easily store whatever you want. For example using a seperate class that holds that additional information for each Dialog. In the case of the “expanding / collapsing” bool you can store a single boolean for each Dialog to indicate if it’s children are expanded or not.

public Dictionary<Dialog, EditorDialog> editorDialogs = new public Dictionary<Dialog, EditorDialog>();
public class EditorDialog
{
    public bool childsExpanded = false;
    // ...

}
EditorDialog GetEditorDialog(Dialog aDialog)
{
    EditorDialog result;
    if (!editorDialogs.TryGetValue(aDialog, out result))
    {
        result = new EditorDialog();
        editorDialogs.Add(aDialog, result);
    }
    return result;
}

With that you can simply add this line:

var editorDialog = GetEditorDialog( dialog );

and set / get the “childsExpanded” as you need.