2021-12-07 10:20:36 -05:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
2022-01-15 11:25:12 -05:00
|
|
|
|
using System.Linq;
|
2022-01-18 12:41:11 -05:00
|
|
|
|
using System.Reflection;
|
2023-04-06 06:33:19 -04:00
|
|
|
|
using System.Text;
|
2021-12-07 10:20:36 -05:00
|
|
|
|
using JetBrains.Annotations;
|
|
|
|
|
using TriInspector.Utilities;
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
namespace TriInspector
|
|
|
|
|
{
|
2022-06-01 03:35:33 -04:00
|
|
|
|
public sealed class TriProperty
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
2023-04-06 06:33:19 -04:00
|
|
|
|
private static readonly StringBuilder SharedPropertyPathStringBuilder = new StringBuilder();
|
|
|
|
|
|
2022-01-15 11:25:12 -05:00
|
|
|
|
private static readonly IReadOnlyList<TriValidationResult> EmptyValidationResults =
|
|
|
|
|
new List<TriValidationResult>();
|
2022-01-18 12:19:15 -05:00
|
|
|
|
|
2021-12-07 10:20:36 -05:00
|
|
|
|
private readonly TriPropertyDefinition _definition;
|
2022-01-06 10:43:09 -05:00
|
|
|
|
private readonly int _propertyIndex;
|
2022-06-01 03:35:33 -04:00
|
|
|
|
[CanBeNull] private readonly SerializedObject _serializedObject;
|
2021-12-07 10:20:36 -05:00
|
|
|
|
[CanBeNull] private readonly SerializedProperty _serializedProperty;
|
|
|
|
|
private List<TriProperty> _childrenProperties;
|
2022-01-15 11:25:12 -05:00
|
|
|
|
private List<TriValidationResult> _validationResults;
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
|
|
|
|
private GUIContent _displayNameBackingField;
|
2023-04-06 06:33:19 -04:00
|
|
|
|
private string _propertyPath;
|
2022-01-20 05:12:52 -05:00
|
|
|
|
private string _isExpandedPrefsKey;
|
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
private int _lastUpdateFrame;
|
|
|
|
|
private bool _isUpdating;
|
|
|
|
|
|
|
|
|
|
[CanBeNull] private object _value;
|
|
|
|
|
[CanBeNull] private Type _valueType;
|
|
|
|
|
private bool _isValueMixed;
|
|
|
|
|
|
2022-06-02 03:18:13 -04:00
|
|
|
|
public event Action<TriProperty> ValueChanged;
|
|
|
|
|
public event Action<TriProperty> ChildValueChanged;
|
2022-06-01 03:35:33 -04:00
|
|
|
|
|
|
|
|
|
internal TriProperty(
|
|
|
|
|
TriPropertyTree propertyTree,
|
|
|
|
|
TriProperty parent,
|
|
|
|
|
TriPropertyDefinition definition,
|
|
|
|
|
SerializedObject serializedObject
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
Parent = parent;
|
|
|
|
|
_definition = definition;
|
|
|
|
|
_propertyIndex = -1;
|
|
|
|
|
_serializedProperty = null;
|
|
|
|
|
_serializedObject = serializedObject;
|
|
|
|
|
|
|
|
|
|
PropertyTree = propertyTree;
|
|
|
|
|
PropertyType = GetPropertyType(this);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 10:20:36 -05:00
|
|
|
|
internal TriProperty(
|
2022-05-21 04:49:12 -04:00
|
|
|
|
TriPropertyTree propertyTree,
|
2022-06-01 03:35:33 -04:00
|
|
|
|
TriProperty parent,
|
2021-12-07 10:20:36 -05:00
|
|
|
|
TriPropertyDefinition definition,
|
2022-01-06 10:43:09 -05:00
|
|
|
|
int propertyIndex,
|
2021-12-07 10:20:36 -05:00
|
|
|
|
[CanBeNull] SerializedProperty serializedProperty)
|
|
|
|
|
{
|
2022-06-01 03:35:33 -04:00
|
|
|
|
Parent = parent;
|
2021-12-07 10:20:36 -05:00
|
|
|
|
_definition = definition;
|
2022-01-06 10:43:09 -05:00
|
|
|
|
_propertyIndex = propertyIndex;
|
2021-12-07 10:20:36 -05:00
|
|
|
|
_serializedProperty = serializedProperty?.Copy();
|
2022-06-01 03:35:33 -04:00
|
|
|
|
_serializedObject = _serializedProperty?.serializedObject;
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
|
|
|
|
PropertyTree = propertyTree;
|
|
|
|
|
PropertyType = GetPropertyType(this);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-13 06:18:29 -05:00
|
|
|
|
internal TriPropertyDefinition Definition => _definition;
|
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public TriPropertyType PropertyType { get; }
|
|
|
|
|
|
|
|
|
|
[PublicAPI]
|
|
|
|
|
public TriPropertyTree PropertyTree { get; }
|
|
|
|
|
|
2022-06-01 03:35:33 -04:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public TriProperty Parent { get; }
|
|
|
|
|
|
2022-12-09 10:50:24 -05:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public TriProperty Owner => IsArrayElement ? Parent.Owner : Parent;
|
|
|
|
|
|
2022-06-01 03:35:33 -04:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public bool IsRootProperty => Parent == null;
|
|
|
|
|
|
2022-01-21 12:12:46 -05:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public string RawName => _definition.Name;
|
|
|
|
|
|
2022-01-15 11:25:12 -05:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public string DisplayName => DisplayNameContent.text;
|
2022-01-18 12:19:15 -05:00
|
|
|
|
|
2022-07-12 06:09:21 -04:00
|
|
|
|
public IEqualityComparer Comparer => TriEqualityComparer.Of(ValueType);
|
|
|
|
|
|
2021-12-07 10:20:36 -05:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public GUIContent DisplayNameContent
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2022-05-30 06:15:09 -04:00
|
|
|
|
if (TriPropertyOverrideContext.Current != null &&
|
|
|
|
|
TriPropertyOverrideContext.Current.TryGetDisplayName(this, out var overrideName))
|
2022-01-30 10:44:16 -05:00
|
|
|
|
{
|
2022-05-30 06:15:09 -04:00
|
|
|
|
return overrideName;
|
2022-01-30 10:44:16 -05:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 10:20:36 -05:00
|
|
|
|
if (_displayNameBackingField == null)
|
|
|
|
|
{
|
2022-05-29 10:39:48 -04:00
|
|
|
|
if (TryGetAttribute(out HideLabelAttribute _) || IsArrayElement)
|
2022-01-06 10:43:09 -05:00
|
|
|
|
{
|
2022-05-14 02:14:42 -04:00
|
|
|
|
_displayNameBackingField = new GUIContent("");
|
2022-01-06 10:43:09 -05:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_displayNameBackingField = new GUIContent(ObjectNames.NicifyVariableName(_definition.Name));
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-11 12:17:12 -05:00
|
|
|
|
if (IsArrayElement)
|
|
|
|
|
{
|
|
|
|
|
if (TriUnityInspectorUtilities.TryGetSpecialArrayElementName(this, out var specialName))
|
|
|
|
|
{
|
|
|
|
|
_displayNameBackingField.text = specialName;
|
|
|
|
|
}
|
2023-08-18 02:35:16 -04:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_displayNameBackingField.text = TriUnityInspectorUtilities.GetStandardArrayElementName(this);
|
|
|
|
|
}
|
2022-11-11 12:17:12 -05:00
|
|
|
|
}
|
|
|
|
|
else
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
2022-05-16 01:44:30 -04:00
|
|
|
|
if (_definition.CustomLabel != null)
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
2022-05-16 01:44:30 -04:00
|
|
|
|
_displayNameBackingField.text = _definition.CustomLabel.GetValue(this, "");
|
2021-12-07 10:20:36 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-16 01:44:30 -04:00
|
|
|
|
if (_definition.CustomTooltip != null)
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
2022-05-16 01:44:30 -04:00
|
|
|
|
_displayNameBackingField.tooltip = _definition.CustomTooltip.GetValue(this, "");
|
2021-12-07 10:20:36 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _displayNameBackingField;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-06 06:33:19 -04:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public string PropertyPath
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (_propertyPath == null)
|
|
|
|
|
{
|
|
|
|
|
SharedPropertyPathStringBuilder.Clear();
|
|
|
|
|
BuildPropertyPath(this, SharedPropertyPathStringBuilder);
|
|
|
|
|
_propertyPath = SharedPropertyPathStringBuilder.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _propertyPath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 10:20:36 -05:00
|
|
|
|
[PublicAPI]
|
2022-01-05 07:24:23 -05:00
|
|
|
|
public bool IsVisible
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
foreach (var processor in _definition.HideProcessors)
|
|
|
|
|
{
|
|
|
|
|
if (processor.IsHidden(this))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
|
|
|
|
[PublicAPI]
|
|
|
|
|
public bool IsEnabled
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2022-01-05 07:24:23 -05:00
|
|
|
|
if (_definition.IsReadOnly)
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-01-06 10:43:09 -05:00
|
|
|
|
|
2022-01-05 07:24:23 -05:00
|
|
|
|
foreach (var processor in _definition.DisableProcessors)
|
|
|
|
|
{
|
|
|
|
|
if (processor.IsDisabled(this))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[PublicAPI]
|
|
|
|
|
public Type FieldType => _definition.FieldType;
|
|
|
|
|
|
|
|
|
|
[PublicAPI]
|
|
|
|
|
public Type ArrayElementType => _definition.ArrayElementType;
|
|
|
|
|
|
|
|
|
|
[PublicAPI]
|
|
|
|
|
public bool IsArrayElement => _definition.IsArrayElement;
|
|
|
|
|
|
2022-01-08 12:25:50 -05:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public bool IsArray => _definition.IsArray;
|
|
|
|
|
|
2022-01-06 10:43:09 -05:00
|
|
|
|
public int IndexInArray => IsArrayElement
|
|
|
|
|
? _propertyIndex
|
|
|
|
|
: throw new InvalidOperationException("Cannot read IndexInArray for !IsArrayElement");
|
|
|
|
|
|
2021-12-07 10:20:36 -05:00
|
|
|
|
public IReadOnlyList<TriCustomDrawer> AllDrawers => _definition.Drawers;
|
|
|
|
|
|
2022-06-06 07:17:53 -04:00
|
|
|
|
internal IReadOnlyList<string> ExtensionErrors => _definition.ExtensionErrors;
|
|
|
|
|
|
2022-01-15 11:25:12 -05:00
|
|
|
|
public bool HasValidators => _definition.Validators.Count != 0;
|
|
|
|
|
|
|
|
|
|
public IReadOnlyList<TriValidationResult> ValidationResults =>
|
|
|
|
|
_validationResults ?? EmptyValidationResults;
|
|
|
|
|
|
2021-12-07 10:20:36 -05:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public bool IsExpanded
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (_serializedProperty != null)
|
|
|
|
|
{
|
|
|
|
|
return _serializedProperty.isExpanded;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-21 23:36:15 -05:00
|
|
|
|
if (_isExpandedPrefsKey == null)
|
|
|
|
|
{
|
2023-04-06 06:35:01 -04:00
|
|
|
|
_isExpandedPrefsKey = $"TriInspector.expanded.{PropertyPath}";
|
2022-01-21 23:36:15 -05:00
|
|
|
|
}
|
2022-01-20 05:12:52 -05:00
|
|
|
|
|
2023-04-06 06:35:01 -04:00
|
|
|
|
return SessionState.GetBool(_isExpandedPrefsKey, false);
|
2021-12-07 10:20:36 -05:00
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (IsExpanded == value)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_serializedProperty != null)
|
|
|
|
|
{
|
|
|
|
|
_serializedProperty.isExpanded = value;
|
|
|
|
|
}
|
2022-01-20 05:12:52 -05:00
|
|
|
|
else if (_isExpandedPrefsKey != null)
|
|
|
|
|
{
|
2023-04-06 06:35:01 -04:00
|
|
|
|
SessionState.SetBool(_isExpandedPrefsKey, value);
|
2022-01-20 05:12:52 -05:00
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[PublicAPI]
|
|
|
|
|
[CanBeNull]
|
2022-05-29 07:41:40 -04:00
|
|
|
|
public Type ValueType
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2022-05-29 11:10:35 -04:00
|
|
|
|
if (PropertyType != TriPropertyType.Reference)
|
|
|
|
|
{
|
|
|
|
|
return _definition.FieldType;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
UpdateIfRequired();
|
|
|
|
|
return _valueType;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
public bool IsValueMixed
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2022-05-29 11:10:35 -04:00
|
|
|
|
if (PropertyTree.TargetsCount == 1)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
UpdateIfRequired();
|
|
|
|
|
return _isValueMixed;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-08 10:36:08 -05:00
|
|
|
|
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
|
|
|
|
[PublicAPI]
|
2022-05-29 07:41:40 -04:00
|
|
|
|
[CanBeNull]
|
|
|
|
|
public object Value
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
UpdateIfRequired();
|
|
|
|
|
return _value;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
|
|
|
|
[PublicAPI]
|
2022-05-29 07:41:40 -04:00
|
|
|
|
public IReadOnlyList<TriProperty> ChildrenProperties
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2022-05-29 11:10:35 -04:00
|
|
|
|
if (_childrenProperties != null && PropertyType == TriPropertyType.Generic)
|
|
|
|
|
{
|
|
|
|
|
return _childrenProperties;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
UpdateIfRequired();
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
return PropertyType == TriPropertyType.Generic || PropertyType == TriPropertyType.Reference
|
|
|
|
|
? _childrenProperties
|
|
|
|
|
: throw new InvalidOperationException("Cannot read ChildrenProperties for " + PropertyType);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
|
|
|
|
[PublicAPI]
|
2022-05-29 07:41:40 -04:00
|
|
|
|
public IReadOnlyList<TriProperty> ArrayElementProperties
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
UpdateIfRequired();
|
|
|
|
|
|
|
|
|
|
return PropertyType == TriPropertyType.Array
|
|
|
|
|
? _childrenProperties
|
|
|
|
|
: throw new InvalidOperationException("Cannot read ArrayElementProperties for " + PropertyType);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-08-17 13:46:26 -04:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public bool TryGetMemberInfo(out MemberInfo memberInfo)
|
|
|
|
|
{
|
|
|
|
|
return _definition.TryGetMemberInfo(out memberInfo);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-20 05:05:35 -05:00
|
|
|
|
public object GetValue(int targetIndex)
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
2022-01-06 10:43:09 -05:00
|
|
|
|
return _definition.GetValue(this, targetIndex);
|
2021-12-07 10:20:36 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[PublicAPI]
|
|
|
|
|
public void SetValue(object value)
|
2022-05-09 03:29:33 -04:00
|
|
|
|
{
|
|
|
|
|
ModifyAndRecordForUndo(targetIndex => SetValueRecursive(this, value, targetIndex));
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 09:27:41 -04:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public void SetValues(Func<int, object> getValue)
|
|
|
|
|
{
|
|
|
|
|
ModifyAndRecordForUndo(targetIndex =>
|
|
|
|
|
{
|
|
|
|
|
var value = getValue.Invoke(targetIndex);
|
|
|
|
|
SetValueRecursive(this, value, targetIndex);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-09 03:29:33 -04:00
|
|
|
|
public void ModifyAndRecordForUndo(Action<int> call)
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
2022-06-02 03:18:13 -04:00
|
|
|
|
PropertyTree.ApplyChanges();
|
2022-01-07 10:36:38 -05:00
|
|
|
|
|
2022-05-18 02:20:51 -04:00
|
|
|
|
PropertyTree.ForceCreateUndoGroup();
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-17 06:33:23 -04:00
|
|
|
|
for (var targetIndex = 0; targetIndex < PropertyTree.TargetsCount; targetIndex++)
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
2022-05-09 03:29:33 -04:00
|
|
|
|
call.Invoke(targetIndex);
|
2021-12-07 10:20:36 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-02 03:18:13 -04:00
|
|
|
|
PropertyTree.Update(forceUpdate: true);
|
2022-01-18 12:19:15 -05:00
|
|
|
|
|
2022-05-11 04:54:19 -04:00
|
|
|
|
NotifyValueChanged();
|
2022-06-02 03:18:13 -04:00
|
|
|
|
|
|
|
|
|
PropertyTree.RequestValidation();
|
|
|
|
|
PropertyTree.RequestRepaint();
|
2022-05-11 04:54:19 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void NotifyValueChanged()
|
|
|
|
|
{
|
2022-06-01 03:35:33 -04:00
|
|
|
|
NotifyValueChanged(this);
|
2022-05-11 04:54:19 -04:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-01 03:35:33 -04:00
|
|
|
|
private void NotifyValueChanged(TriProperty property)
|
2022-05-11 04:54:19 -04:00
|
|
|
|
{
|
2022-06-02 03:18:13 -04:00
|
|
|
|
if (property == this)
|
|
|
|
|
{
|
|
|
|
|
ValueChanged?.Invoke(property);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ChildValueChanged?.Invoke(property);
|
|
|
|
|
}
|
2022-06-01 03:35:33 -04:00
|
|
|
|
|
|
|
|
|
Parent?.NotifyValueChanged(property);
|
2021-12-07 10:20:36 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
private void UpdateIfRequired(bool forceUpdate = false)
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
2022-05-29 07:41:40 -04:00
|
|
|
|
if (_isUpdating)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("Recursive call detected");
|
|
|
|
|
}
|
2022-01-20 05:05:35 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
if (_lastUpdateFrame == PropertyTree.RepaintFrame && !forceUpdate)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
_isUpdating = true;
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
try
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
2022-05-29 07:41:40 -04:00
|
|
|
|
_lastUpdateFrame = PropertyTree.RepaintFrame;
|
2022-01-21 23:36:15 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
ReadValue(this, out var newValue, out var newValueIsMixed);
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
var newValueType = FieldType.IsValueType ? FieldType
|
|
|
|
|
: ReferenceEquals(_value, newValue) ? _valueType
|
|
|
|
|
: newValue?.GetType();
|
|
|
|
|
var valueTypeChanged = _valueType != newValueType;
|
|
|
|
|
|
|
|
|
|
_value = newValue;
|
|
|
|
|
_valueType = newValueType;
|
|
|
|
|
_isValueMixed = newValueIsMixed;
|
|
|
|
|
|
|
|
|
|
switch (PropertyType)
|
|
|
|
|
{
|
|
|
|
|
case TriPropertyType.Generic:
|
|
|
|
|
case TriPropertyType.Reference:
|
|
|
|
|
if (_childrenProperties == null || valueTypeChanged)
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
2022-05-29 07:41:40 -04:00
|
|
|
|
if (_childrenProperties == null)
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
2022-05-29 07:41:40 -04:00
|
|
|
|
_childrenProperties = new List<TriProperty>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_childrenProperties.Clear();
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
var selfType = PropertyType == TriPropertyType.Reference ? _valueType : FieldType;
|
|
|
|
|
if (selfType != null)
|
|
|
|
|
{
|
|
|
|
|
var properties = TriTypeDefinition.GetCached(selfType).Properties;
|
|
|
|
|
for (var index = 0; index < properties.Count; index++)
|
|
|
|
|
{
|
|
|
|
|
var childDefinition = properties[index];
|
2022-06-01 03:35:33 -04:00
|
|
|
|
var childSerializedProperty = _serializedProperty != null
|
|
|
|
|
? _serializedProperty.FindPropertyRelative(childDefinition.Name)
|
|
|
|
|
: _serializedObject?.FindProperty(childDefinition.Name);
|
2022-05-29 07:41:40 -04:00
|
|
|
|
var childProperty = new TriProperty(PropertyTree, this,
|
|
|
|
|
childDefinition, index, childSerializedProperty);
|
|
|
|
|
|
|
|
|
|
_childrenProperties.Add(childProperty);
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
break;
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
case TriPropertyType.Array:
|
|
|
|
|
if (_childrenProperties == null)
|
|
|
|
|
{
|
|
|
|
|
_childrenProperties = new List<TriProperty>();
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
var listSize = ((IList) newValue)?.Count ?? 0;
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
while (_childrenProperties.Count < listSize)
|
|
|
|
|
{
|
|
|
|
|
var index = _childrenProperties.Count;
|
|
|
|
|
var elementDefinition = _definition.ArrayElementDefinition;
|
|
|
|
|
var elementSerializedReference = _serializedProperty?.GetArrayElementAtIndex(index);
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
var elementProperty = new TriProperty(PropertyTree, this,
|
|
|
|
|
elementDefinition, index, elementSerializedReference);
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
_childrenProperties.Add(elementProperty);
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
while (_childrenProperties.Count > listSize)
|
|
|
|
|
{
|
|
|
|
|
_childrenProperties.RemoveAt(_childrenProperties.Count - 1);
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
|
2022-05-29 07:41:40 -04:00
|
|
|
|
break;
|
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
}
|
2022-05-29 07:41:40 -04:00
|
|
|
|
finally
|
2022-01-15 10:29:28 -05:00
|
|
|
|
{
|
2022-05-29 07:41:40 -04:00
|
|
|
|
_isUpdating = false;
|
2022-01-15 10:29:28 -05:00
|
|
|
|
}
|
2021-12-07 10:20:36 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-15 11:25:12 -05:00
|
|
|
|
internal void RunValidation()
|
|
|
|
|
{
|
2022-05-29 07:41:40 -04:00
|
|
|
|
UpdateIfRequired();
|
|
|
|
|
|
2022-01-15 11:25:12 -05:00
|
|
|
|
if (HasValidators)
|
|
|
|
|
{
|
|
|
|
|
_validationResults = _definition.Validators
|
|
|
|
|
.Select(it => it.Validate(this))
|
2022-01-18 12:19:15 -05:00
|
|
|
|
.Where(it => !it.IsValid)
|
2022-01-15 11:25:12 -05:00
|
|
|
|
.ToList();
|
|
|
|
|
}
|
2022-01-18 12:19:15 -05:00
|
|
|
|
|
2022-01-15 11:25:12 -05:00
|
|
|
|
if (_childrenProperties != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var childrenProperty in _childrenProperties)
|
|
|
|
|
{
|
|
|
|
|
childrenProperty.RunValidation();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-21 04:49:12 -04:00
|
|
|
|
internal void EnumerateValidationResults(Action<TriProperty, TriValidationResult> call)
|
|
|
|
|
{
|
2022-05-29 07:41:40 -04:00
|
|
|
|
UpdateIfRequired();
|
|
|
|
|
|
2022-05-21 04:49:12 -04:00
|
|
|
|
if (_validationResults != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var result in _validationResults)
|
|
|
|
|
{
|
|
|
|
|
call.Invoke(this, result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_childrenProperties != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var childrenProperty in _childrenProperties)
|
|
|
|
|
{
|
|
|
|
|
childrenProperty.EnumerateValidationResults(call);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 10:20:36 -05:00
|
|
|
|
[PublicAPI]
|
|
|
|
|
public bool TryGetSerializedProperty(out SerializedProperty serializedProperty)
|
|
|
|
|
{
|
|
|
|
|
serializedProperty = _serializedProperty;
|
|
|
|
|
return serializedProperty != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[PublicAPI]
|
|
|
|
|
public bool TryGetAttribute<TAttribute>(out TAttribute attribute)
|
|
|
|
|
where TAttribute : Attribute
|
|
|
|
|
{
|
|
|
|
|
if (ValueType != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var attr in TriReflectionUtilities.GetAttributesCached(ValueType))
|
|
|
|
|
{
|
|
|
|
|
if (attr is TAttribute typedAttr)
|
|
|
|
|
{
|
|
|
|
|
attribute = typedAttr;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var attr in _definition.Attributes)
|
|
|
|
|
{
|
|
|
|
|
if (attr is TAttribute typedAttr)
|
|
|
|
|
{
|
|
|
|
|
attribute = typedAttr;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attribute = null;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-06 06:33:19 -04:00
|
|
|
|
internal static void BuildPropertyPath(TriProperty property, StringBuilder sb)
|
|
|
|
|
{
|
|
|
|
|
if (property.IsRootProperty)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (property.Parent != null && !property.Parent.IsRootProperty)
|
|
|
|
|
{
|
|
|
|
|
BuildPropertyPath(property.Parent, sb);
|
|
|
|
|
sb.Append('.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (property.IsArrayElement)
|
|
|
|
|
{
|
|
|
|
|
sb.Append("Array.data[").Append(property.IndexInArray).Append(']');
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sb.Append(property.RawName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-07 10:36:38 -05:00
|
|
|
|
private static void SetValueRecursive(TriProperty property, object value, int targetIndex)
|
|
|
|
|
{
|
|
|
|
|
// for value types we must recursively set all parent objects
|
|
|
|
|
// because we cannot directly modify structs
|
|
|
|
|
// but we can re-set entire parent value
|
|
|
|
|
while (property._definition.SetValue(property, value, targetIndex, out var parentValue) &&
|
2022-10-31 08:07:46 -04:00
|
|
|
|
property.Parent != null)
|
2022-01-07 10:36:38 -05:00
|
|
|
|
{
|
2022-06-01 03:35:33 -04:00
|
|
|
|
property = property.Parent;
|
2022-01-07 10:36:38 -05:00
|
|
|
|
value = parentValue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-20 05:05:35 -05:00
|
|
|
|
private static void ReadValue(TriProperty property, out object newValue, out bool isMixed)
|
2022-01-10 03:10:07 -05:00
|
|
|
|
{
|
2022-01-20 05:05:35 -05:00
|
|
|
|
newValue = property.GetValue(0);
|
|
|
|
|
|
2022-05-17 06:33:23 -04:00
|
|
|
|
if (property.PropertyTree.TargetsCount == 1)
|
2022-01-10 03:10:07 -05:00
|
|
|
|
{
|
2022-01-20 05:05:35 -05:00
|
|
|
|
isMixed = false;
|
|
|
|
|
return;
|
2022-01-10 03:10:07 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (property.PropertyType)
|
|
|
|
|
{
|
|
|
|
|
case TriPropertyType.Array:
|
|
|
|
|
{
|
2022-01-20 05:05:35 -05:00
|
|
|
|
var list = (IList) newValue;
|
2022-05-17 06:33:23 -04:00
|
|
|
|
for (var i = 1; i < property.PropertyTree.TargetsCount; i++)
|
2022-01-20 05:05:35 -05:00
|
|
|
|
{
|
|
|
|
|
if (list == null)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var otherList = (IList) property.GetValue(i);
|
|
|
|
|
if (otherList == null || otherList.Count < list.Count)
|
|
|
|
|
{
|
|
|
|
|
newValue = list = otherList;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isMixed = true;
|
|
|
|
|
return;
|
2022-01-10 03:10:07 -05:00
|
|
|
|
}
|
|
|
|
|
case TriPropertyType.Reference:
|
|
|
|
|
{
|
2022-05-17 06:33:23 -04:00
|
|
|
|
for (var i = 1; i < property.PropertyTree.TargetsCount; i++)
|
2022-01-10 03:10:07 -05:00
|
|
|
|
{
|
2022-01-20 05:05:35 -05:00
|
|
|
|
var otherValue = property.GetValue(i);
|
2022-01-10 03:10:07 -05:00
|
|
|
|
|
2022-01-20 05:05:35 -05:00
|
|
|
|
if (newValue?.GetType() != otherValue?.GetType())
|
2022-01-10 03:10:07 -05:00
|
|
|
|
{
|
2022-01-20 05:05:35 -05:00
|
|
|
|
isMixed = true;
|
|
|
|
|
newValue = null;
|
|
|
|
|
return;
|
2022-01-10 03:10:07 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-20 05:05:35 -05:00
|
|
|
|
isMixed = false;
|
|
|
|
|
return;
|
2022-01-10 03:10:07 -05:00
|
|
|
|
}
|
|
|
|
|
case TriPropertyType.Generic:
|
|
|
|
|
{
|
2022-01-20 05:05:35 -05:00
|
|
|
|
isMixed = false;
|
|
|
|
|
return;
|
2022-01-10 03:10:07 -05:00
|
|
|
|
}
|
|
|
|
|
case TriPropertyType.Primitive:
|
|
|
|
|
{
|
2022-05-17 06:33:23 -04:00
|
|
|
|
for (var i = 1; i < property.PropertyTree.TargetsCount; i++)
|
2022-01-10 03:10:07 -05:00
|
|
|
|
{
|
2022-01-20 05:05:35 -05:00
|
|
|
|
var otherValue = property.GetValue(i);
|
2022-07-12 06:09:21 -04:00
|
|
|
|
if (!property.Comparer.Equals(otherValue, newValue))
|
2022-01-10 03:10:07 -05:00
|
|
|
|
{
|
2022-01-20 05:05:35 -05:00
|
|
|
|
isMixed = true;
|
|
|
|
|
return;
|
2022-01-10 03:10:07 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-20 05:05:35 -05:00
|
|
|
|
isMixed = false;
|
|
|
|
|
return;
|
2022-01-10 03:10:07 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
{
|
2022-01-20 05:05:35 -05:00
|
|
|
|
Debug.LogError($"Unexpected property type: {property.PropertyType}");
|
|
|
|
|
isMixed = true;
|
|
|
|
|
return;
|
2022-01-10 03:10:07 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 10:20:36 -05:00
|
|
|
|
private static TriPropertyType GetPropertyType(TriProperty property)
|
|
|
|
|
{
|
|
|
|
|
if (property._serializedProperty != null)
|
|
|
|
|
{
|
|
|
|
|
if (property._serializedProperty.isArray &&
|
|
|
|
|
property._serializedProperty.propertyType != SerializedPropertyType.String)
|
|
|
|
|
{
|
|
|
|
|
return TriPropertyType.Array;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (property._serializedProperty.propertyType == SerializedPropertyType.ManagedReference)
|
|
|
|
|
{
|
|
|
|
|
return TriPropertyType.Reference;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (property._serializedProperty.propertyType == SerializedPropertyType.Generic)
|
|
|
|
|
{
|
|
|
|
|
return TriPropertyType.Generic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TriPropertyType.Primitive;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-01 03:35:33 -04:00
|
|
|
|
if (property._serializedObject != null)
|
|
|
|
|
{
|
|
|
|
|
return TriPropertyType.Generic;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 10:20:36 -05:00
|
|
|
|
if (property._definition.FieldType.IsPrimitive ||
|
2022-05-25 04:07:43 -04:00
|
|
|
|
property._definition.FieldType == typeof(string) ||
|
|
|
|
|
typeof(UnityEngine.Object).IsAssignableFrom(property._definition.FieldType))
|
2021-12-07 10:20:36 -05:00
|
|
|
|
{
|
|
|
|
|
return TriPropertyType.Primitive;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (property._definition.FieldType.IsValueType)
|
|
|
|
|
{
|
|
|
|
|
return TriPropertyType.Generic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (property._definition.IsArray)
|
|
|
|
|
{
|
|
|
|
|
return TriPropertyType.Array;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TriPropertyType.Reference;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum TriPropertyType
|
|
|
|
|
{
|
|
|
|
|
Array,
|
|
|
|
|
Reference,
|
|
|
|
|
Generic,
|
|
|
|
|
Primitive,
|
|
|
|
|
}
|
|
|
|
|
}
|