Reputation: 113
I want to create a Custom Editor for Unity with a list inside a list and allow to edit the size dynamically and with a Popup inside the second list.
Here is a couple of examples of what I want:
The problem is that I can't change the second list size because it change the size of all the elements in the second list, so i can't have diferent sizes for each element of list.
Also I have the same problem with the popup, the item selected is allways the same for all the popups (as you can see in the second image).
How I can save each dimension or popup selected of each item selected without changing the others?
Here is my code:
ScriptableObject class
public class MyClass : ScriptableObject {
public class MyInsideClass
{
public List<string> data;
public MyInsideClass()
{
data = new List<string>();
}
}
public List<MyInsideClass> allData;
}
Custom Editor (Database just have the popup list names)
[CustomEditor(typeof(MyClass))]
public class TempEdior : Editor
{
int numberOfCombinations = 0;
int numberOfDataForCombination = 0;
int selected = 0;
public override void OnInspectorGUI()
{
GUILayout.BeginHorizontal();
GUILayout.Label("Number of combinations:");
numberOfCombinations = EditorGUILayout.IntField(numberOfCombinations);
GUILayout.EndHorizontal();
for (int i = 0; i < numberOfCombinations; i++)
{
GUILayout.BeginHorizontal();
GUILayout.Label("Combination " + (i + 1) + " - number of data:");
numberOfDataForCombination = EditorGUILayout.IntField(numberOfDataForCombination);
GUILayout.EndHorizontal();
for (int j = 0; j < numberOfDataForCombination; j++)
{
Rect rect = EditorGUILayout.GetControlRect();
selected = EditorGUI.Popup(new Rect(rect.x + 63, rect.y, 100, EditorGUIUtility.singleLineHeight), selected, Database.Instance.slotTypes.ToArray());
}
}
}
}
Upvotes: 1
Views: 13830
Reputation: 952
IMO you're approaching this the wrong way. It's easy to get carried away writing inspector code forever, in convoluted ways that break Unity's paradigms for little benefit. Rely on SerializedProperties as much as you can, as it will handle undo, multi-edit etc.
Basically all you want is to edit a string using a popup, right? Then just use a PropertyDrawer for this, and for the rest just let Unity's array inspector do its magic:
using System;
using UnityEditor;
using UnityEngine;
public class TestArrayOfArray : MonoBehaviour
{
[Serializable]
public struct ComboItem
{
public string value;
}
[Serializable]
public struct Combo
{
public ComboItem[] items;
}
public Combo[] combos;
}
[CustomPropertyDrawer(typeof(TestArrayOfArray.ComboItem))]
public class ComboItemDrawer : PropertyDrawer
{
static readonly string[] comboItemDatabase = { "Bla", "Bli", "Blu" };
static readonly GUIContent[] comboItemDatabaseGUIContents = Array.ConvertAll(comboItemDatabase, i => new GUIContent(i));
public override void OnGUI( Rect position, SerializedProperty property, GUIContent label )
{
property = property.FindPropertyRelative("value");
EditorGUI.BeginChangeCheck();
int selectedIndex = Array.IndexOf(comboItemDatabase, property.stringValue);
selectedIndex = EditorGUI.Popup(position, label, selectedIndex, comboItemDatabaseGUIContents);
if (EditorGUI.EndChangeCheck())
{
property.stringValue = comboItemDatabase[selectedIndex];
}
}
}
This is very crude, runtime + inspector code in a single file, fake "database" hard-coded as a static array, doesn't handle mixed values in case of a multi-edit, etc etc, but it should get you started.
--
General advice: favor arrays over Lists if you can, eg in this case the combos are static serialized data that you're never gonna resize at runtime, so an array is more efficient.
Inline field declarations when possible for readability (eg public List<string> data = new List<string>();
is fine).
Don't initialize arrays/lists that are serialized, as their default value will be overwritten by deserialization, leading to a wasted allocation.
Upvotes: 1