public static void DrawVariable(Type fieldType, string fieldName, object fieldValue, string tooltip, VariableAttributes variableAttributes, IEnumerable <Attribute> customAttributes, bool allowExtensions, Type contextType, Action <object> changeCallback) { if ((variableAttributes & VariableAttributes.Static) != 0) { var style = new GUIStyle { normal = { background = SidekickEditorGUI.StaticBackground } }; EditorGUILayout.BeginVertical(style); } GUIStyle expandButtonStyle = new GUIStyle(GUI.skin.button); RectOffset padding = expandButtonStyle.padding; padding.left = 0; padding.right = 1; expandButtonStyle.padding = padding; fieldValue ??= TypeUtility.GetDefaultValue(fieldType); string displayName = SidekickUtility.NicifyIdentifier(fieldName); GUIContent label = new GUIContent(displayName, tooltip); bool isArray = fieldType.IsArray; bool isGenericList = TypeUtility.IsGenericList(fieldType); bool isGenericDictionary = TypeUtility.IsGenericDictionary(fieldType); if (isGenericDictionary) { EditorGUILayout.BeginHorizontal(); string expandedID = fieldType.FullName + fieldName; bool expanded = DrawHeader(expandedID, label, (variableAttributes & VariableAttributes.Static) != 0); int count = 0; if (fieldValue != null) { EditorGUI.BeginDisabledGroup(true); count = (int)fieldType.GetProperty("Count").GetValue(fieldValue); EditorGUILayout.IntField(count, GUILayout.Width(80)); EditorGUI.EndDisabledGroup(); } if (allowExtensions) { DrawExtensions(fieldValue, expandButtonStyle); } EditorGUILayout.EndHorizontal(); if (expanded) { EditorGUI.indentLevel++; if (fieldValue != null) { FieldInfo entriesArrayField = fieldType.GetField("entries", BindingFlags.NonPublic | BindingFlags.Instance); IList entriesArray = (IList)entriesArrayField.GetValue(fieldValue); Type elementType = TypeUtility.GetFirstElementType(entriesArrayField.FieldType); FieldInfo elementKeyFieldInfo = elementType.GetField("key", BindingFlags.Public | BindingFlags.Instance); FieldInfo elementValueFieldInfo = elementType.GetField("value", BindingFlags.Public | BindingFlags.Instance); int oldIndent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; for (int i = 0; i < count; i++) { object entry = entriesArray[i]; EditorGUILayout.BeginHorizontal(); object key = elementKeyFieldInfo.GetValue(entry); object value = elementValueFieldInfo.GetValue(entry); using (new EditorGUI.DisabledScope(true)) { DrawIndividualVariable(GUIContent.none, key.GetType(), key, null, out _, newValue => { /*list[index] = newValue;*/ }); } DrawIndividualVariable(GUIContent.none, value.GetType(), value, null, out var handled, newValue => { PropertyInfo indexer = fieldType.GetProperties().First(x => x.GetIndexParameters().Length > 0); indexer.SetValue(fieldValue, newValue, new[] { key }); }); EditorGUILayout.EndHorizontal(); } EditorGUI.indentLevel = oldIndent; } EditorGUI.indentLevel--; } EditorGUILayout.EndFoldoutHeaderGroup(); } else if (isArray || isGenericList) { Type elementType = TypeUtility.GetFirstElementType(fieldType); EditorGUILayout.BeginHorizontal(); string expandedID = fieldType.FullName + fieldName; bool expanded = DrawHeader(expandedID, label, (variableAttributes & VariableAttributes.Static) != 0); EditorGUI.BeginDisabledGroup((variableAttributes & VariableAttributes.ReadOnly) != 0); IList list = null; int previousSize = 0; if (fieldValue != null) { list = (IList)fieldValue; previousSize = list.Count; } int newSize = Mathf.Max(0, EditorGUILayout.IntField(previousSize, GUILayout.Width(80))); if (newSize != previousSize) { var newValue = CollectionUtility.Resize(list, isArray, fieldType, elementType, newSize); changeCallback(newValue); } if (allowExtensions) { DrawExtensions(fieldValue, expandButtonStyle); } EditorGUILayout.EndHorizontal(); if (expanded) { EditorGUI.indentLevel++; if (list != null) { for (int i = 0; i < list.Count; i++) { EditorGUILayout.BeginHorizontal(); int index = i; DrawIndividualVariable(new GUIContent("Element " + i), elementType, list[i], null, out var handled, newValue => { list[index] = newValue; }); if (allowExtensions) { DrawExtensions(list[i], expandButtonStyle); } EditorGUILayout.EndHorizontal(); } } EditorGUI.indentLevel--; } EditorGUILayout.EndFoldoutHeaderGroup(); } else { EditorGUI.BeginDisabledGroup((variableAttributes & VariableAttributes.ReadOnly) != 0); // Not a collection EditorGUILayout.BeginHorizontal(); DrawIndividualVariable(label, fieldType, fieldValue, customAttributes, out var handled, changeCallback); if (handled && allowExtensions) { DrawExtensions(fieldValue, expandButtonStyle); } EditorGUILayout.EndHorizontal(); if (!handled) { EditorGUI.EndDisabledGroup(); string expandedID = fieldType.FullName + fieldName; EditorGUILayout.BeginHorizontal(); bool expanded = DrawHeader(expandedID, label, (variableAttributes & VariableAttributes.Static) != 0); if (allowExtensions) { DrawExtensions(fieldValue, expandButtonStyle); } EditorGUILayout.EndHorizontal(); EditorGUI.BeginDisabledGroup((variableAttributes & VariableAttributes.ReadOnly) != 0); if (expanded) { EditorGUI.indentLevel++; if (fieldValue != null) { var fields = fieldType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (var fieldInfo in fields) { GUIContent subLabel = new GUIContent(fieldInfo.Name); DrawIndividualVariable(subLabel, fieldInfo.FieldType, fieldInfo.GetValue(fieldValue), null, out _, newValue => { fieldInfo.SetValue(fieldValue, newValue); }); } } else { GUILayout.Label("Null"); } EditorGUI.indentLevel--; } EditorGUILayout.EndFoldoutHeaderGroup(); } } EditorGUI.EndDisabledGroup(); if ((variableAttributes & VariableAttributes.Static) != 0) { EditorGUILayout.EndVertical(); } }