245 lines
10 KiB
C#
245 lines
10 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using UnityEngine;
|
|
|
|
namespace Module.Inspector.Editor.Utilities
|
|
{
|
|
public static class EditorPropertyUtility
|
|
{
|
|
private static Dictionary<FieldInfo, Result> CACHED_RESULTS;
|
|
private static Dictionary<Type, Type> CACHED_ATT_TO_DRAWER;
|
|
|
|
private static void InitializeCache()
|
|
{
|
|
if (CACHED_ATT_TO_DRAWER != null)
|
|
return;
|
|
|
|
CACHED_ATT_TO_DRAWER = new Dictionary<Type, Type>();
|
|
|
|
Type baseDrawerType = typeof(AbstractPropertyDrawer);
|
|
var assembly = Assembly.GetAssembly(baseDrawerType);
|
|
Type[] types = assembly.GetTypes();
|
|
|
|
for (var i = 0; i < types.Length; i++)
|
|
{
|
|
Type type = types[i];
|
|
|
|
if (type.IsAbstract || !baseDrawerType.IsAssignableFrom(type))
|
|
continue;
|
|
|
|
IList<CustomAttributeData> attributes = type.GetCustomAttributesData();
|
|
|
|
for (var j = 0; j < attributes.Count; j++)
|
|
{
|
|
CustomAttributeData attData = attributes[j];
|
|
IList<CustomAttributeTypedArgument> arguments = attData.ConstructorArguments;
|
|
|
|
for (var k = 0; k < arguments.Count; k++)
|
|
{
|
|
if (!(arguments[k].Value is Type argType))
|
|
continue;
|
|
|
|
if (CACHED_ATT_TO_DRAWER.ContainsKey(argType))
|
|
Debug.LogWarningFormat("Already contained {0}, but tried to add with {1} and already had {2}.", argType, type, CACHED_ATT_TO_DRAWER[argType]);
|
|
else
|
|
CACHED_ATT_TO_DRAWER.Add(argType, type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Result Query(FieldInfo fieldInfo)
|
|
{
|
|
InitializeCache();
|
|
|
|
if (CACHED_RESULTS == null)
|
|
CACHED_RESULTS = new Dictionary<FieldInfo, Result>();
|
|
|
|
if (CACHED_RESULTS.TryGetValue(fieldInfo, out Result result))
|
|
return result;
|
|
|
|
result = InternalFetchProperties(fieldInfo);
|
|
CACHED_RESULTS.Add(fieldInfo, result);
|
|
return result;
|
|
}
|
|
|
|
private static Result InternalFetchProperties(FieldInfo fieldInfo)
|
|
{
|
|
ResultValue<DrawerPropertyAttribute, DrawerPropertyDrawer> drawer = null;
|
|
var typeDrawer = InternalCreateInstanceOf<DrawerPropertyDrawer>(fieldInfo);
|
|
|
|
if (typeDrawer != null)
|
|
drawer = new ResultValue<DrawerPropertyAttribute, DrawerPropertyDrawer>(null, typeDrawer);
|
|
|
|
var predrawerModifiers = new List<ResultValue<PredrawerModifierPropertyAttribute, PredrawerModifierPropertyDrawer>>(2);
|
|
var valueModifiers = new List<ResultValue<ValueModifierPropertyAttribute, ValueModifierPropertyDrawer>>(2);
|
|
var accessModifiers = new List<ResultValue<AccessModifierPropertyAttribute, AccessModifierPropertyDrawer>>(2);
|
|
object[] attributes = fieldInfo.GetCustomAttributes(false);
|
|
string tooltip = null;
|
|
var isObsolete = false;
|
|
string obsoleteText = null;
|
|
|
|
for (var i = 0; i < attributes.Length; i++)
|
|
{
|
|
object att = attributes[i];
|
|
|
|
if (att is DrawerPropertyAttribute attDrawer)
|
|
{
|
|
if (drawer != null)
|
|
continue;
|
|
|
|
var prop = InternalCreateInstanceOf<DrawerPropertyDrawer>(attDrawer);
|
|
|
|
if (prop != null)
|
|
drawer = new ResultValue<DrawerPropertyAttribute, DrawerPropertyDrawer>(attDrawer, prop);
|
|
}
|
|
else if (att is PredrawerModifierPropertyAttribute predawerModifier)
|
|
{
|
|
var prop = InternalCreateInstanceOf<PredrawerModifierPropertyDrawer>(predawerModifier);
|
|
|
|
if (prop != null)
|
|
predrawerModifiers.Add(new ResultValue<PredrawerModifierPropertyAttribute, PredrawerModifierPropertyDrawer>(predawerModifier, prop));
|
|
}
|
|
else if (att is ValueModifierPropertyAttribute valueModifier)
|
|
{
|
|
var prop = InternalCreateInstanceOf<ValueModifierPropertyDrawer>(valueModifier);
|
|
|
|
if (prop != null)
|
|
valueModifiers.Add(new ResultValue<ValueModifierPropertyAttribute, ValueModifierPropertyDrawer>(valueModifier, prop));
|
|
}
|
|
else if (att is AccessModifierPropertyAttribute accessModifier)
|
|
{
|
|
var prop = InternalCreateInstanceOf<AccessModifierPropertyDrawer>(accessModifier);
|
|
|
|
if (prop != null)
|
|
accessModifiers.Add(new ResultValue<AccessModifierPropertyAttribute, AccessModifierPropertyDrawer>(accessModifier, prop));
|
|
}
|
|
else if (att is TooltipAttribute attTooltip)
|
|
{
|
|
tooltip = attTooltip.tooltip;
|
|
}
|
|
else if (att is ObsoleteAttribute attObsolete)
|
|
{
|
|
isObsolete = true;
|
|
obsoleteText = attObsolete.Message;
|
|
}
|
|
}
|
|
|
|
if (isObsolete)
|
|
{
|
|
if (string.IsNullOrEmpty(obsoleteText))
|
|
{
|
|
if (tooltip != null)
|
|
tooltip += $"\n[Obsolete]";
|
|
else
|
|
tooltip = $"[Obsolete]";
|
|
}
|
|
else
|
|
{
|
|
if (tooltip != null)
|
|
tooltip += $"\n[Obsolete: {obsoleteText}]";
|
|
else
|
|
tooltip = $"[Obsolete: {obsoleteText}]";
|
|
}
|
|
}
|
|
|
|
return new Result(drawer, predrawerModifiers, valueModifiers, accessModifiers, tooltip, isObsolete);
|
|
}
|
|
|
|
private static T InternalCreateInstanceOf<T>(AbstractPropertyAttribute att) where T : AbstractPropertyDrawer
|
|
{
|
|
if (CACHED_ATT_TO_DRAWER.TryGetValue(att.GetType(), out Type drawerType))
|
|
return Activator.CreateInstance(drawerType) as T;
|
|
|
|
return null;
|
|
}
|
|
|
|
private static T InternalCreateInstanceOf<T>(FieldInfo fieldInfo) where T : AbstractPropertyDrawer
|
|
{
|
|
if (CACHED_ATT_TO_DRAWER.TryGetValue(fieldInfo.FieldType, out Type drawerType))
|
|
return Activator.CreateInstance(drawerType) as T;
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class: Result from property query
|
|
/// </summary>
|
|
public sealed class Result
|
|
{
|
|
public readonly ResultValue<DrawerPropertyAttribute, DrawerPropertyDrawer> draw;
|
|
public readonly List<ResultValue<PredrawerModifierPropertyAttribute, PredrawerModifierPropertyDrawer>> predrawerModifiers;
|
|
public readonly List<ResultValue<ValueModifierPropertyAttribute, ValueModifierPropertyDrawer>> valueModifiers;
|
|
public readonly List<ResultValue<AccessModifierPropertyAttribute, AccessModifierPropertyDrawer>> accessModifiers;
|
|
public readonly string tooltip;
|
|
public readonly bool isObsolete;
|
|
|
|
public Result(ResultValue<DrawerPropertyAttribute, DrawerPropertyDrawer> draw,
|
|
List<ResultValue<PredrawerModifierPropertyAttribute, PredrawerModifierPropertyDrawer>> predrawerModifiers,
|
|
List<ResultValue<ValueModifierPropertyAttribute, ValueModifierPropertyDrawer>> valueModifiers,
|
|
List<ResultValue<AccessModifierPropertyAttribute, AccessModifierPropertyDrawer>> accessModifiers,
|
|
string tooltip,
|
|
bool isObsolete)
|
|
{
|
|
this.draw = draw;
|
|
this.predrawerModifiers = predrawerModifiers;
|
|
this.valueModifiers = valueModifiers;
|
|
this.accessModifiers = accessModifiers;
|
|
this.tooltip = tooltip;
|
|
this.isObsolete = isObsolete;
|
|
}
|
|
|
|
public T GetPredrawerModifier<T>() where T : PredrawerModifierPropertyAttribute
|
|
{
|
|
for (var i = 0; i < predrawerModifiers.Count; i++)
|
|
{
|
|
if (predrawerModifiers[i].attribute is T att)
|
|
return att;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public T GetValueModifier<T>() where T : ValueModifierPropertyAttribute
|
|
{
|
|
for (var i = 0; i < valueModifiers.Count; i++)
|
|
{
|
|
if (valueModifiers[i].attribute is T att)
|
|
return att;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public T GetAccessModifier<T>() where T : AccessModifierPropertyAttribute
|
|
{
|
|
for (var i = 0; i < accessModifiers.Count; i++)
|
|
{
|
|
if (accessModifiers[i].attribute is T att)
|
|
return att;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class: Contains attribute and drawer values
|
|
/// </summary>
|
|
/// <typeparam name="T0"></typeparam>
|
|
/// <typeparam name="T1"></typeparam>
|
|
public sealed class ResultValue<T0, T1> where T0 : AbstractPropertyAttribute
|
|
where T1 : AbstractPropertyDrawer
|
|
{
|
|
public readonly T0 attribute;
|
|
public readonly T1 drawer;
|
|
|
|
public ResultValue(T0 attribute, T1 drawer)
|
|
{
|
|
this.attribute = attribute;
|
|
this.drawer = drawer;
|
|
}
|
|
}
|
|
}
|
|
} |