Tri-Inspector/Editor/TriPropertyDefinition.cs

363 lines
13 KiB
C#
Raw Normal View History

2021-12-07 10:20:36 -05:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
2022-05-11 07:15:12 -04:00
using TriInspector.Resolvers;
2021-12-07 10:20:36 -05:00
using TriInspector.Utilities;
using UnityEngine;
namespace TriInspector
{
2022-01-28 12:13:11 -05:00
public class TriPropertyDefinition
2021-12-07 10:20:36 -05:00
{
2022-06-01 03:35:33 -04:00
private readonly ValueGetterDelegate _valueGetter;
[CanBeNull] private readonly ValueSetterDelegate _valueSetter;
2022-01-06 10:43:09 -05:00
private readonly List<string> _extensionErrors = new List<string>();
2022-08-17 13:46:26 -04:00
private readonly MemberInfo _memberInfo;
private readonly List<Attribute> _attributes;
2023-06-21 13:48:08 -04:00
private readonly bool _skipNullValuesFix;
2022-01-06 10:43:09 -05:00
private TriPropertyDefinition _arrayElementDefinitionBackingField;
2021-12-07 10:20:36 -05:00
private IReadOnlyList<TriCustomDrawer> _drawersBackingField;
2022-01-15 11:25:12 -05:00
private IReadOnlyList<TriValidator> _validatorsBackingField;
private IReadOnlyList<TriPropertyHideProcessor> _hideProcessorsBackingField;
private IReadOnlyList<TriPropertyDisableProcessor> _disableProcessorsBackingField;
2021-12-07 10:20:36 -05:00
2022-08-17 13:46:26 -04:00
public static TriPropertyDefinition CreateForFieldInfo(int order, FieldInfo fi)
2021-12-07 10:20:36 -05:00
{
2022-08-17 13:46:26 -04:00
return CreateForMemberInfo(fi, order, fi.Name, fi.FieldType, MakeGetter(fi), MakeSetter(fi));
2021-12-07 10:20:36 -05:00
}
2022-08-17 13:46:26 -04:00
public static TriPropertyDefinition CreateForPropertyInfo(int order, PropertyInfo pi)
2022-01-18 12:41:11 -05:00
{
2022-08-17 13:46:26 -04:00
return CreateForMemberInfo(pi, order, pi.Name, pi.PropertyType, MakeGetter(pi), MakeSetter(pi));
2022-01-18 12:41:11 -05:00
}
2022-08-17 13:46:26 -04:00
public static TriPropertyDefinition CreateForMethodInfo(int order, MethodInfo mi)
2021-12-07 10:20:36 -05:00
{
2022-08-17 13:46:26 -04:00
return CreateForMemberInfo(mi, order, mi.Name, typeof(MethodInfo), MakeGetter(mi), MakeSetter(mi));
}
private static TriPropertyDefinition CreateForMemberInfo(
MemberInfo memberInfo, int order, string propertyName, Type propertyType,
ValueGetterDelegate valueGetter, ValueSetterDelegate valueSetter)
{
var attributes = memberInfo?.GetCustomAttributes().ToList();
var ownerType = memberInfo?.DeclaringType ?? typeof(object);
return new TriPropertyDefinition(
memberInfo, ownerType, order, propertyName, propertyType, valueGetter, valueSetter, attributes, false);
2021-12-07 10:20:36 -05:00
}
2023-06-21 13:48:08 -04:00
internal static TriPropertyDefinition CreateForGetterSetter(
int order, string name, Type fieldType,
ValueGetterDelegate valueGetter, ValueSetterDelegate valueSetter)
{
return new TriPropertyDefinition(
null, null, order, name, fieldType, valueGetter, valueSetter, null, false);
}
2022-06-01 03:35:33 -04:00
internal TriPropertyDefinition(
2022-01-18 12:41:11 -05:00
MemberInfo memberInfo,
2022-08-17 13:46:26 -04:00
Type ownerType,
2021-12-07 10:20:36 -05:00
int order,
string fieldName,
Type fieldType,
2022-06-01 03:35:33 -04:00
ValueGetterDelegate valueGetter,
ValueSetterDelegate valueSetter,
2022-08-17 13:46:26 -04:00
List<Attribute> attributes,
2021-12-07 10:20:36 -05:00
bool isArrayElement)
{
2022-08-17 13:46:26 -04:00
OwnerType = ownerType;
2021-12-07 10:20:36 -05:00
Name = fieldName;
FieldType = fieldType;
IsArrayElement = isArrayElement;
2022-08-17 13:46:26 -04:00
_attributes = attributes ?? new List<Attribute>();
_memberInfo = memberInfo;
2021-12-07 10:20:36 -05:00
_valueGetter = valueGetter;
_valueSetter = valueSetter;
2023-06-21 13:48:08 -04:00
_skipNullValuesFix = memberInfo != null && memberInfo.GetCustomAttribute<SerializeReference>() != null;
2022-08-17 13:46:26 -04:00
Order = order;
2021-12-07 10:20:36 -05:00
IsReadOnly = _valueSetter == null || Attributes.TryGet(out ReadOnlyAttribute _);
if (TriReflectionUtilities.IsArrayOrList(FieldType, out var elementType))
{
IsArray = true;
ArrayElementType = elementType;
}
2022-05-11 07:15:12 -04:00
if (Attributes.TryGet(out LabelTextAttribute labelTextAttribute))
{
CustomLabel = ValueResolver.ResolveString(this, labelTextAttribute.Text);
}
if (Attributes.TryGet(out PropertyTooltipAttribute tooltipAttribute))
{
CustomTooltip = ValueResolver.ResolveString(this, tooltipAttribute.Tooltip);
}
else if (Attributes.TryGet(out TooltipAttribute unityTooltipAttribute))
{
CustomTooltip = new ConstantValueResolver<string>(unityTooltipAttribute.tooltip);
}
2021-12-07 10:20:36 -05:00
}
2022-08-17 13:46:26 -04:00
public Type OwnerType { get; }
2022-01-18 12:41:11 -05:00
2021-12-07 10:20:36 -05:00
public Type FieldType { get; }
public string Name { get; }
2022-08-17 13:46:26 -04:00
public int Order { get; internal set; }
2021-12-07 10:20:36 -05:00
2022-08-17 13:46:26 -04:00
public IReadOnlyList<Attribute> Attributes => _attributes;
2021-12-07 10:20:36 -05:00
public bool IsReadOnly { get; }
public bool IsArrayElement { get; }
public Type ArrayElementType { get; }
public bool IsArray { get; }
[CanBeNull] public ValueResolver<string> CustomLabel { get; }
[CanBeNull] public ValueResolver<string> CustomTooltip { get; }
2022-05-11 07:15:12 -04:00
public IReadOnlyList<TriPropertyHideProcessor> HideProcessors => PopulateHideProcessor();
public IReadOnlyList<TriPropertyDisableProcessor> DisableProcessors => PopulateDisableProcessors();
public IReadOnlyList<TriCustomDrawer> Drawers => PopulateDrawers();
public IReadOnlyList<TriValidator> Validators => PopulateValidators();
internal IReadOnlyList<string> ExtensionErrors
{
get
{
PopulateHideProcessor();
PopulateDisableProcessors();
PopulateDrawers();
PopulateValidators();
return _extensionErrors;
2022-01-15 11:25:12 -05:00
}
}
2022-08-17 13:46:26 -04:00
public List<Attribute> GetEditableAttributes()
{
return _attributes;
}
public bool TryGetMemberInfo(out MemberInfo memberInfo)
{
memberInfo = _memberInfo;
return memberInfo != null;
}
2022-01-06 10:43:09 -05:00
public object GetValue(TriProperty property, int targetIndex)
2021-12-07 10:20:36 -05:00
{
var value = _valueGetter(property, targetIndex);
2023-06-21 13:48:08 -04:00
if (value == null && !_skipNullValuesFix)
{
value = TriUnitySerializationUtilities.PopulateUnityDefaultValueForType(FieldType);
if (value != null)
{
_valueSetter?.Invoke(property, targetIndex, value);
}
}
return value;
2021-12-07 10:20:36 -05:00
}
2022-01-07 10:36:38 -05:00
public bool SetValue(TriProperty property, object value, int targetIndex, out object parentValue)
2021-12-07 10:20:36 -05:00
{
if (IsReadOnly)
{
Debug.LogError("Cannot set value for readonly property");
2022-01-07 10:36:38 -05:00
parentValue = default;
return false;
2021-12-07 10:20:36 -05:00
}
2022-06-01 03:35:33 -04:00
parentValue = _valueSetter?.Invoke(property, targetIndex, value);
2022-01-07 10:36:38 -05:00
return true;
2021-12-07 10:20:36 -05:00
}
2022-01-06 10:43:09 -05:00
public TriPropertyDefinition ArrayElementDefinition
2021-12-07 10:20:36 -05:00
{
2022-01-06 10:43:09 -05:00
get
2021-12-07 10:20:36 -05:00
{
2022-01-06 10:43:09 -05:00
if (_arrayElementDefinitionBackingField == null)
{
if (!IsArray)
{
throw new InvalidOperationException(
$"Cannot get array element definition for non array property: {FieldType}");
}
2021-12-07 10:20:36 -05:00
2022-06-01 03:35:33 -04:00
var elementGetter = new ValueGetterDelegate((self, targetIndex) =>
2022-01-06 10:43:09 -05:00
{
2022-06-01 03:35:33 -04:00
var parentValue = (IList) self.Parent.GetValue(targetIndex);
return parentValue[self.IndexInArray];
2022-01-06 10:43:09 -05:00
});
2022-06-01 03:35:33 -04:00
var elementSetter = new ValueSetterDelegate((self, targetIndex, value) =>
2022-01-06 10:43:09 -05:00
{
2022-06-01 03:35:33 -04:00
var parentValue = (IList) self.Parent.GetValue(targetIndex);
parentValue[self.IndexInArray] = value;
return parentValue;
2022-01-06 10:43:09 -05:00
});
2021-12-07 10:20:36 -05:00
2022-08-17 13:46:26 -04:00
_arrayElementDefinitionBackingField = new TriPropertyDefinition(_memberInfo, OwnerType, 0,
"Element", ArrayElementType, elementGetter, elementSetter, _attributes, true);
2022-01-06 10:43:09 -05:00
}
2021-12-07 10:20:36 -05:00
2022-01-06 10:43:09 -05:00
return _arrayElementDefinitionBackingField;
}
2021-12-07 10:20:36 -05:00
}
private IReadOnlyList<TriPropertyHideProcessor> PopulateHideProcessor()
{
2022-06-06 08:08:45 -04:00
if (_hideProcessorsBackingField != null)
{
return _hideProcessorsBackingField;
}
return _hideProcessorsBackingField = TriDrawersUtilities
.CreateHideProcessorsFor(FieldType, Attributes)
.Where(CanApplyExtensionOnSelf)
.ToList();
}
private IReadOnlyList<TriPropertyDisableProcessor> PopulateDisableProcessors()
{
2022-06-06 08:08:45 -04:00
if (_disableProcessorsBackingField != null)
{
return _disableProcessorsBackingField;
}
return _disableProcessorsBackingField = TriDrawersUtilities
.CreateDisableProcessorsFor(FieldType, Attributes)
.Where(CanApplyExtensionOnSelf)
.ToList();
}
private IReadOnlyList<TriValidator> PopulateValidators()
{
2022-06-06 08:08:45 -04:00
if (_validatorsBackingField != null)
{
return _validatorsBackingField;
}
return _validatorsBackingField = Enumerable.Empty<TriValidator>()
.Concat(TriDrawersUtilities.CreateValueValidatorsFor(FieldType))
.Concat(TriDrawersUtilities.CreateAttributeValidatorsFor(FieldType, Attributes))
.Where(CanApplyExtensionOnSelf)
.ToList();
}
private IReadOnlyList<TriCustomDrawer> PopulateDrawers()
{
2022-06-06 08:08:45 -04:00
if (_drawersBackingField != null)
{
return _drawersBackingField;
}
return _drawersBackingField = Enumerable.Empty<TriCustomDrawer>()
.Concat(TriDrawersUtilities.CreateValueDrawersFor(FieldType))
.Concat(TriDrawersUtilities.CreateAttributeDrawersFor(FieldType, Attributes))
.Concat(new[]
{
new ValidatorsDrawer {Order = TriDrawerOrder.Validator,},
})
.Where(CanApplyExtensionOnSelf)
.OrderBy(it => it.Order)
.ToList();
}
2022-06-01 03:35:33 -04:00
private static ValueGetterDelegate MakeGetter(FieldInfo fi)
2022-01-06 10:43:09 -05:00
{
2022-06-01 03:35:33 -04:00
return (self, targetIndex) =>
{
var parentValue = self.Parent.GetValue(targetIndex);
return fi.GetValue(parentValue);
};
2022-01-06 10:43:09 -05:00
}
2022-06-01 03:35:33 -04:00
private static ValueSetterDelegate MakeSetter(FieldInfo fi)
2022-01-06 10:43:09 -05:00
{
2022-06-01 03:35:33 -04:00
return (self, targetIndex, value) =>
{
var parentValue = self.Parent.GetValue(targetIndex);
fi.SetValue(parentValue, value);
return parentValue;
};
2022-01-06 10:43:09 -05:00
}
2022-01-06 12:11:27 -05:00
2022-06-01 03:35:33 -04:00
private static ValueGetterDelegate MakeGetter(PropertyInfo pi)
2021-12-07 10:20:36 -05:00
{
var method = pi.GetMethod;
2022-06-01 03:35:33 -04:00
return (self, targetIndex) =>
{
var parentValue = self.Parent.GetValue(targetIndex);
return method.Invoke(parentValue, null);
};
2021-12-07 10:20:36 -05:00
}
2022-06-01 03:35:33 -04:00
private static ValueSetterDelegate MakeSetter(PropertyInfo pi)
2021-12-07 10:20:36 -05:00
{
var method = pi.SetMethod;
if (method == null)
{
return null;
}
2022-06-01 03:35:33 -04:00
return (self, targetIndex, value) =>
{
var parentValue = self.Parent.GetValue(targetIndex);
method.Invoke(parentValue, new[] {value,});
return parentValue;
};
2021-12-07 10:20:36 -05:00
}
2022-01-18 12:41:11 -05:00
2022-06-01 03:35:33 -04:00
private static ValueGetterDelegate MakeGetter(MethodInfo mi)
2022-01-18 12:41:11 -05:00
{
2022-06-01 03:35:33 -04:00
return (self, targetIndex) => mi;
2022-01-18 12:41:11 -05:00
}
2022-06-01 03:35:33 -04:00
private static ValueSetterDelegate MakeSetter(MethodInfo mi)
2022-01-18 12:41:11 -05:00
{
2022-06-01 03:35:33 -04:00
return (self, targetIndex, value) =>
{
var parentValue = self.Parent.GetValue(targetIndex);
return parentValue;
};
2022-01-18 12:41:11 -05:00
}
2022-05-07 12:31:14 -04:00
2022-06-03 08:16:23 -04:00
private bool CanApplyExtensionOnSelf(TriPropertyExtension propertyExtension)
2022-05-07 12:31:14 -04:00
{
2022-06-03 08:16:23 -04:00
if (propertyExtension.ApplyOnArrayElement.HasValue)
2022-05-21 04:17:47 -04:00
{
2022-06-03 08:16:23 -04:00
if (IsArrayElement && !propertyExtension.ApplyOnArrayElement.Value ||
IsArray && propertyExtension.ApplyOnArrayElement.Value)
{
return false;
}
2022-05-21 04:17:47 -04:00
}
var result = propertyExtension.Initialize(this);
if (result.IsError)
2022-05-07 12:31:14 -04:00
{
_extensionErrors.Add(result.ErrorMessage);
2022-05-07 12:31:14 -04:00
}
return result.ShouldApply;
2022-05-07 12:31:14 -04:00
}
2022-06-01 03:35:33 -04:00
public delegate object ValueGetterDelegate(TriProperty self, int targetIndex);
2022-06-01 03:35:33 -04:00
public delegate object ValueSetterDelegate(TriProperty self, int targetIndex, object value);
2021-12-07 10:20:36 -05:00
}
}