diff --git a/Assets/BetterCommons/Editor/Comparers/CachedSerializedPropertyComparer.cs b/Assets/BetterCommons/Editor/Comparers/CachedSerializedPropertyComparer.cs new file mode 100644 index 0000000..cc8b7ff --- /dev/null +++ b/Assets/BetterCommons/Editor/Comparers/CachedSerializedPropertyComparer.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Better.Commons.EditorAddons.Drawers.Base; +using Better.Commons.Runtime.Comparers; + +namespace Better.Commons.EditorAddons.Comparers +{ + public class CachedSerializedPropertyComparer : BaseComparer, + IEqualityComparer + { + public bool Equals(CachedSerializedProperty x, CachedSerializedProperty y) + { + if (ReferenceEquals(x, y)) return true; + if (ReferenceEquals(x, null)) return false; + if (ReferenceEquals(y, null)) return false; + if (x.GetType() != y.GetType()) return false; + return x == y; + } + + public int GetHashCode(CachedSerializedProperty obj) + { + return obj.GetHashCode(); + } + + } +} \ No newline at end of file diff --git a/Assets/BetterCommons/Editor/Comparers/CachedSerializedPropertyComparer.cs.meta b/Assets/BetterCommons/Editor/Comparers/CachedSerializedPropertyComparer.cs.meta new file mode 100644 index 0000000..54b2f74 --- /dev/null +++ b/Assets/BetterCommons/Editor/Comparers/CachedSerializedPropertyComparer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ad4cc8e3748645db8db6a1f2e22eb09e +timeCreated: 1727722187 \ No newline at end of file diff --git a/Assets/BetterCommons/Editor/Comparers/SerializedPropertyComparer.cs b/Assets/BetterCommons/Editor/Comparers/SerializedPropertyComparer.cs index e2a74fb..9daadfc 100644 --- a/Assets/BetterCommons/Editor/Comparers/SerializedPropertyComparer.cs +++ b/Assets/BetterCommons/Editor/Comparers/SerializedPropertyComparer.cs @@ -20,7 +20,7 @@ public bool Equals(SerializedProperty x, SerializedProperty y) public int GetHashCode(SerializedProperty obj) { - return !obj.IsDisposed() && obj.propertyPath != null ? obj.propertyPath.GetHashCode() : 0; + return obj.Verify() && !obj.IsDisposed() && obj.propertyPath != null ? obj.propertyPath.GetHashCode() : 0; } } } \ No newline at end of file diff --git a/Assets/BetterCommons/Editor/Drawers/Base/CachedSerializedProperty.cs b/Assets/BetterCommons/Editor/Drawers/Base/CachedSerializedProperty.cs new file mode 100644 index 0000000..afbab53 --- /dev/null +++ b/Assets/BetterCommons/Editor/Drawers/Base/CachedSerializedProperty.cs @@ -0,0 +1,87 @@ +using System; +using Better.Commons.EditorAddons.Extensions; +using UnityEditor; + +namespace Better.Commons.EditorAddons.Drawers.Base +{ + public class CachedSerializedProperty : IEquatable + { + private readonly int _hashCode; + private readonly SerializedProperty _serializedProperty; + + public SerializedProperty SerializedProperty => _serializedProperty; + + public CachedSerializedProperty(SerializedProperty serializedProperty) + { + _hashCode = serializedProperty.GetHashCode(); + _serializedProperty = serializedProperty; + } + + public override int GetHashCode() + { + return HashCode.Combine(_hashCode, _serializedProperty); + } + + public bool IsValid() + { + try + { + if (_serializedProperty == null) + { + return false; + } + + if (!_serializedProperty.Verify()) + { + return false; + } + + if (_serializedProperty.IsDisposed()) + { + return false; + } + + return _serializedProperty.serializedObject.targetObject != null; + } + catch + { + return false; + } + } + + public bool Equals(CachedSerializedProperty other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return _hashCode == other._hashCode; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((CachedSerializedProperty)obj); + } + + public static implicit operator SerializedProperty(CachedSerializedProperty property) + { + return property.SerializedProperty; + } + + public static explicit operator CachedSerializedProperty(SerializedProperty property) + { + return new CachedSerializedProperty(property); + } + + public static bool operator ==(CachedSerializedProperty left, CachedSerializedProperty right) + { + return !ReferenceEquals(left, null) && left.Equals(right); + } + + public static bool operator !=(CachedSerializedProperty left, CachedSerializedProperty right) + { + return !ReferenceEquals(left, null) && !left.Equals(right); + } + } +} \ No newline at end of file diff --git a/Assets/BetterCommons/Editor/Drawers/Base/CachedSerializedProperty.cs.meta b/Assets/BetterCommons/Editor/Drawers/Base/CachedSerializedProperty.cs.meta new file mode 100644 index 0000000..87571e5 --- /dev/null +++ b/Assets/BetterCommons/Editor/Drawers/Base/CachedSerializedProperty.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d27bc7dd6eea4522be92d5aff15eaa91 +timeCreated: 1727722065 \ No newline at end of file diff --git a/Assets/BetterCommons/Editor/Drawers/Base/HandlerCollection.cs b/Assets/BetterCommons/Editor/Drawers/Base/HandlerCollection.cs index af06d30..d9ff9e9 100644 --- a/Assets/BetterCommons/Editor/Drawers/Base/HandlerCollection.cs +++ b/Assets/BetterCommons/Editor/Drawers/Base/HandlerCollection.cs @@ -5,14 +5,14 @@ namespace Better.Commons.EditorAddons.Drawers.Base { - public class HandlerCollection : Dictionary> where T : SerializedPropertyHandler + public class HandlerCollection : Dictionary> where T : SerializedPropertyHandler { - public HandlerCollection() : base(SerializedPropertyComparer.Instance) + public HandlerCollection() : base(CachedSerializedPropertyComparer.Instance) { } /// - /// Deconstruct method for stored wrappers + /// ContainerReleased method for stored wrappers /// public void Deconstruct() { @@ -21,5 +21,22 @@ public void Deconstruct() value.Handler.Deconstruct(); } } + + public void Revalidate() + { + var listToRemove = new List(); + foreach (var property in Keys) + { + if (!property.IsValid()) + { + listToRemove.Add(property); + } + } + + foreach (var property in listToRemove) + { + Remove(property); + } + } } } \ No newline at end of file diff --git a/Assets/BetterCommons/Editor/Drawers/BasePropertyDrawer.cs b/Assets/BetterCommons/Editor/Drawers/BasePropertyDrawer.cs index 0edc0ea..fc74b0b 100644 --- a/Assets/BetterCommons/Editor/Drawers/BasePropertyDrawer.cs +++ b/Assets/BetterCommons/Editor/Drawers/BasePropertyDrawer.cs @@ -18,6 +18,7 @@ public abstract class BasePropertyDrawer : PropertyDrawer protected TAttribute Attribute { get; private set; } protected HandlerCollection Handlers { get; private set; } + protected ElementsContainer Container { get; private set; } protected TypeHandlerBinder TypeHandlersBinder { get; private set; } protected BasePropertyDrawer() @@ -53,9 +54,11 @@ protected THandler GetHandler(SerializedProperty property) var attributeType = Attribute.GetType(); var fieldType = GetFieldOrElementType(); - if (Handlers.TryGetValue(property, out var value)) + var cached = new CachedSerializedProperty(property); + Handlers.Revalidate(); + + if (Handlers.TryGetValue(cached, out var value)) { - ValidationUtility.ValidateCachedProperties(Handlers); return value.Handler; } @@ -66,25 +69,31 @@ protected THandler GetHandler(SerializedProperty property) } var collectionValue = new CollectionValue(handler, fieldType); - Handlers.Add(property, collectionValue); + Handlers.Add(cached, collectionValue); return handler; } public sealed override VisualElement CreatePropertyGUI(SerializedProperty property) { - var container = new ElementsContainer(property); + if (Container != null) + { + ContainerReleased(Container); + Container = null; + } + + Container = new ElementsContainer(property); FieldInfo = fieldInfo; Attribute = (TAttribute)attribute; Handlers = new HandlerCollection(); TypeHandlersBinder = HandlerBinderRegistry.GetMap(); - PopulateContainer(container); - container.Use(); + PopulateContainer(Container); + Container.Use(); var subState = StyleDefinition.CombineSubState(typeof(TAttribute).Name, GetType().Name); - container.RootElement.AddToClassList(subState); - return container.RootElement; + Container.RootElement.AddToClassList(subState); + return Container.RootElement; } protected abstract void PopulateContainer(ElementsContainer container); @@ -111,9 +120,14 @@ protected virtual Type GetFieldOrElementType() return fieldType; } - protected virtual void Deconstruct() + private void Deconstruct() { Handlers?.Deconstruct(); + ContainerReleased(Container); + } + + protected virtual void ContainerReleased(ElementsContainer container) + { } } } \ No newline at end of file diff --git a/Assets/BetterCommons/Editor/Drawers/Container/ContainerPrewarmElement.cs b/Assets/BetterCommons/Editor/Drawers/Container/ContainerPrewarmElement.cs new file mode 100644 index 0000000..8b4c61a --- /dev/null +++ b/Assets/BetterCommons/Editor/Drawers/Container/ContainerPrewarmElement.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Better.Commons.EditorAddons.Drawers.Container +{ + public class ContainerPrewarmElement : SubPrewarmElement + { + private List PrewarmChildren { get; } + + public ContainerPrewarmElement() : base() + { + PrewarmChildren = new List(); + } + + public void Add(SubPrewarmElement prewarmElement) + { + PrewarmChildren.Add(prewarmElement); + base.Add(prewarmElement); + } + + public IEnumerable GetByTags(IEnumerable tag) + { + return PrewarmChildren.Where(x => x.ContainsAnyTags(tag)); + } + + public bool TryGetByTag(object tag, out SubPrewarmElement element) + { + element = PrewarmChildren.FirstOrDefault(x => x.ContainsTag(tag)); + return element != null; + } + } +} \ No newline at end of file diff --git a/Assets/BetterCommons/Editor/Drawers/Container/ContainerPrewarmElement.cs.meta b/Assets/BetterCommons/Editor/Drawers/Container/ContainerPrewarmElement.cs.meta new file mode 100644 index 0000000..03ecd68 --- /dev/null +++ b/Assets/BetterCommons/Editor/Drawers/Container/ContainerPrewarmElement.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f3c33c8b4f4048ffaa19d0a7d5efbed7 +timeCreated: 1727048683 \ No newline at end of file diff --git a/Assets/BetterCommons/Editor/Drawers/Container/ElementsContainer.cs b/Assets/BetterCommons/Editor/Drawers/Container/ElementsContainer.cs index 07be352..dc1aafe 100644 --- a/Assets/BetterCommons/Editor/Drawers/Container/ElementsContainer.cs +++ b/Assets/BetterCommons/Editor/Drawers/Container/ElementsContainer.cs @@ -18,11 +18,14 @@ public class ElementsContainer public SerializedObject SerializedObject => SerializedProperty.serializedObject; public SerializedProperty SerializedProperty { get; } public LabelContainer LabelContainer { get; } - public List PrewarmChildren { get; } + + public List ContainersPrewarmChildren { get; } public event Action SerializedObjectChanged; public event Action SerializedPropertyChanged; + public const string Tag = nameof(ElementsContainer); + public ElementsContainer(SerializedProperty serializedProperty) { Used = false; @@ -34,7 +37,7 @@ public ElementsContainer(SerializedProperty serializedProperty) RootElement.TrackSerializedObjectValue(SerializedObject, OnSerializedObjectChanged); LabelContainer = new LabelContainer(serializedProperty.displayName); - PrewarmChildren = new List(); + ContainersPrewarmChildren = new List(); CoreElement = new PrewarmElement(); PropertyField propertyField; @@ -50,10 +53,11 @@ public ElementsContainer(SerializedProperty serializedProperty) CoreElement.Add(propertyField); } - RootElement.Add(CoreElement); + CreateElementFrom(CoreElement); + propertyField.name = $"{nameof(ElementsContainer)}_{SerializedProperty.propertyPath}"; propertyField.RegisterCallback(OnSerializedPropertyChanged); - propertyField.RegisterCallback(ScheduleUpdateGeometry); + propertyField.RegisterCallback(ScheduleAttachToPanel); propertyField.style.FlexGrow(StyleDefinition.OneStyleFloat); } @@ -64,33 +68,41 @@ private VisualElement CreateRootElement() return rootElement; } - public SubPrewarmElement CreateElementFrom(VisualElement element) + public SubPrewarmElement CreateElementFrom(VisualElement element, string tag = Tag) { + if(!TryGetByTag(tag, out var containerPrewarmElement)) + { + containerPrewarmElement = new ContainerPrewarmElement(); + containerPrewarmElement.AddTag(tag); + ContainersPrewarmChildren.Add(containerPrewarmElement); + RootElement.Add(containerPrewarmElement); + } + var item = new SubPrewarmElement(); item.Add(element); - PrewarmChildren.Add(item); - RootElement.Add(item); + containerPrewarmElement.Add(item); return item; } - - public SubPrewarmElement GetByTag(object tag) + + public bool TryGetByTag(object containerTag, object subTag, out SubPrewarmElement element) { - if (TryGetByTag(tag, out var fieldVisualElement)) + if (!TryGetByTag(containerTag, out var bufferElement)) { - return fieldVisualElement; + element = null; + return false; } - - throw new KeyNotFoundException($"Element with tag: {tag} not found"); + + return bufferElement.TryGetByTag(subTag, out element); } - public IEnumerable GetByTags(IEnumerable tag) + public IEnumerable GetByTags(IEnumerable tag) { - return PrewarmChildren.Where(x => x.ContainsAnyTags(tag)); + return ContainersPrewarmChildren.Where(x => x.ContainsAnyTags(tag)); } - public bool TryGetByTag(object tag, out SubPrewarmElement element) + public bool TryGetByTag(object tag, out ContainerPrewarmElement element) { - element = PrewarmChildren.FirstOrDefault(x => x.ContainsTag(tag)); + element = ContainersPrewarmChildren.FirstOrDefault(x => x.ContainsTag(tag)); return element != null; } @@ -109,14 +121,14 @@ private void OnSerializedPropertyChanged(SerializedPropertyChangeEvent changeEve SerializedPropertyChanged?.Invoke(this); } - private void ScheduleUpdateGeometry(GeometryChangedEvent changedEvent) + private void ScheduleAttachToPanel(AttachToPanelEvent changedEvent) { if (changedEvent.target is not PropertyField element) return; - element.schedule.Execute(() => OnGeometryChanged(element)); + element.schedule.Execute(() => OnAttachToPanel(element)); } - private void OnGeometryChanged(VisualElement element) + private void OnAttachToPanel(VisualElement element) { var propertyPath = SerializedProperty.propertyPath; var propertyFields = element.Query().Where(field => field.bindingPath.CompareOrdinal(propertyPath)).Build(); diff --git a/Assets/BetterCommons/Editor/Extensions/ElementsContainerExtensions.cs b/Assets/BetterCommons/Editor/Extensions/ElementsContainerExtensions.cs index 9033eeb..470830a 100644 --- a/Assets/BetterCommons/Editor/Extensions/ElementsContainerExtensions.cs +++ b/Assets/BetterCommons/Editor/Extensions/ElementsContainerExtensions.cs @@ -31,23 +31,24 @@ public static Image AddIcon(this ElementsContainer self, IconType iconType) public static void AddNotSupportedBox(this ElementsContainer self, Type fieldType, Type attributeType) { var helpBox = VisualElementUtility.NotSupportedBox(self.SerializedProperty, fieldType, attributeType); - if (self.TryGetByTag(VisualElementUtility.NotSupportedTag, out var element)) + if (self.TryGetByTag(VisualElementUtility.HelpBoxTag, VisualElementUtility.NotSupportedTag, out var element)) { element.Add(helpBox); } else { - element = self.CreateElementFrom(helpBox); + element = self.CreateElementFrom(helpBox, VisualElementUtility.HelpBoxTag); element.AddTag(VisualElementUtility.NotSupportedTag); } } public static SubPrewarmElement GetOrAddHelpBox(this ElementsContainer self, string message, object tag, HelpBoxMessageType messageType) { - if (!self.TryGetByTag(tag, out var element)) + if (!self.TryGetByTag(VisualElementUtility.HelpBoxTag, tag, out var element)) { var helpBox = VisualElementUtility.HelpBox(message, messageType); - element = self.CreateElementFrom(helpBox); + element = self.CreateElementFrom(helpBox, VisualElementUtility.HelpBoxTag); + element.name = $"{tag}"; element.AddTag(tag); } diff --git a/Assets/BetterCommons/Editor/Extensions/SerializedPropertyExtensions.cs b/Assets/BetterCommons/Editor/Extensions/SerializedPropertyExtensions.cs index 61209cb..25a6fd0 100644 --- a/Assets/BetterCommons/Editor/Extensions/SerializedPropertyExtensions.cs +++ b/Assets/BetterCommons/Editor/Extensions/SerializedPropertyExtensions.cs @@ -377,10 +377,10 @@ public static object GetLastNonCollectionParent(this SerializedProperty self) { var container = containers[index]; if (container.GetType().IsEnumerable()) continue; - return container; + return container.ParentInstance; } - return containers.FirstOrDefault(); + return containers.FirstOrDefault()?.ParentInstance; } public static List GetPropertyParents(this SerializedProperty self) @@ -515,7 +515,7 @@ private static List TraverseBaseClasses(Type currentType, string nam private static void SetMemberValue(object container, string name, object value) { var type = container.GetType(); - var members = type.GetMember(name, Defines.FieldsFlags); + var members = type.GetMembersByNameRecursive(name).ToArray(); for (var i = 0; i < members.Length; ++i) { if (members[i] is FieldInfo field) diff --git a/Assets/BetterCommons/Editor/Utility/SelectorUtility.cs b/Assets/BetterCommons/Editor/Utility/SelectorUtility.cs index 92e0cef..677991a 100644 --- a/Assets/BetterCommons/Editor/Utility/SelectorUtility.cs +++ b/Assets/BetterCommons/Editor/Utility/SelectorUtility.cs @@ -4,6 +4,7 @@ using System.Reflection; using Better.Commons.Runtime.Extensions; using Better.Commons.Runtime.Utility; +using UnityEngine; namespace Better.Commons.EditorAddons.Utility { @@ -44,7 +45,7 @@ public static bool TryGetValue(string selector, object instance, out object valu if (TryGetStaticInfo(selector, out var selectorInfo)) { value = ReflectionUtility.GetValueFromStaticMember(selectorInfo.Type, selectorInfo.MemberName); - return true; + return value != null; } if (TryGetInstanceInfo(selector, out selectorInfo)) @@ -55,10 +56,91 @@ public static bool TryGetValue(string selector, object instance, out object valu } var memberName = selector.Replace(Brackets, string.Empty); - value = ReflectionUtility.GetValueFromInstanceMember(instance, memberName); + + if (!TryFindMethodParameters(instance, memberName, out var parameters)) + { + value = null; + return false; + } + + value = ReflectionUtility.GetValueFromInstanceMember(memberName, instance, parameters); return value != null; } + private static bool TryFindMethodParameters(object instance, string memberName, out object[] parameters) + { + var instanceType = instance.GetType(); + var member = ReflectionUtility.GetMemberByNameRecursive(instanceType, memberName); + + if (member is MethodInfo methodInfo) + { + return TryFindParameters(methodInfo.GetParameters(), instance, instanceType, out parameters); + } + + parameters = Array.Empty(); + return true; + } + + private static bool TryFindParameters(ParameterInfo[] parameterInfos, object instance, Type instanceType, out object[] parameters) + { + if (parameterInfos.Length > 1) + { + parameters = Array.Empty(); + return false; + } + + if (parameterInfos.Length == 0) + { + parameters = Array.Empty(); + return true; + } + + return TryFindSingleParameter(instance, instanceType, parameterInfos[0], out parameters); + } + + private static bool TryFindSingleParameter(object instance, Type instanceType, ParameterInfo parameter, out object[] parameters) + { + if (parameter.IsOut) + { + parameters = Array.Empty(); + return false; + } + + if (parameter.ParameterType == typeof(GameObject)) + { + var foundGameObjectParameter = TryFindGameObjectParameter(instance, out parameters); + return foundGameObjectParameter; + } + + if (parameter.ParameterType.IsAssignableFrom(instanceType)) + { + parameters = new object[] { instance }; + return true; + } + + parameters = Array.Empty(); + return false; + } + + private static bool TryFindGameObjectParameter(object instance, out object[] parameters) + { + if (instance is GameObject) + { + parameters = new object[] { instance }; + return true; + } + + if (instance is Component component) + { + parameters = new object[] { component.gameObject }; + return true; + } + + parameters = Array.Empty(); + return false; + } + + private static bool TryGetStaticInfo(string selector, out SelectorInfo info) { if (selector.IsNullOrEmpty()) diff --git a/Assets/BetterCommons/Editor/Utility/StyleDefinition.cs b/Assets/BetterCommons/Editor/Utility/StyleDefinition.cs index ca02e4a..1d945d6 100644 --- a/Assets/BetterCommons/Editor/Utility/StyleDefinition.cs +++ b/Assets/BetterCommons/Editor/Utility/StyleDefinition.cs @@ -8,6 +8,7 @@ public static class StyleDefinition public const string BetterPropertyClass = "better-property-field"; private static float _spaceHeight = 6f; public static readonly StyleLength SingleLineHeight = new StyleLength(new Length(18, LengthUnit.Pixel)); + public static readonly StyleLength ButtonHeight = new StyleLength(new Length(21, LengthUnit.Pixel)); public static readonly StyleLength IndentLevelPadding = new StyleLength(new Length(15, LengthUnit.Pixel)); public static readonly StyleFloat OneStyleFloat = new StyleFloat(1f); public static readonly StyleFloat ZeroStyleFloat = new StyleFloat(0f); diff --git a/Assets/BetterCommons/Editor/Utility/ValidationUtility.cs b/Assets/BetterCommons/Editor/Utility/ValidationUtility.cs deleted file mode 100644 index 75da81b..0000000 --- a/Assets/BetterCommons/Editor/Utility/ValidationUtility.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using Better.Commons.EditorAddons.Drawers.Base; -using Better.Commons.EditorAddons.Drawers.Handlers; -using Better.Commons.EditorAddons.Extensions; -using Better.Commons.Runtime.Utility; -using UnityEditor; - -namespace Better.Commons.EditorAddons.Utility -{ - public static class ValidationUtility - { - public static void ValidateCachedProperties(HandlerCollection collection) where THandler : SerializedPropertyHandler - { - ValidateCachedProperties(collection, DefaultValidationFunc); - } - - /// - /// Validates stored properties if their supported - /// - /// - /// - public static void ValidateCachedProperties(HandlerCollection collection, Func, bool> validationFunc) - where THandler : SerializedPropertyHandler - { - if (validationFunc == null) - { - DebugUtility.LogException(nameof(validationFunc)); - return; - } - - List keysToRemove = null; - foreach (var value in collection) - { - if (validationFunc.Invoke(value.Key, value.Value)) continue; - if (keysToRemove == null) - { - keysToRemove = new List(); - } - - keysToRemove.Add(value.Key); - } - - if (keysToRemove != null) - { - foreach (var serializedProperty in keysToRemove) - { - collection.Remove(serializedProperty); - } - } - } - - private static bool DefaultValidationFunc(SerializedProperty serializedProperty, CollectionValue collectionValue) where THandler : SerializedPropertyHandler - { - return serializedProperty.Verify() && !serializedProperty.IsDisposed(); - } - } -} \ No newline at end of file diff --git a/Assets/BetterCommons/Editor/Utility/ValidationUtility.cs.meta b/Assets/BetterCommons/Editor/Utility/ValidationUtility.cs.meta deleted file mode 100644 index f5a895a..0000000 --- a/Assets/BetterCommons/Editor/Utility/ValidationUtility.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 623d25d589584854bbcae1450e9b2c01 -timeCreated: 1716678421 \ No newline at end of file diff --git a/Assets/BetterCommons/Editor/Utility/VisualElementUtility.cs b/Assets/BetterCommons/Editor/Utility/VisualElementUtility.cs index a731bc3..214ed1a 100644 --- a/Assets/BetterCommons/Editor/Utility/VisualElementUtility.cs +++ b/Assets/BetterCommons/Editor/Utility/VisualElementUtility.cs @@ -19,7 +19,8 @@ public static class VisualElementUtility private static readonly HelpBox EmptyHelpBox = new HelpBox(); public const string NotSupportedTag = nameof(NotSupportedTag); - + public const string HelpBoxTag = nameof(HelpBox); + private static string NotSupportedMessage(string fieldName, Type fieldType, Type attributeType) { return $"Field {fieldName.FormatBold()} of type {fieldType.Name.FormatBold()} not supported for {attributeType.Name.FormatBold()}"; diff --git a/Assets/BetterCommons/Runtime/Extensions/ActionExtensions.cs b/Assets/BetterCommons/Runtime/Extensions/ActionExtensions.cs index d0bf076..57bad48 100644 --- a/Assets/BetterCommons/Runtime/Extensions/ActionExtensions.cs +++ b/Assets/BetterCommons/Runtime/Extensions/ActionExtensions.cs @@ -7,7 +7,7 @@ public static class ActionExtensions { private const bool DefaultLogException = true; - #region SafeInvoke`16 + #region TryInvoke`16 public static bool TryInvoke(this Action self, bool logException = DefaultLogException) { diff --git a/Assets/BetterCommons/Runtime/Extensions/CallbackEventHandlerExtensions.cs b/Assets/BetterCommons/Runtime/Extensions/CallbackEventHandlerExtensions.cs new file mode 100644 index 0000000..41b395a --- /dev/null +++ b/Assets/BetterCommons/Runtime/Extensions/CallbackEventHandlerExtensions.cs @@ -0,0 +1,146 @@ +using UnityEngine.UIElements; + +namespace Better.Commons.Runtime.Extensions +{ + public static class CallbackEventHandlerExtensions + { + #region RegisterCallback`16 + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5, arg6)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5, arg6, arg7)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)); + } + + public static void RegisterCallback( + this CallbackEventHandler self, + EventCallback callback, + T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16 + ) where TEventType : EventBase, new() + { + self.RegisterCallback(callback, (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)); + } + + #endregion + } +} \ No newline at end of file diff --git a/Assets/BetterCommons/Runtime/Extensions/CallbackEventHandlerExtensions.cs.meta b/Assets/BetterCommons/Runtime/Extensions/CallbackEventHandlerExtensions.cs.meta new file mode 100644 index 0000000..f871868 --- /dev/null +++ b/Assets/BetterCommons/Runtime/Extensions/CallbackEventHandlerExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a78eb3249ed4232b3d05185700b1a98 +timeCreated: 1727748705 \ No newline at end of file diff --git a/Assets/BetterCommons/Runtime/Extensions/FuncExtensions.cs b/Assets/BetterCommons/Runtime/Extensions/FuncExtensions.cs index 4d9c8ab..8c8471f 100644 --- a/Assets/BetterCommons/Runtime/Extensions/FuncExtensions.cs +++ b/Assets/BetterCommons/Runtime/Extensions/FuncExtensions.cs @@ -7,7 +7,7 @@ public static class FuncExtensions { private const bool DefaultLogException = true; - #region SafeInvoke`16 + #region TryInvoke`16 public static bool TryInvoke(this Func self, out TResult result, bool logException = DefaultLogException) { diff --git a/Assets/BetterCommons/Runtime/Extensions/StyleExtensions.cs b/Assets/BetterCommons/Runtime/Extensions/StyleExtensions.cs index 909a572..ef9a1a4 100644 --- a/Assets/BetterCommons/Runtime/Extensions/StyleExtensions.cs +++ b/Assets/BetterCommons/Runtime/Extensions/StyleExtensions.cs @@ -42,12 +42,39 @@ public static IStyle BackgroundImage(this IStyle self, StyleBackground backgroun return self; } + public static IStyle BorderTopColor(this IStyle self, StyleColor borderTopColor) + { + self.borderTopColor = borderTopColor; + return self; + } + public static IStyle BorderBottomColor(this IStyle self, StyleColor borderBottomColor) { self.borderBottomColor = borderBottomColor; return self; } + public static IStyle BorderLeftColor(this IStyle self, StyleColor borderLeftColor) + { + self.borderLeftColor = borderLeftColor; + return self; + } + + public static IStyle BorderRightColor(this IStyle self, StyleColor borderRightColor) + { + self.borderRightColor = borderRightColor; + return self; + } + + public static IStyle BorderColor(this IStyle self, StyleColor borderColor) + { + self.borderTopColor = borderColor; + self.borderLeftColor = borderColor; + self.borderRightColor = borderColor; + self.borderBottomColor = borderColor; + return self; + } + public static IStyle BorderBottomLeftRadius(this IStyle self, StyleLength borderBottomLeftRadius) { self.borderBottomLeftRadius = borderBottomLeftRadius; @@ -75,36 +102,18 @@ public static IStyle BorderWidth(this IStyle self, StyleFloat width) return self; } - public static IStyle BorderLeftColor(this IStyle self, StyleColor borderLeftColor) - { - self.borderLeftColor = borderLeftColor; - return self; - } - public static IStyle BorderLeftWidth(this IStyle self, StyleFloat borderLeftWidth) { self.borderLeftWidth = borderLeftWidth; return self; } - public static IStyle BorderRightColor(this IStyle self, StyleColor borderRightColor) - { - self.borderRightColor = borderRightColor; - return self; - } - public static IStyle BorderRightWidth(this IStyle self, StyleFloat borderRightWidth) { self.borderRightWidth = borderRightWidth; return self; } - public static IStyle BorderTopColor(this IStyle self, StyleColor borderTopColor) - { - self.borderTopColor = borderTopColor; - return self; - } - public static IStyle BorderTopLeftRadius(this IStyle self, StyleLength borderTopLeftRadius) { self.borderTopLeftRadius = borderTopLeftRadius; diff --git a/Assets/BetterCommons/Runtime/Extensions/TypeExtensions.cs b/Assets/BetterCommons/Runtime/Extensions/TypeExtensions.cs index 54d05ca..24d280c 100644 --- a/Assets/BetterCommons/Runtime/Extensions/TypeExtensions.cs +++ b/Assets/BetterCommons/Runtime/Extensions/TypeExtensions.cs @@ -122,5 +122,10 @@ public static MemberInfo GetMemberByNameRecursive(this Type type, string memberN { return ReflectionUtility.GetMemberByNameRecursive(type, memberName); } + + public static IEnumerable GetMembersByNameRecursive(this Type type, string memberName) + { + return ReflectionUtility.GetMembersByNameRecursive(type, memberName); + } } } \ No newline at end of file diff --git a/Assets/BetterCommons/Runtime/UIElements.meta b/Assets/BetterCommons/Runtime/UIElements.meta new file mode 100644 index 0000000..8c5e621 --- /dev/null +++ b/Assets/BetterCommons/Runtime/UIElements.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5a48b7e6fc7948079d3e0b49f422c5dd +timeCreated: 1728247193 \ No newline at end of file diff --git a/Assets/BetterCommons/Runtime/UIElements/ToggleButton.cs b/Assets/BetterCommons/Runtime/UIElements/ToggleButton.cs new file mode 100644 index 0000000..204a3b6 --- /dev/null +++ b/Assets/BetterCommons/Runtime/UIElements/ToggleButton.cs @@ -0,0 +1,38 @@ +using System; +using UnityEngine.UIElements; + +namespace Better.Commons.Runtime.UIElements +{ + public class ToggleButton : Button + { + public event Action Toggled; + + private bool _toggled; + + public ToggleButton(Action clickEvent, Action toggleEvent, bool defaultState = false) : base(clickEvent) + { + clicked += OnClicked; + Toggled = toggleEvent; + SetToggled(defaultState); + } + + public ToggleButton(Action toggled, bool defaultState = false) : this(null, toggled, defaultState) + { + } + + public ToggleButton(bool defaultState = false) : this(null, defaultState) + { + } + + private void OnClicked() + { + SetToggled(!_toggled); + } + + private void SetToggled(bool toggled) + { + _toggled = toggled; + Toggled?.Invoke(_toggled); + } + } +} \ No newline at end of file diff --git a/Assets/BetterCommons/Runtime/UIElements/ToggleButton.cs.meta b/Assets/BetterCommons/Runtime/UIElements/ToggleButton.cs.meta new file mode 100644 index 0000000..4646cc6 --- /dev/null +++ b/Assets/BetterCommons/Runtime/UIElements/ToggleButton.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a052914540f84e1aa8d448fc18eb92d8 +timeCreated: 1728198074 \ No newline at end of file diff --git a/Assets/BetterCommons/Runtime/Utility/ReflectionUtility.cs b/Assets/BetterCommons/Runtime/Utility/ReflectionUtility.cs index 1c60473..3bcc160 100644 --- a/Assets/BetterCommons/Runtime/Utility/ReflectionUtility.cs +++ b/Assets/BetterCommons/Runtime/Utility/ReflectionUtility.cs @@ -399,32 +399,34 @@ private static MemberInfo ConvertToConstructedGenericType(MemberInfo memberInfo, return members.FirstOrDefault(); } - // Return the original memberInfo if it's not a property of a generic type definition or doesn't need to be constructed return memberInfo; } public static MemberInfo GetMemberByNameRecursive(Type type, string memberName) + { + return GetMembersByNameRecursive(type, memberName).FirstOrDefault(m => m.Name == memberName); + } + + public static IEnumerable GetMembersByNameRecursive(Type type, string memberName) { if (type == null) { DebugUtility.LogException(nameof(type)); - return null; + return Enumerable.Empty(); } if (string.IsNullOrEmpty(memberName)) { DebugUtility.LogException(nameof(memberName)); - return null; + return Enumerable.Empty();; } var allMembers = GetMembersRecursive(type); - // Use LINQ to find the member by name. This assumes you want the first match if there are multiple members with the same name (overloads). - // If you expect overloads and want to handle them differently, you might need a more complex approach. - return allMembers.FirstOrDefault(m => m.Name == memberName); + return allMembers.Where(m => m.Name == memberName); } - - public static object GetValueFromInstanceMember(object instance, string memberName) + + public static object GetValueFromInstanceMember(string memberName, object instance, object[] parameters) { if (instance == null) { @@ -440,7 +442,8 @@ public static object GetValueFromInstanceMember(object instance, string memberNa var type = instance.GetType(); var member = GetMemberByNameRecursive(type, memberName); - if (TryGetValue(member, instance, out var value)) + + if (TryGetValue(member, instance, parameters, out var value)) { return value; } @@ -463,15 +466,15 @@ public static object GetValueFromStaticMember(Type type, string memberName) } var member = GetMemberByNameRecursive(type, memberName); - if (TryGetValue(member, null, out var value)) + if (TryGetValue(member, null, Array.Empty(), out var value)) { return value; } return null; } - - private static bool TryGetValue(MemberInfo memberInfo, object instance, out object value) + + private static bool TryGetValue(MemberInfo memberInfo, object instance, object[] parameters, out object value) { if (memberInfo is PropertyInfo propertyInfo) { @@ -487,7 +490,7 @@ private static bool TryGetValue(MemberInfo memberInfo, object instance, out obje if (memberInfo is MethodInfo methodInfo) { - value = methodInfo.Invoke(instance, Array.Empty()); + value = methodInfo.Invoke(instance, parameters); return true; } diff --git a/Assets/BetterCommons/package.json b/Assets/BetterCommons/package.json index 8393767..fd2ce6a 100644 --- a/Assets/BetterCommons/package.json +++ b/Assets/BetterCommons/package.json @@ -1,7 +1,7 @@ { "name": "com.tdw.better.commons", "displayName": "Better Commons", - "version": "0.0.56", + "version": "0.0.57", "unity": "2021.3", "description": " ", "dependencies": {