123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
- #if UNITY_EDITOR
- using System;
- using System.Collections.Generic;
- using System.Reflection;
- using UnityEditor;
- using UnityEngine;
- #if UNITY_6000_0_OR_NEWER
- using GetDrawerTypeForTypeDelegate = System.Func<System.Type, System.Type[], bool, System.Type>;
- #else
- using GetDrawerTypeForTypeDelegate = System.Func<System.Type, System.Type>;
- #endif
- namespace Animancer.Editor
- {
- /// <summary>[Editor-Only] A cache of <see cref="PropertyDrawer"/>s mapped to their target type.</summary>
- /// https://kybernetik.com.au/animancer/api/Animancer.Editor/PropertyDrawers
- public static class PropertyDrawers
- {
- /************************************************************************************************************************/
- private const string
- ScriptAttributeUtility = "UnityEditor.ScriptAttributeUtility",
- FieldFieldName = "m_FieldInfo",
- AttributeFieldName = "m_Attribute";
- private static readonly GetDrawerTypeForTypeDelegate
- GetDrawerTypeForType;
- private static readonly FieldInfo
- FieldField,
- AttributeField;
- /************************************************************************************************************************/
- static PropertyDrawers()
- {
- var editorAssembly = typeof(CustomPropertyDrawer).Assembly;
- var scriptAttributeUtility = editorAssembly.GetType(ScriptAttributeUtility);
- if (scriptAttributeUtility == null)
- return;
- var getDrawerTypeForType = scriptAttributeUtility.GetMethod(
- nameof(GetDrawerTypeForType),
- AnimancerReflection.StaticBindings,
- null,
- #if UNITY_6000_0_OR_NEWER
- new Type[] { typeof(Type), typeof(Type[]), typeof(bool) },
- #else
- new Type[] { typeof(Type) },
- #endif
- null);
- if (getDrawerTypeForType == null)
- return;
- GetDrawerTypeForType = (GetDrawerTypeForTypeDelegate)Delegate.CreateDelegate(
- typeof(GetDrawerTypeForTypeDelegate),
- getDrawerTypeForType);
- var propertyDrawer = typeof(PropertyDrawer);
- FieldField = propertyDrawer.GetField(FieldFieldName, AnimancerReflection.InstanceBindings);
- AttributeField = propertyDrawer.GetField(AttributeFieldName, AnimancerReflection.InstanceBindings);
- Selection.selectionChanged += OnSelectionChanged;
- }
- /************************************************************************************************************************/
- private static readonly Dictionary<Type, PropertyDrawer>
- ObjectTypeToDrawer = new();
- private static readonly Dictionary<Type, PropertyDrawer>
- DrawerTypeToInstance = new();
- /// <summary>Tries to get a <see cref="PropertyDrawer"/> for the given `objectType`.</summary>
- public static bool TryGetDrawer(
- Type objectType,
- FieldInfo field,
- Attribute attribute,
- out PropertyDrawer drawer)
- {
- if (GetDrawerTypeForType == null)
- {
- drawer = null;
- return false;
- }
- if (ObjectTypeToDrawer.TryGetValue(objectType, out drawer))
- return true;
- Type drawerType;
- try
- {
- #if UNITY_6000_0_OR_NEWER
- drawerType = GetDrawerTypeForType(objectType, Type.EmptyTypes, true);
- #else
- drawerType = GetDrawerTypeForType(objectType);
- #endif
- }
- catch (Exception exception)
- {
- Debug.LogException(exception);
- ObjectTypeToDrawer.Add(objectType, null);
- return false;
- }
- if (DrawerTypeToInstance.TryGetValue(drawerType, out drawer))
- {
- ObjectTypeToDrawer.Add(objectType, drawer);
- return true;
- }
- try
- {
- drawer = (PropertyDrawer)Activator.CreateInstance(drawerType);
- FieldField?.SetValue(drawer, field);
- AttributeField?.SetValue(drawer, attribute);
- }
- catch (Exception exception)
- {
- Debug.LogException(exception);
- }
- ObjectTypeToDrawer.Add(objectType, drawer);
- DrawerTypeToInstance.Add(drawerType, drawer);
- return drawer != null;
- }
- /************************************************************************************************************************/
- /// <summary>[Editor-Only]
- /// Indicates that a cached <see cref="PropertyDrawer"/>
- /// should not be kept in the cache after the selection changes.
- /// </summary>
- /// https://kybernetik.com.au/animancer/api/Animancer.Editor/IDiscardOnSelectionChange
- public interface IDiscardOnSelectionChange { }
- /************************************************************************************************************************/
- /// <summary>Discards any cached <see cref="IDiscardOnSelectionChange"/> drawers.</summary>
- private static void OnSelectionChanged()
- {
- DiscardOnSelectionChanged(ObjectTypeToDrawer);
- DiscardOnSelectionChanged(DrawerTypeToInstance);
- }
- /************************************************************************************************************************/
- /// <summary>Discards any cached <see cref="IDiscardOnSelectionChange"/> drawers.</summary>
- private static void DiscardOnSelectionChanged(Dictionary<Type, PropertyDrawer> drawers)
- {
- var discard = ListPool<Type>.Instance.Acquire();
- foreach (var drawer in drawers)
- if (drawer.Value is IDiscardOnSelectionChange)
- discard.Add(drawer.Key);
- for (int i = discard.Count - 1; i >= 0; i--)
- drawers.Remove(discard[i]);
- ListPool<Type>.Instance.Release(discard);
- }
- /************************************************************************************************************************/
- }
- }
- #endif
|