Tri-Inspector/Editor/TriPropertyDefinition.cs

199 lines
6.6 KiB
C#
Raw Normal View History

2021-12-07 18:20:36 +03:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using TriInspector.Utilities;
using UnityEngine;
namespace TriInspector
{
internal class TriPropertyDefinition
{
2022-01-06 18:43:09 +03:00
private readonly Func<TriProperty, object, object> _valueGetter;
[CanBeNull] private readonly Action<TriProperty, object, object> _valueSetter;
private TriPropertyDefinition _arrayElementDefinitionBackingField;
2021-12-07 18:20:36 +03:00
private IReadOnlyList<TriCustomDrawer> _drawersBackingField;
private IReadOnlyList<TriPropertyHideProcessor> _hideProcessorsBackingField;
private IReadOnlyList<TriPropertyDisableProcessor> _disableProcessorsBackingField;
2021-12-07 18:20:36 +03:00
internal TriPropertyDefinition(int order, FieldInfo fi)
2022-01-06 18:43:09 +03:00
: this(order, fi.Name, fi.FieldType, MakeGetter(fi), MakeSetter(fi), fi.GetCustomAttributes(), false)
2021-12-07 18:20:36 +03:00
{
}
internal TriPropertyDefinition(int order, PropertyInfo pi)
: this(order, pi.Name, pi.PropertyType, MakeGetter(pi), MakeSetter(pi), pi.GetCustomAttributes(), false)
{
}
private TriPropertyDefinition(
int order,
string fieldName,
Type fieldType,
2022-01-06 18:43:09 +03:00
Func<TriProperty, object, object> valueGetter,
Action<TriProperty, object, object> valueSetter,
2021-12-07 18:20:36 +03:00
IEnumerable<Attribute> fieldAttributes,
bool isArrayElement)
{
Name = fieldName;
FieldType = fieldType;
IsArrayElement = isArrayElement;
_valueGetter = valueGetter;
_valueSetter = valueSetter;
Attributes = fieldAttributes.ToList();
Order = Attributes.TryGet(out PropertyOrderAttribute orderAttribute) ? orderAttribute.Order : order;
IsReadOnly = _valueSetter == null || Attributes.TryGet(out ReadOnlyAttribute _);
if (TriReflectionUtilities.IsArrayOrList(FieldType, out var elementType))
{
IsArray = true;
ArrayElementType = elementType;
}
}
public Type FieldType { get; }
public string Name { get; }
public int Order { get; }
public IReadOnlyList<Attribute> Attributes { get; }
public bool IsReadOnly { get; }
public bool IsArrayElement { get; }
public Type ArrayElementType { get; }
public bool IsArray { get; }
public IReadOnlyList<TriPropertyHideProcessor> HideProcessors
{
get
{
if (_hideProcessorsBackingField == null)
{
_hideProcessorsBackingField =
TriDrawersUtilities.CreateHideProcessorsFor(Attributes).ToList();
}
return _hideProcessorsBackingField;
}
}
public IReadOnlyList<TriPropertyDisableProcessor> DisableProcessors
{
get
{
if (_disableProcessorsBackingField == null)
{
_disableProcessorsBackingField =
TriDrawersUtilities.CreateDisableProcessorsFor(Attributes).ToList();
}
return _disableProcessorsBackingField;
}
}
2021-12-07 18:20:36 +03:00
public IReadOnlyList<TriCustomDrawer> Drawers
{
get
{
if (_drawersBackingField == null)
{
_drawersBackingField = Enumerable.Empty<TriCustomDrawer>()
.Concat(TriDrawersUtilities.CreateValueDrawersFor(FieldType))
.Concat(TriDrawersUtilities.CreateAttributeDrawersFor(Attributes))
2021-12-07 18:20:36 +03:00
.OrderBy(it => it.Order)
.ToList();
}
return _drawersBackingField;
}
}
2022-01-06 18:43:09 +03:00
public object GetValue(TriProperty property, int targetIndex)
2021-12-07 18:20:36 +03:00
{
2022-01-06 18:43:09 +03:00
var parentValue = property.Parent.GetValue(targetIndex);
return _valueGetter(property, parentValue);
2021-12-07 18:20:36 +03:00
}
2022-01-07 18:36:38 +03:00
public bool SetValue(TriProperty property, object value, int targetIndex, out object parentValue)
2021-12-07 18:20:36 +03:00
{
if (IsReadOnly)
{
Debug.LogError("Cannot set value for readonly property");
2022-01-07 18:36:38 +03:00
parentValue = default;
return false;
2021-12-07 18:20:36 +03:00
}
2022-01-07 18:36:38 +03:00
parentValue = property.Parent.GetValue(targetIndex);
2022-01-06 18:43:09 +03:00
_valueSetter?.Invoke(property, parentValue, value);
2022-01-07 18:36:38 +03:00
return true;
2021-12-07 18:20:36 +03:00
}
2022-01-06 18:43:09 +03:00
public TriPropertyDefinition ArrayElementDefinition
2021-12-07 18:20:36 +03:00
{
2022-01-06 18:43:09 +03:00
get
2021-12-07 18:20:36 +03:00
{
2022-01-06 18:43:09 +03:00
if (_arrayElementDefinitionBackingField == null)
{
if (!IsArray)
{
throw new InvalidOperationException(
$"Cannot get array element definition for non array property: {FieldType}");
}
2021-12-07 18:20:36 +03:00
2022-01-06 18:43:09 +03:00
var elementGetter = new Func<TriProperty, object, object>((self, obj) =>
{
var list = (IList) obj;
return list[self.IndexInArray];
});
var elementSetter = new Action<TriProperty, object, object>((self, obj, value) =>
{
var list = (IList) obj;
list[self.IndexInArray] = value;
});
var elementAttributes = Attributes;
2021-12-07 18:20:36 +03:00
2022-01-06 18:43:09 +03:00
_arrayElementDefinitionBackingField = new TriPropertyDefinition(0, "Element", ArrayElementType,
elementGetter, elementSetter, elementAttributes, true);
}
2021-12-07 18:20:36 +03:00
2022-01-06 18:43:09 +03:00
return _arrayElementDefinitionBackingField;
}
2021-12-07 18:20:36 +03:00
}
2022-01-06 18:43:09 +03:00
private static Func<TriProperty, object, object> MakeGetter(FieldInfo fi)
{
return (self, obj) => fi.GetValue(obj);
}
private static Action<TriProperty, object, object> MakeSetter(FieldInfo fi)
{
return (self, obj, value) => fi.SetValue(obj, value);
}
2022-01-06 20:11:27 +03:00
2022-01-06 18:43:09 +03:00
private static Func<TriProperty, object, object> MakeGetter(PropertyInfo pi)
2021-12-07 18:20:36 +03:00
{
var method = pi.GetMethod;
2022-01-06 18:43:09 +03:00
return (self, obj) => method.Invoke(obj, null);
2021-12-07 18:20:36 +03:00
}
2022-01-06 18:43:09 +03:00
private static Action<TriProperty, object, object> MakeSetter(PropertyInfo pi)
2021-12-07 18:20:36 +03:00
{
var method = pi.SetMethod;
if (method == null)
{
return null;
}
2022-01-06 18:43:09 +03:00
return (self, obj, value) => method.Invoke(obj, new[] {value,});
2021-12-07 18:20:36 +03:00
}
}
}