Remove: depth limit

This commit is contained in:
AnnulusGames 2024-03-04 23:36:38 +09:00
parent ea19961861
commit cd3c0f2a00
17 changed files with 96 additions and 75 deletions

View File

@ -92,7 +92,7 @@ namespace Alchemy.Editor
}
// Add elements
InspectorHelper.BuildElements(serializedObject, root, target, name => serializedObject.FindProperty(name), 0);
InspectorHelper.BuildElements(serializedObject, root, target, name => serializedObject.FindProperty(name));
return root;
}

View File

@ -21,7 +21,7 @@ namespace Alchemy.Editor
var serializedObject = new SerializedObject(this);
// Build visual elements and bind serialized object
InspectorHelper.BuildElements(serializedObject, windowElement, this, name => serializedObject.FindProperty(name), 0);
InspectorHelper.BuildElements(serializedObject, windowElement, this, name => serializedObject.FindProperty(name));
windowElement.Bind(serializedObject);
// Remove "Serialized Data Model Controller" field

View File

@ -11,9 +11,8 @@ namespace Alchemy.Editor.Elements
/// </summary>
public sealed class AlchemyPropertyField : BindableElement
{
public AlchemyPropertyField(SerializedProperty property, Type type, int depth, bool isArrayElement = false)
public AlchemyPropertyField(SerializedProperty property, Type type, bool isArrayElement = false)
{
if (depth > 20) return;
var labelText = ObjectNames.NicifyVariableName(property.displayName);
switch (property.propertyType)
@ -24,7 +23,7 @@ namespace Alchemy.Editor.Elements
case SerializedPropertyType.ObjectReference:
if (property.GetAttribute<InlineEditorAttribute>() != null)
{
element = new InlineEditorObjectField(property, type, depth);
element = new InlineEditorObjectField(property, type);
}
else
{
@ -40,14 +39,14 @@ namespace Alchemy.Editor.Elements
}
else if (property.isArray)
{
element = new PropertyListView(property, depth);
element = new PropertyListView(property);
}
else if (targetType.TryGetCustomAttribute<PropertyGroupAttribute>(out var groupAttribute)) // custom group
{
var drawer = AlchemyEditorUtility.CreateGroupDrawer(groupAttribute, targetType);
var root = drawer.CreateRootElement(labelText);
InspectorHelper.BuildElements(property.serializedObject, root, property.GetValue<object>(), name => property.FindPropertyRelative(name), depth + 1);
InspectorHelper.BuildElements(property.serializedObject, root, property.GetValue<object>(), name => property.FindPropertyRelative(name));
if (root is BindableElement bindableElement) bindableElement.BindProperty(property);
element = root;
}
@ -57,13 +56,13 @@ namespace Alchemy.Editor.Elements
var clickable = InternalAPIHelper.GetClickable(foldout.Q<Toggle>());
InternalAPIHelper.SetAcceptClicksIfDisabled(clickable, true);
InspectorHelper.BuildElements(property.serializedObject, foldout, property.GetValue<object>(), name => property.FindPropertyRelative(name), depth + 1);
InspectorHelper.BuildElements(property.serializedObject, foldout, property.GetValue<object>(), name => property.FindPropertyRelative(name));
foldout.BindProperty(property);
element = foldout;
}
break;
case SerializedPropertyType.ManagedReference:
element = new SerializeReferenceField(property, depth);
element = new SerializeReferenceField(property);
break;
}
Add(element);

View File

@ -7,11 +7,9 @@ namespace Alchemy.Editor.Elements
{
public sealed class ClassField : VisualElement
{
public ClassField(Type type, string label, int depth) : this(TypeHelper.CreateDefaultInstance(type), type, label, depth) { }
public ClassField(object obj, Type type, string label, int depth)
public ClassField(Type type, string label) : this(TypeHelper.CreateDefaultInstance(type), type, label) { }
public ClassField(object obj, Type type, string label)
{
if (depth > InspectorHelper.MaxDepth) return;
var foldout = new Foldout
{
text = label,
@ -46,7 +44,7 @@ namespace Alchemy.Editor.Elements
// Add member elements
foreach (var member in node.Members.OrderByAttributeThenByMemberType())
{
var element = new ReflectionField(obj, member, depth + 1);
var element = new ReflectionField(obj, member);
element.style.width = Length.Percent(100f);
element.OnValueChanged += x => OnValueChanged?.Invoke(obj);

View File

@ -8,7 +8,7 @@ namespace Alchemy.Editor.Elements
{
public sealed class DictionaryField : HashMapFieldBase
{
public DictionaryField(object collection, string label, int depth) : base(collection, label, depth)
public DictionaryField(object collection, string label) : base(collection, label)
{
if (collection != null)
{
@ -60,14 +60,14 @@ namespace Alchemy.Editor.Elements
ReflectionHelper.Invoke(Collection, "Clear");
}
public override HashMapItemBase CreateItem(object collection, object elementObj, string label, int depth)
public override HashMapItemBase CreateItem(object collection, object elementObj, string label)
{
return new Item(collection, elementObj, depth + 1);
return new Item(collection, elementObj);
}
public sealed class Item : HashMapItemBase
{
public Item(object collection, object keyValuePair, int depth)
public Item(object collection, object keyValuePair)
{
var box = new Box()
{
@ -97,14 +97,14 @@ namespace Alchemy.Editor.Elements
};
box.Add(keyValueElement);
keyField = new GenericField(key, keyType, KeyName, depth)
keyField = new GenericField(key, keyType, KeyName)
{
style = { flexGrow = 1f }
};
keyField.OnValueChanged += SetKey;
keyValueElement.Add(keyField);
valueField = new GenericField(value, valueType, ValueName, depth)
valueField = new GenericField(value, valueType, ValueName)
{
style = { flexGrow = 1f }
};

View File

@ -15,15 +15,14 @@ namespace Alchemy.Editor.Elements
{
const string CreateButtonText = "Create...";
public GenericField(object obj, Type type, string label, int depth, bool isDelayed = false)
public GenericField(object obj, Type type, string label,bool isDelayed = false)
{
Build(obj, type, label, depth, isDelayed);
Build(obj, type, label, isDelayed);
GUIHelper.ScheduleAdjustLabelWidth(this);
}
void Build(object obj, Type type, string label, int depth, bool isDelayed)
void Build(object obj, Type type, string label, bool isDelayed)
{
if (depth > InspectorHelper.MaxDepth) return;
Clear();
// Add [Create...] button
@ -53,7 +52,7 @@ namespace Alchemy.Editor.Elements
nullLabelElement.Add(new Button(() =>
{
var instance = "";
Build(instance, type, label, depth, isDelayed);
Build(instance, type, label, isDelayed);
OnValueChanged?.Invoke(instance);
})
{
@ -65,7 +64,7 @@ namespace Alchemy.Editor.Elements
nullLabelElement.Add(new Button(() =>
{
var instance = Activator.CreateInstance(type, Activator.CreateInstance(type.GenericTypeArguments[0]));
Build(instance, type, label, depth, isDelayed);
Build(instance, type, label, isDelayed);
OnValueChanged?.Invoke(instance);
})
{
@ -77,7 +76,7 @@ namespace Alchemy.Editor.Elements
nullLabelElement.Add(new Button(() =>
{
var instance = TypeHelper.CreateDefaultInstance(type);
Build(instance, type, label, depth, isDelayed);
Build(instance, type, label, isDelayed);
OnValueChanged?.Invoke(instance);
})
{
@ -228,26 +227,26 @@ namespace Alchemy.Editor.Elements
}
else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>))
{
var field = new HashSetField(obj, label, depth + 1);
var field = new HashSetField(obj, label);
field.OnValueChanged += x => OnValueChanged?.Invoke(x);
Add(field);
}
else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
var field = new DictionaryField(obj, label, depth + 1);
var field = new DictionaryField(obj, label);
field.OnValueChanged += x => OnValueChanged?.Invoke(x);
Add(field);
}
else if (typeof(IList).IsAssignableFrom(type))
{
var field = new ListField((IList)obj, label, depth + 1);
var field = new ListField((IList)obj, label);
field.OnValueChanged += x => OnValueChanged?.Invoke(x);
Add(field);
}
else
{
var field = new ClassField(obj, type, label, depth + 1);
var field = new ClassField(obj, type, label);
field.OnValueChanged += x => OnValueChanged?.Invoke(x);
Add(field);
}

View File

@ -8,9 +8,8 @@ namespace Alchemy.Editor.Elements
{
public abstract class HashMapFieldBase : VisualElement
{
public HashMapFieldBase(object collection, string label, int depth)
public HashMapFieldBase(object collection, string label)
{
this.depth = depth;
this.collection = collection;
var foldout = new Foldout()
@ -51,7 +50,6 @@ namespace Alchemy.Editor.Elements
public object Collection => collection;
readonly object collection;
readonly int depth;
bool isInputting;
@ -75,7 +73,7 @@ namespace Alchemy.Editor.Elements
isInputting = true;
var initValue = CreateElement();
var form = CreateItem(collection, initValue, "New Value", depth);
var form = CreateItem(collection, initValue, "New Value");
inputForm.Clear();
inputForm.Add(form);
form.OnValueChanged += ValidateValue;
@ -119,7 +117,7 @@ namespace Alchemy.Editor.Elements
var i = 0;
foreach (var item in (IEnumerable)collection)
{
var element = CreateItem(collection, item, "Element " + i, depth);
var element = CreateItem(collection, item, "Element " + i);
element.OnClose += () =>
{
if (isInputting) return;
@ -151,7 +149,7 @@ namespace Alchemy.Editor.Elements
}
}
public abstract HashMapItemBase CreateItem(object collection, object elementObj, string label, int depth);
public abstract HashMapItemBase CreateItem(object collection, object elementObj, string label);
public abstract bool CheckElement(object element);
public abstract object CreateElement();
public abstract void AddElement(object element);

View File

@ -6,7 +6,7 @@ namespace Alchemy.Editor.Elements
{
public sealed class HashSetField : HashMapFieldBase
{
public HashSetField(object collection, string label, int depth) : base(collection, label, depth) { }
public HashSetField(object collection, string label) : base(collection, label) { }
public override string CollectionTypeName => "HashSet";
@ -35,14 +35,14 @@ namespace Alchemy.Editor.Elements
ReflectionHelper.Invoke(Collection, "Clear");
}
public override HashMapItemBase CreateItem(object collection, object elementObj, string label, int depth)
public override HashMapItemBase CreateItem(object collection, object elementObj, string label)
{
return new Item(collection, elementObj, label, depth);
return new Item(collection, elementObj, label);
}
public sealed class Item : HashMapItemBase
{
public Item(object collection, object elementObj, string label, int depth)
public Item(object collection, object elementObj, string label)
{
var box = new Box()
{
@ -55,7 +55,7 @@ namespace Alchemy.Editor.Elements
var valueType = elementObj == null ? collection.GetType().GenericTypeArguments[0] : elementObj.GetType();
inputField = new GenericField(elementObj, valueType, label, depth);
inputField = new GenericField(elementObj, valueType, label);
inputField.style.flexGrow = 1f;
inputField.OnValueChanged += x =>
{

View File

@ -12,12 +12,10 @@ namespace Alchemy.Editor.Elements
/// </summary>
public sealed class InlineEditorObjectField : BindableElement
{
public InlineEditorObjectField(SerializedProperty property, Type type, int depth)
public InlineEditorObjectField(SerializedProperty property, Type type)
{
Assert.IsTrue(property.propertyType == SerializedPropertyType.ObjectReference);
this.depth = depth;
style.minHeight = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
foldout = new Foldout()
@ -55,7 +53,6 @@ namespace Alchemy.Editor.Elements
readonly Foldout foldout;
readonly ObjectField field;
readonly int depth;
bool isNull;
public bool IsObjectNull => isNull;
@ -101,7 +98,7 @@ namespace Alchemy.Editor.Elements
{
foldout.Add(new VisualElement() { style = { height = EditorGUIUtility.standardVerticalSpacing } });
var so = new SerializedObject(property.objectReferenceValue);
InspectorHelper.BuildElements(so, foldout, so.targetObject, name => so.FindProperty(name), depth);
InspectorHelper.BuildElements(so, foldout, so.targetObject, name => so.FindProperty(name));
this.Bind(so);
}
else

View File

@ -18,7 +18,7 @@ namespace Alchemy.Editor.Elements
const string ItemClassName = "unity-list-view__item";
public ListField(IList target, string label, int depth)
public ListField(IList target, string label)
{
Assert.IsNotNull(target);
list = target;
@ -32,7 +32,7 @@ namespace Alchemy.Editor.Elements
var value = list[index];
var listType = list.GetType();
var valueType = value != null ? value.GetType() : listType.IsGenericType ? listType.GenericTypeArguments[0] : typeof(object);
var fieldElement = new GenericField(value, valueType, label, depth);
var fieldElement = new GenericField(value, valueType, label);
element.Add(fieldElement);
var labelElement = fieldElement.Q<Label>();
if (labelElement != null) labelElement.text = "Element " + index;

View File

@ -60,7 +60,7 @@ namespace Alchemy.Editor.Elements
var index = i;
var parameter = parameters[index];
parameterObjects[index] = TypeHelper.CreateDefaultInstance(parameter.ParameterType);
var element = new GenericField(parameterObjects[index], parameter.ParameterType, ObjectNames.NicifyVariableName(parameter.Name), 0);
var element = new GenericField(parameterObjects[index], parameter.ParameterType, ObjectNames.NicifyVariableName(parameter.Name));
element.OnValueChanged += x => parameterObjects[index] = x;
element.style.paddingRight = 4f;
foldout.Add(element);

View File

@ -12,7 +12,7 @@ namespace Alchemy.Editor.Elements
/// </summary>
public sealed class PropertyListView : BindableElement
{
public PropertyListView(SerializedProperty property, int depth)
public PropertyListView(SerializedProperty property)
{
Assert.IsTrue(property.isArray);
@ -24,7 +24,7 @@ namespace Alchemy.Editor.Elements
listView.bindItem = (element, index) =>
{
var arrayElement = property.GetArrayElementAtIndex(index);
var e = new AlchemyPropertyField(arrayElement, property.GetPropertyType(true), depth + 1, true);
var e = new AlchemyPropertyField(arrayElement, property.GetPropertyType(true), true);
element.Add(e);
element.Bind(arrayElement.serializedObject);
if (events != null)

View File

@ -9,12 +9,12 @@ namespace Alchemy.Editor.Elements
{
public sealed class ReflectionField : VisualElement
{
public ReflectionField(object target, MemberInfo memberInfo, int depth)
public ReflectionField(object target, MemberInfo memberInfo)
{
Rebuild(target, memberInfo, depth);
Rebuild(target, memberInfo);
}
public void Rebuild(object target, MemberInfo memberInfo, int depth)
public void Rebuild(object target, MemberInfo memberInfo)
{
Clear();
@ -36,7 +36,7 @@ namespace Alchemy.Editor.Elements
case FieldInfo fieldInfo:
value = fieldInfo.IsStatic ? fieldInfo.GetValue(null) : target == null ? TypeHelper.GetDefaultValue(fieldInfo.FieldType) : fieldInfo.GetValue(target);
var fieldType = target == null ? fieldInfo.FieldType : fieldInfo.GetValue(target)?.GetType() ?? fieldInfo.FieldType;
element = new GenericField(value, fieldType, ObjectNames.NicifyVariableName(memberInfo.Name), depth, true);
element = new GenericField(value, fieldType, ObjectNames.NicifyVariableName(memberInfo.Name), true);
element.OnValueChanged += x =>
{
OnBeforeValueChange?.Invoke(target);
@ -57,7 +57,7 @@ namespace Alchemy.Editor.Elements
value = propertyInfo.GetMethod.IsStatic ? propertyInfo.GetValue(null) : target == null ? TypeHelper.GetDefaultValue(propertyInfo.PropertyType) : propertyInfo.GetValue(target);
var propertyType = target == null ? propertyInfo.PropertyType : propertyInfo.GetValue(target)?.GetType() ?? propertyInfo.PropertyType;
element = new GenericField(value, propertyType, ObjectNames.NicifyVariableName(memberInfo.Name), depth, true);
element = new GenericField(value, propertyType, ObjectNames.NicifyVariableName(memberInfo.Name), true);
element.OnValueChanged += x =>
{
OnBeforeValueChange?.Invoke(target);

View File

@ -14,7 +14,7 @@ namespace Alchemy.Editor.Elements
/// </summary>
public sealed class SerializeReferenceField : VisualElement
{
public SerializeReferenceField(SerializedProperty property, int depth)
public SerializeReferenceField(SerializedProperty property)
{
Assert.IsTrue(property.propertyType == SerializedPropertyType.ManagedReference);
@ -76,7 +76,7 @@ namespace Alchemy.Editor.Elements
property.serializedObject.ApplyModifiedProperties();
property.serializedObject.Update();
Rebuild(property, depth);
Rebuild(property);
};
dropdown.Show(position);
@ -100,7 +100,7 @@ namespace Alchemy.Editor.Elements
buttonContainer.style.right = 0f;
Add(buttonContainer);
Rebuild(property, depth);
Rebuild(property);
}
public readonly Foldout foldout;
@ -109,7 +109,7 @@ namespace Alchemy.Editor.Elements
/// <summary>
/// Rebuild child elements
/// </summary>
void Rebuild(SerializedProperty property, int depth)
void Rebuild(SerializedProperty property)
{
foldout.Clear();
@ -120,7 +120,7 @@ namespace Alchemy.Editor.Elements
}
else
{
InspectorHelper.BuildElements(property.serializedObject, foldout, property.managedReferenceValue, x => property.FindPropertyRelative(x), depth + 1);
InspectorHelper.BuildElements(property.serializedObject, foldout, property.managedReferenceValue, x => property.FindPropertyRelative(x));
}
this.Bind(property.serializedObject);

View File

@ -16,8 +16,6 @@ namespace Alchemy.Editor
{
internal static class InspectorHelper
{
public const int MaxDepth = 15;
public sealed class GroupNode
{
public GroupNode(string name, AlchemyGroupDrawer drawer)
@ -74,9 +72,8 @@ namespace Alchemy.Editor
}
}
public static void BuildElements(SerializedObject serializedObject, VisualElement rootElement, object target, Func<string, SerializedProperty> findPropertyFunc, int depth)
public static void BuildElements(SerializedObject serializedObject, VisualElement rootElement, object target, Func<string, SerializedProperty> findPropertyFunc)
{
if (depth >= MaxDepth) return;
if (target == null) return;
// Build node
@ -133,7 +130,7 @@ namespace Alchemy.Editor
}
else
{
element = CreateMemberElement(serializedObject, target, member, findPropertyFunc, depth + 1);
element = CreateMemberElement(serializedObject, target, member, findPropertyFunc);
}
if (element == null) continue;
@ -197,10 +194,8 @@ namespace Alchemy.Editor
return rootNode;
}
public static VisualElement CreateMemberElement(SerializedObject serializedObject, object target, MemberInfo memberInfo, Func<string, SerializedProperty> findPropertyFunc, int depth)
public static VisualElement CreateMemberElement(SerializedObject serializedObject, object target, MemberInfo memberInfo, Func<string, SerializedProperty> findPropertyFunc)
{
if (depth > MaxDepth) return null;
switch (memberInfo)
{
case MethodInfo methodInfo:
@ -224,11 +219,11 @@ namespace Alchemy.Editor
{
if (memberInfo is FieldInfo fieldInfo)
{
return new AlchemyPropertyField(property, fieldInfo.FieldType, depth);
return new AlchemyPropertyField(property, fieldInfo.FieldType);
}
else
{
return new AlchemyPropertyField(property, ((PropertyInfo)memberInfo).PropertyType, depth);
return new AlchemyPropertyField(property, ((PropertyInfo)memberInfo).PropertyType);
}
}
}
@ -246,12 +241,12 @@ namespace Alchemy.Editor
var p = GetProperty();
if (p != null)
{
var field = new ReflectionField(target, fieldInfo, depth);
var field = new ReflectionField(target, fieldInfo);
var foldout = field.Q<Foldout>();
foldout?.BindProperty(p);
field.TrackPropertyValue(p, p =>
{
field.Rebuild(target, memberInfo, depth);
field.Rebuild(target, memberInfo);
var foldout = field.Q<Foldout>();
foldout?.BindProperty(p);
});
@ -279,7 +274,7 @@ namespace Alchemy.Editor
// Create element if member has ShowInInspector attribute
if (memberInfo.HasCustomAttribute<ShowInInspectorAttribute>())
{
return new ReflectionField(target, memberInfo, depth);
return new ReflectionField(target, memberInfo);
}
break;
}

View File

@ -0,0 +1,24 @@
using System;
using Alchemy.Inspector;
using UnityEngine;
public class DepthTest : MonoBehaviour
{
[Serializable]
[BoxGroup]
public class NodeA
{
[SerializeField] float foo;
[SerializeField] NodeB node;
}
[Serializable]
[BoxGroup]
public class NodeB
{
[SerializeField] float bar;
[SerializeField] NodeA node;
}
public NodeA node;
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6eba956dee63540d8b7030e2e337edfc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: