diff --git a/Alchemy/Assets/Alchemy/Editor/AlchemyAttributeDrawer.cs b/Alchemy/Assets/Alchemy/Editor/AlchemyAttributeDrawer.cs index 0d736ff..e4d874b 100644 --- a/Alchemy/Assets/Alchemy/Editor/AlchemyAttributeDrawer.cs +++ b/Alchemy/Assets/Alchemy/Editor/AlchemyAttributeDrawer.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; @@ -6,17 +7,23 @@ namespace Alchemy.Editor { + public interface IAlchemyAttributeDrawer + { + void SetContext(SerializedObject serializedObject, SerializedProperty serializedProperty, object target, MemberInfo memberInfo, Attribute attribute, VisualElement targetElement); + void OnCreateElement(); + } + /// /// Base class for extending drawing processing for fields with Alchemy attributes. /// - public abstract class AlchemyAttributeDrawer + public abstract class AlchemyAttributeDrawer : IAlchemyAttributeDrawer where T : Attribute { - SerializedObject serializedObject; - SerializedProperty serializedProperty; - object target; - MemberInfo memberInfo; - Attribute attribute; - VisualElement targetElement; + private SerializedObject serializedObject; + private SerializedProperty serializedProperty; + private object target; + private MemberInfo memberInfo; + private T attribute; + private VisualElement targetElement; /// /// Target serialized object. @@ -41,7 +48,7 @@ public abstract class AlchemyAttributeDrawer /// /// Target attribute. /// - public Attribute Attribute => attribute; + public T Attribute => attribute; /// /// Target visual element. @@ -53,25 +60,14 @@ public abstract class AlchemyAttributeDrawer /// public abstract void OnCreateElement(); - internal static void ExecutePropertyDrawers(SerializedObject serializedObject, SerializedProperty property, object target, MemberInfo memberInfo, VisualElement memberElement) + void IAlchemyAttributeDrawer.SetContext(SerializedObject serializedObject, SerializedProperty serializedProperty, object target, MemberInfo memberInfo, Attribute attribute, VisualElement targetElement) { - var attributes = memberInfo.GetCustomAttributes(); - var processorTypes = TypeCache.GetTypesWithAttribute(typeof(CustomAttributeDrawerAttribute)); - foreach (var attribute in attributes) - { - var processorType = processorTypes.FirstOrDefault(x => x.IsSubclassOf(typeof(AlchemyAttributeDrawer)) && x.GetCustomAttribute().targetAttributeType == attribute.GetType()); - if (processorType == null) continue; - - var processor = (AlchemyAttributeDrawer)Activator.CreateInstance(processorType); - processor.serializedObject = serializedObject; - processor.serializedProperty = property; - processor.target = target; - processor.memberInfo = memberInfo; - processor.attribute = attribute; - processor.targetElement = memberElement; - - processor.OnCreateElement(); - } + this.serializedObject = serializedObject; + this.serializedProperty = serializedProperty; + this.target = target; + this.memberInfo = memberInfo; + this.attribute = attribute as T; + this.targetElement = targetElement; } } } \ No newline at end of file diff --git a/Alchemy/Assets/Alchemy/Editor/AlchemyAttributeDrawerHelper.cs b/Alchemy/Assets/Alchemy/Editor/AlchemyAttributeDrawerHelper.cs new file mode 100644 index 0000000..8a5b974 --- /dev/null +++ b/Alchemy/Assets/Alchemy/Editor/AlchemyAttributeDrawerHelper.cs @@ -0,0 +1,27 @@ +using System; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEngine.UIElements; + +namespace Alchemy.Editor +{ + internal static class AlchemyAttributeDrawerHelper + { + internal static void ExecutePropertyDrawers(SerializedObject serializedObject, SerializedProperty property, object target, MemberInfo memberInfo, VisualElement memberElement) + { + var attributes = memberInfo.GetCustomAttributes(); + var processorTypes = TypeCache.GetTypesWithAttribute(typeof(CustomAttributeDrawerAttribute)).Where(x => x.IsSubclassOfGeneric(typeof(AlchemyAttributeDrawer<>))); + foreach (var attribute in attributes) + { + var processorType = processorTypes.FirstOrDefault(x => x.GetCustomAttribute().targetAttributeType == attribute.GetType()); + if (processorType == null) continue; + + var processor = (IAlchemyAttributeDrawer)Activator.CreateInstance(processorType); + processor.SetContext(serializedObject, property, target, memberInfo, attribute, memberElement); + + processor.OnCreateElement(); + } + } + } +} \ No newline at end of file diff --git a/Alchemy/Assets/Alchemy/Editor/AlchemyAttributeDrawerHelper.cs.meta b/Alchemy/Assets/Alchemy/Editor/AlchemyAttributeDrawerHelper.cs.meta new file mode 100644 index 0000000..afc6063 --- /dev/null +++ b/Alchemy/Assets/Alchemy/Editor/AlchemyAttributeDrawerHelper.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a4c4a4eb0c44125408cbdd8c93fdde43 \ No newline at end of file diff --git a/Alchemy/Assets/Alchemy/Editor/BuiltinAttributeDrawers.cs b/Alchemy/Assets/Alchemy/Editor/BuiltinAttributeDrawers.cs index 871ddfa..c4d2b57 100644 --- a/Alchemy/Assets/Alchemy/Editor/BuiltinAttributeDrawers.cs +++ b/Alchemy/Assets/Alchemy/Editor/BuiltinAttributeDrawers.cs @@ -9,7 +9,7 @@ namespace Alchemy.Editor.Drawers { [CustomAttributeDrawer(typeof(ReadOnlyAttribute))] - public sealed class ReadOnlyDrawer : AlchemyAttributeDrawer + public sealed class ReadOnlyDrawer : AlchemyAttributeDrawer { public override void OnCreateElement() { @@ -18,7 +18,7 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(IndentAttribute))] - public sealed class IndentDrawer : AlchemyAttributeDrawer + public sealed class IndentDrawer : AlchemyAttributeDrawer { const float IndentPadding = 15f; @@ -36,7 +36,7 @@ void AddPadding() } [CustomAttributeDrawer(typeof(HideInPlayModeAttribute))] - public sealed class HideInPlayModeDrawer : AlchemyAttributeDrawer + public sealed class HideInPlayModeDrawer : AlchemyAttributeDrawer { public override void OnCreateElement() { @@ -45,7 +45,7 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(HideInEditModeAttribute))] - public sealed class HideInEditModeDrawer : AlchemyAttributeDrawer + public sealed class HideInEditModeDrawer : AlchemyAttributeDrawer { public override void OnCreateElement() { @@ -54,7 +54,7 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(DisableInPlayModeAttribute))] - public sealed class DisableInPlayModeDrawer : AlchemyAttributeDrawer + public sealed class DisableInPlayModeDrawer : AlchemyAttributeDrawer { public override void OnCreateElement() { @@ -63,7 +63,7 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(DisableInEditModeAttribute))] - public sealed class DisableInEditModeDrawer : AlchemyAttributeDrawer + public sealed class DisableInEditModeDrawer : AlchemyAttributeDrawer { public override void OnCreateElement() { @@ -72,7 +72,7 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(HideLabelAttribute))] - public sealed class HideLabelDrawer : AlchemyAttributeDrawer + public sealed class HideLabelDrawer : AlchemyAttributeDrawer { public override void OnCreateElement() { @@ -89,11 +89,11 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(LabelTextAttribute))] - public sealed class LabelTextDrawer : AlchemyAttributeDrawer + public sealed class LabelTextDrawer : AlchemyAttributeDrawer { public override void OnCreateElement() { - var labelTextAttribute = (LabelTextAttribute)Attribute; + var labelTextAttribute = Attribute; switch (TargetElement) { @@ -116,11 +116,11 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(LabelWidthAttribute))] - public sealed class LabelWidthDrawer : AlchemyAttributeDrawer + public sealed class LabelWidthDrawer : AlchemyAttributeDrawer { public override void OnCreateElement() { - var width = ((LabelWidthAttribute)Attribute).Width; + var width = Attribute.Width; if (TargetElement is AlchemyPropertyField field && field.FieldElement is PropertyField) { @@ -141,47 +141,47 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(HideIfAttribute))] - public sealed class HideIfDrawer : TrackSerializedObjectAttributeDrawer + public sealed class HideIfDrawer : TrackSerializedObjectAttributeDrawer { protected override void OnInspectorChanged() { - var condition = ReflectionHelper.GetValueBool(Target, ((HideIfAttribute)Attribute).Condition); + var condition = ReflectionHelper.GetValueBool(Target, Attribute.Condition); TargetElement.style.display = condition ? DisplayStyle.None : DisplayStyle.Flex; } } [CustomAttributeDrawer(typeof(ShowIfAttribute))] - public sealed class ShowIfDrawer : TrackSerializedObjectAttributeDrawer + public sealed class ShowIfDrawer : TrackSerializedObjectAttributeDrawer { protected override void OnInspectorChanged() { - var condition = ReflectionHelper.GetValueBool(Target, ((ShowIfAttribute)Attribute).Condition); + var condition = ReflectionHelper.GetValueBool(Target, Attribute.Condition); TargetElement.style.display = !condition ? DisplayStyle.None : DisplayStyle.Flex; } } [CustomAttributeDrawer(typeof(DisableIfAttribute))] - public sealed class DisableIfDrawer : TrackSerializedObjectAttributeDrawer + public sealed class DisableIfDrawer : TrackSerializedObjectAttributeDrawer { protected override void OnInspectorChanged() { - var condition = ReflectionHelper.GetValueBool(Target, ((DisableIfAttribute)Attribute).Condition); + var condition = ReflectionHelper.GetValueBool(Target, Attribute.Condition); TargetElement.SetEnabled(!condition); } } [CustomAttributeDrawer(typeof(EnableIfAttribute))] - public sealed class EnableIfDrawer : TrackSerializedObjectAttributeDrawer + public sealed class EnableIfDrawer : TrackSerializedObjectAttributeDrawer { protected override void OnInspectorChanged() { - var condition = ReflectionHelper.GetValueBool(Target, ((EnableIfAttribute)Attribute).Condition); + var condition = ReflectionHelper.GetValueBool(Target, Attribute.Condition); TargetElement.SetEnabled(condition); } } [CustomAttributeDrawer(typeof(RequiredAttribute))] - public sealed class RequiredDrawer : TrackSerializedObjectAttributeDrawer + public sealed class RequiredDrawer : TrackSerializedObjectAttributeDrawer { HelpBox helpBox; @@ -189,7 +189,7 @@ public override void OnCreateElement() { if (SerializedProperty.propertyType != SerializedPropertyType.ObjectReference) return; - var message = ((RequiredAttribute)Attribute).Message ?? ObjectNames.NicifyVariableName(SerializedProperty.displayName) + " is required."; + var message = Attribute.Message ?? ObjectNames.NicifyVariableName(SerializedProperty.displayName) + " is required."; helpBox = new HelpBox(message, HelpBoxMessageType.Error); var parent = TargetElement.parent; @@ -205,13 +205,13 @@ protected override void OnInspectorChanged() } [CustomAttributeDrawer(typeof(ValidateInputAttribute))] - public sealed class ValidateInputDrawer : TrackSerializedObjectAttributeDrawer + public sealed class ValidateInputDrawer : TrackSerializedObjectAttributeDrawer { HelpBox helpBox; public override void OnCreateElement() { - var message = ((ValidateInputAttribute)Attribute).Message ?? ObjectNames.NicifyVariableName(SerializedProperty.displayName) + " is not valid."; + var message = Attribute.Message ?? ObjectNames.NicifyVariableName(SerializedProperty.displayName) + " is not valid."; helpBox = new HelpBox(message, HelpBoxMessageType.Error); var parent = TargetElement.parent; @@ -222,19 +222,19 @@ public override void OnCreateElement() protected override void OnInspectorChanged() { - var result = ReflectionHelper.Invoke(Target, ((ValidateInputAttribute)Attribute).Condition, SerializedProperty.GetValue()); + var result = ReflectionHelper.Invoke(Target, Attribute.Condition, SerializedProperty.GetValue()); helpBox.style.display = result is bool flag && flag ? DisplayStyle.None : DisplayStyle.Flex; } } [CustomAttributeDrawer(typeof(HelpBoxAttribute))] - public sealed class HelpBoxDrawer : AlchemyAttributeDrawer + public sealed class HelpBoxDrawer : AlchemyAttributeDrawer { HelpBox helpBox; public override void OnCreateElement() { - var att = (HelpBoxAttribute)Attribute; + var att = Attribute; helpBox = new HelpBox(att.Message, att.MessageType); var parent = TargetElement.parent; @@ -243,7 +243,7 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(PreviewAttribute))] - public sealed class PreviewDrawer : TrackSerializedObjectAttributeDrawer + public sealed class PreviewDrawer : TrackSerializedObjectAttributeDrawer { private Image image; private const float BorderWidth = 1f; @@ -253,7 +253,7 @@ public override void OnCreateElement() { if (SerializedProperty == null || SerializedProperty.propertyType != SerializedPropertyType.ObjectReference) return; - var att = (PreviewAttribute)Attribute; + var att = Attribute; image = new Image { @@ -306,11 +306,11 @@ protected override void OnInspectorChanged() } [CustomAttributeDrawer(typeof(HorizontalLineAttribute))] - public sealed class HorizontalLineDrawer : AlchemyAttributeDrawer + public sealed class HorizontalLineDrawer : AlchemyAttributeDrawer { public override void OnCreateElement() { - var att = (HorizontalLineAttribute)Attribute; + var att = Attribute; var parent = TargetElement.parent; var lineColor = att.Color == default ? GUIHelper.LineColor : att.Color; var line = GUIHelper.CreateLine(lineColor, EditorGUIUtility.standardVerticalSpacing * 4f); @@ -319,11 +319,11 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(TitleAttribute))] - public sealed class TitleDrawer : AlchemyAttributeDrawer + public sealed class TitleDrawer : AlchemyAttributeDrawer { public override void OnCreateElement() { - var att = (TitleAttribute)Attribute; + var att = Attribute; var parent = TargetElement.parent; var title = new Label(att.TitleText) @@ -358,7 +358,7 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(BlockquoteAttribute))] - public sealed class BlockquoteDrawer : AlchemyAttributeDrawer + public sealed class BlockquoteDrawer : AlchemyAttributeDrawer { public BlockquoteDrawer() { @@ -370,7 +370,7 @@ public BlockquoteDrawer() public override void OnCreateElement() { - var att = (BlockquoteAttribute)Attribute; + var att = Attribute; var blockquote = new IMGUIContainer(() => { var width = EditorGUIUtility.currentViewWidth; @@ -397,13 +397,13 @@ public override void OnCreateElement() } [CustomAttributeDrawer(typeof(OnValueChangedAttribute))] - public sealed class OnValueChangedDrawer : AlchemyAttributeDrawer + public sealed class OnValueChangedDrawer : AlchemyAttributeDrawer { public override void OnCreateElement() { TargetElement.TrackPropertyValue(SerializedProperty, property => { - var methodName = ((OnValueChangedAttribute)Attribute).MethodName; + var methodName = Attribute.MethodName; var methods = ReflectionHelper.GetAllMethodsIncludingBaseNonPublic(Target.GetType()) .Where(x => x.Name == methodName); diff --git a/Alchemy/Assets/Alchemy/Editor/Elements/ClassField.cs b/Alchemy/Assets/Alchemy/Editor/Elements/ClassField.cs index 91334cc..056cf49 100644 --- a/Alchemy/Assets/Alchemy/Editor/Elements/ClassField.cs +++ b/Alchemy/Assets/Alchemy/Editor/Elements/ClassField.cs @@ -51,7 +51,7 @@ public ClassField(object obj, Type type, string label) var e = node.Drawer?.GetGroupElement(member.GetCustomAttribute()); if (e == null) node.VisualElement.Add(element); else e.Add(element); - AlchemyAttributeDrawer.ExecutePropertyDrawers(null, null, obj, member, element); + AlchemyAttributeDrawerHelper.ExecutePropertyDrawers(null, null, obj, member, element); } } diff --git a/Alchemy/Assets/Alchemy/Editor/Internal/InspectorHelper.cs b/Alchemy/Assets/Alchemy/Editor/Internal/InspectorHelper.cs index 407618f..82dc06d 100644 --- a/Alchemy/Assets/Alchemy/Editor/Internal/InspectorHelper.cs +++ b/Alchemy/Assets/Alchemy/Editor/Internal/InspectorHelper.cs @@ -145,7 +145,7 @@ public static void BuildElements(SerializedObject serializedObject, VisualElemen if (e == null) node.VisualElement.Add(element); else e.Add(element); - AlchemyAttributeDrawer.ExecutePropertyDrawers(serializedObject, property, target, member, element); + AlchemyAttributeDrawerHelper.ExecutePropertyDrawers(serializedObject, property, target, member, element); } } } diff --git a/Alchemy/Assets/Alchemy/Editor/Internal/TypeHelper.cs b/Alchemy/Assets/Alchemy/Editor/Internal/TypeHelper.cs index 4b887f7..f89d881 100644 --- a/Alchemy/Assets/Alchemy/Editor/Internal/TypeHelper.cs +++ b/Alchemy/Assets/Alchemy/Editor/Internal/TypeHelper.cs @@ -50,5 +50,20 @@ public static bool HasDefaultConstructor(Type type) { return type.GetConstructors().Any(t => t.GetParameters().Count() == 0); } + + public static bool IsSubclassOfGeneric(this Type type, Type genericType) + { + var current = type.BaseType; + while (current != null && current != typeof(object)) + { + if (current.IsGenericType && current.GetGenericTypeDefinition() == genericType) + { + return true; + } + current = current.BaseType; + } + + return false; + } } } diff --git a/Alchemy/Assets/Alchemy/Editor/TrackSerializedObjectAttributeDrawer.cs b/Alchemy/Assets/Alchemy/Editor/TrackSerializedObjectAttributeDrawer.cs index de273b7..7aad8d2 100644 --- a/Alchemy/Assets/Alchemy/Editor/TrackSerializedObjectAttributeDrawer.cs +++ b/Alchemy/Assets/Alchemy/Editor/TrackSerializedObjectAttributeDrawer.cs @@ -1,8 +1,9 @@ +using System; using UnityEditor.UIElements; namespace Alchemy.Editor.Drawers { - public abstract class TrackSerializedObjectAttributeDrawer : AlchemyAttributeDrawer + public abstract class TrackSerializedObjectAttributeDrawer : AlchemyAttributeDrawer where T : Attribute { public override void OnCreateElement() {