From 02fb8a98409afd296f1e430d6dc1988352e5262b Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Sat, 9 Jul 2022 14:59:12 -0400 Subject: [PATCH 01/16] Update SerializableInterfacePropertyDrawer.cs This fixes the issue #19 --- Editor/SerializableInterfacePropertyDrawer.cs | 50 +++++++++++++++++-- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/Editor/SerializableInterfacePropertyDrawer.cs b/Editor/SerializableInterfacePropertyDrawer.cs index 7ce4953..dd55a1c 100644 --- a/Editor/SerializableInterfacePropertyDrawer.cs +++ b/Editor/SerializableInterfacePropertyDrawer.cs @@ -10,7 +10,11 @@ namespace TNRD [CustomPropertyDrawer(typeof(SerializableInterface<>), true)] internal sealed class SerializableInterfacePropertyDrawer : PropertyDrawer { + private const string k_RawReference = "rawReference"; + private SerializedProperty serializedProperty; + private object previousReferenceValue; + private string lastPropertyPath; private Type genericType; private IReferenceDrawer activeDrawer; @@ -23,15 +27,47 @@ public override bool CanCacheInspectorGUI(SerializedProperty property) private void Initialize(SerializedProperty property) { - if (serializedProperty == property) - return; - - activeDrawer = null; serializedProperty = property; + activeDrawer = null; genericType = GetGenericArgument(); + Assert.IsNotNull(genericType, "Unable to find generic argument, are you doing some shady inheritance?"); } + /// + /// Avoids an unexpected behaviour + /// + private void AvoidDuplicateReferences(SerializedProperty property) + { + if (!IsTargetObjectArray(property)) return; // This function + if (lastPropertyPath == null) return; + if (lastPropertyPath == property.propertyPath) return; // only one element + + var rawReferenceProperty = property.FindPropertyRelative(k_RawReference); // Cache property + var currentReferenceValue = rawReferenceProperty.managedReferenceValue; + + if (currentReferenceValue == null) return; // Value is null. Probably new or not set yet + + if (previousReferenceValue == currentReferenceValue) + { + // The best behaviour would be to create a shallow copy. The extension method from SolidUtilities works perfectly. + // Using serialization or reflection might also work + var instance = Activator.CreateInstance(currentReferenceValue.GetType()); + rawReferenceProperty.managedReferenceValue = instance; + + // propertyRelative.managedReferenceValue = currentReferenceValue.ShallowCopy(); + } + + previousReferenceValue = currentReferenceValue; + } + + + private static bool IsTargetObjectArray(SerializedProperty prop) + { + return prop.propertyPath.Contains(".Array.data["); + } + + /// public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { @@ -44,8 +80,12 @@ public override float GetPropertyHeight(SerializedProperty property, GUIContent public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { Initialize(property); + AvoidDuplicateReferences(property); + activeDrawer = GetReferenceDrawer(activeDrawer, property, label); activeDrawer.OnGUI(position); + + lastPropertyPath = property.propertyPath; } private Type GetGenericArgument() @@ -108,4 +148,4 @@ GUIContent label } } } -} +} \ No newline at end of file From c69d2e1b2367e59095ae326b02ce00767be54682 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Sat, 9 Jul 2022 17:32:31 -0400 Subject: [PATCH 02/16] Clean up SerializableInterfacePropertyDrawer.cs --- Editor/SerializableInterfacePropertyDrawer.cs | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Editor/SerializableInterfacePropertyDrawer.cs b/Editor/SerializableInterfacePropertyDrawer.cs index dd55a1c..68b82a8 100644 --- a/Editor/SerializableInterfacePropertyDrawer.cs +++ b/Editor/SerializableInterfacePropertyDrawer.cs @@ -10,24 +10,23 @@ namespace TNRD [CustomPropertyDrawer(typeof(SerializableInterface<>), true)] internal sealed class SerializableInterfacePropertyDrawer : PropertyDrawer { - private const string k_RawReference = "rawReference"; + private const string RAW_REFERENCE = "rawReference"; + private const string MODE = "mode"; - private SerializedProperty serializedProperty; - private object previousReferenceValue; - private string lastPropertyPath; private Type genericType; - private IReferenceDrawer activeDrawer; + private object previousReferenceValue; + private string previousPropertyPath; + /// public override bool CanCacheInspectorGUI(SerializedProperty property) { return false; } - private void Initialize(SerializedProperty property) + private void Initialize() { - serializedProperty = property; activeDrawer = null; genericType = GetGenericArgument(); @@ -35,34 +34,35 @@ private void Initialize(SerializedProperty property) } /// - /// Avoids an unexpected behaviour + /// When a new instance of is added in an array using the inspector's gizmo, + /// avoids having their field reference the same instance. /// - private void AvoidDuplicateReferences(SerializedProperty property) + /// The SerializedProperty to make the custom GUI for. + private void AvoidDuplicateReferencesInArray(SerializedProperty property) { - if (!IsTargetObjectArray(property)) return; // This function - if (lastPropertyPath == null) return; - if (lastPropertyPath == property.propertyPath) return; // only one element + if (!IsPropertyInArray(property)) return; + if (previousPropertyPath == null) return; + if (previousPropertyPath == property.propertyPath) return; - var rawReferenceProperty = property.FindPropertyRelative(k_RawReference); // Cache property + var rawReferenceProperty = property.FindPropertyRelative(RAW_REFERENCE); var currentReferenceValue = rawReferenceProperty.managedReferenceValue; - if (currentReferenceValue == null) return; // Value is null. Probably new or not set yet + if (currentReferenceValue == null) return; if (previousReferenceValue == currentReferenceValue) - { - // The best behaviour would be to create a shallow copy. The extension method from SolidUtilities works perfectly. - // Using serialization or reflection might also work - var instance = Activator.CreateInstance(currentReferenceValue.GetType()); - rawReferenceProperty.managedReferenceValue = instance; - - // propertyRelative.managedReferenceValue = currentReferenceValue.ShallowCopy(); - } + rawReferenceProperty.managedReferenceValue = CreateInstance(currentReferenceValue); previousReferenceValue = currentReferenceValue; } + private static object CreateInstance(object source) + { + var instance = Activator.CreateInstance(source.GetType()); + EditorUtility.CopySerializedManagedFieldsOnly(source, instance); + return instance; + } - private static bool IsTargetObjectArray(SerializedProperty prop) + private static bool IsPropertyInArray(SerializedProperty prop) { return prop.propertyPath.Contains(".Array.data["); } @@ -71,7 +71,7 @@ private static bool IsTargetObjectArray(SerializedProperty prop) /// public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { - Initialize(property); + Initialize(); activeDrawer = GetReferenceDrawer(activeDrawer, property, label); return activeDrawer.GetHeight(); } @@ -79,13 +79,13 @@ public override float GetPropertyHeight(SerializedProperty property, GUIContent /// public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { - Initialize(property); - AvoidDuplicateReferences(property); + Initialize(); + AvoidDuplicateReferencesInArray(property); activeDrawer = GetReferenceDrawer(activeDrawer, property, label); activeDrawer.OnGUI(position); - lastPropertyPath = property.propertyPath; + previousPropertyPath = property.propertyPath; } private Type GetGenericArgument() @@ -130,7 +130,7 @@ private IReferenceDrawer GetReferenceDrawer( GUIContent label ) { - SerializedProperty modeProperty = serializedProperty.FindPropertyRelative("mode"); + SerializedProperty modeProperty = property.FindPropertyRelative(MODE); ReferenceMode referenceMode = (ReferenceMode)modeProperty.enumValueIndex; switch (referenceMode) From ba10941d3a3fdc57e107592de57e70f39058568c Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Sat, 9 Jul 2022 17:53:02 -0400 Subject: [PATCH 03/16] Update SerializableInterfacePropertyDrawer.cs --- Editor/SerializableInterfacePropertyDrawer.cs | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/Editor/SerializableInterfacePropertyDrawer.cs b/Editor/SerializableInterfacePropertyDrawer.cs index 68b82a8..8e37d3c 100644 --- a/Editor/SerializableInterfacePropertyDrawer.cs +++ b/Editor/SerializableInterfacePropertyDrawer.cs @@ -13,26 +13,48 @@ internal sealed class SerializableInterfacePropertyDrawer : PropertyDrawer private const string RAW_REFERENCE = "rawReference"; private const string MODE = "mode"; + private SerializedProperty serializedProperty; private Type genericType; + private IReferenceDrawer activeDrawer; private object previousReferenceValue; private string previousPropertyPath; /// - public override bool CanCacheInspectorGUI(SerializedProperty property) - { - return false; - } + public override bool CanCacheInspectorGUI(SerializedProperty property) => false; - private void Initialize() + private void Initialize(SerializedProperty property) { + if (serializedProperty == property) + return; + activeDrawer = null; + serializedProperty = property; genericType = GetGenericArgument(); Assert.IsNotNull(genericType, "Unable to find generic argument, are you doing some shady inheritance?"); } + /// + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + Initialize(property); + activeDrawer = GetReferenceDrawer(activeDrawer, property, label); + return activeDrawer.GetHeight(); + } + + /// + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + Initialize(property); + AvoidDuplicateReferencesInArray(property); + + activeDrawer = GetReferenceDrawer(activeDrawer, property, label); + activeDrawer.OnGUI(position); + previousPropertyPath = property.propertyPath; + } + /// /// When a new instance of is added in an array using the inspector's gizmo, /// avoids having their field reference the same instance. @@ -50,42 +72,24 @@ private void AvoidDuplicateReferencesInArray(SerializedProperty property) if (currentReferenceValue == null) return; if (previousReferenceValue == currentReferenceValue) + { rawReferenceProperty.managedReferenceValue = CreateInstance(currentReferenceValue); + rawReferenceProperty.serializedObject.ApplyModifiedProperties(); + } previousReferenceValue = currentReferenceValue; } - - private static object CreateInstance(object source) - { - var instance = Activator.CreateInstance(source.GetType()); - EditorUtility.CopySerializedManagedFieldsOnly(source, instance); - return instance; - } - + private static bool IsPropertyInArray(SerializedProperty prop) { return prop.propertyPath.Contains(".Array.data["); } - - /// - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - Initialize(); - activeDrawer = GetReferenceDrawer(activeDrawer, property, label); - return activeDrawer.GetHeight(); - } - - /// - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + private static object CreateInstance(object source) { - Initialize(); - AvoidDuplicateReferencesInArray(property); - - activeDrawer = GetReferenceDrawer(activeDrawer, property, label); - activeDrawer.OnGUI(position); - - previousPropertyPath = property.propertyPath; + var instance = Activator.CreateInstance(source.GetType()); + EditorUtility.CopySerializedManagedFieldsOnly(source, instance); + return instance; } private Type GetGenericArgument() From d6e8d0be6b30237a99748d8b3dd6b38cae10eeff Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Sat, 9 Jul 2022 17:57:46 -0400 Subject: [PATCH 04/16] Update SerializableInterfacePropertyDrawer.cs removed unnecessary change --- Editor/SerializableInterfacePropertyDrawer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/SerializableInterfacePropertyDrawer.cs b/Editor/SerializableInterfacePropertyDrawer.cs index 8e37d3c..13502ff 100644 --- a/Editor/SerializableInterfacePropertyDrawer.cs +++ b/Editor/SerializableInterfacePropertyDrawer.cs @@ -134,7 +134,7 @@ private IReferenceDrawer GetReferenceDrawer( GUIContent label ) { - SerializedProperty modeProperty = property.FindPropertyRelative(MODE); + SerializedProperty modeProperty = serializedProperty.FindPropertyRelative(MODE); ReferenceMode referenceMode = (ReferenceMode)modeProperty.enumValueIndex; switch (referenceMode) From ae0f89febc17a440992be3b0eb8a1489c35215af Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Sat, 9 Jul 2022 19:10:52 -0400 Subject: [PATCH 05/16] Moved changes to RawReferenceDrawer Since it only applies to SerializableInterfaces in Raw mode, it made more sense to only do it in RawReferenceDrawer instead of SerializableInterfacePropertyDrawer. Tested the same way, no apparent diff. --- Editor/Drawers/RawReferenceDrawer.cs | 50 ++++++++++++++++++- Editor/SerializableInterfacePropertyDrawer.cs | 48 +----------------- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/Editor/Drawers/RawReferenceDrawer.cs b/Editor/Drawers/RawReferenceDrawer.cs index 72fa6e7..a84752b 100644 --- a/Editor/Drawers/RawReferenceDrawer.cs +++ b/Editor/Drawers/RawReferenceDrawer.cs @@ -11,6 +11,9 @@ internal class RawReferenceDrawer : ReferenceDrawer, IReferenceDrawer private readonly GUIContent label; private readonly FieldInfo fieldInfo; + private static object previousReferenceValue; + private static string previousPropertyPath; + private object RawReferenceValue { get @@ -21,6 +24,15 @@ private object RawReferenceValue ISerializableInterface instance = (ISerializableInterface)fieldInfo.GetValue(Property.serializedObject.targetObject); return instance.GetRawReference(); +#endif + } + + set + { +#if UNITY_2021_1_OR_NEWER + RawReferenceProperty.managedReferenceValue = value; +#else + fieldInfo.SetValue(Property.serializedObject.targetObject, value); #endif } } @@ -47,6 +59,8 @@ public float GetHeight() /// public void OnGUI(Rect position) { + AvoidDuplicateReferencesInArray(); + Rect objectFieldRect = new Rect(position) { height = EditorGUIUtility.singleLineHeight @@ -71,6 +85,8 @@ public void OnGUI(Rect position) true); HandleDragAndDrop(objectFieldRect); + + previousPropertyPath = Property.propertyPath; } /// @@ -91,5 +107,37 @@ protected override void OnPropertiesClicked() } } } + + private void AvoidDuplicateReferencesInArray() + { + if (!IsPropertyInArray(Property)) return; + if (previousPropertyPath == null) return; + if (previousPropertyPath == Property.propertyPath) return; + + var rawReferenceProperty = Property.FindPropertyRelative("rawReference"); + var currentReferenceValue = RawReferenceValue; + + if (currentReferenceValue == null) return; + + if (previousReferenceValue == currentReferenceValue) + { + rawReferenceProperty.managedReferenceValue = CreateInstance(currentReferenceValue); + rawReferenceProperty.serializedObject.ApplyModifiedProperties(); + } + + previousReferenceValue = currentReferenceValue; + } + + private static bool IsPropertyInArray(SerializedProperty prop) + { + return prop.propertyPath.Contains(".Array.data["); + } + + private static object CreateInstance(object source) + { + var instance = Activator.CreateInstance(source.GetType()); + EditorUtility.CopySerializedManagedFieldsOnly(source, instance); + return instance; + } } -} +} \ No newline at end of file diff --git a/Editor/SerializableInterfacePropertyDrawer.cs b/Editor/SerializableInterfacePropertyDrawer.cs index 13502ff..1d23d42 100644 --- a/Editor/SerializableInterfacePropertyDrawer.cs +++ b/Editor/SerializableInterfacePropertyDrawer.cs @@ -10,17 +10,11 @@ namespace TNRD [CustomPropertyDrawer(typeof(SerializableInterface<>), true)] internal sealed class SerializableInterfacePropertyDrawer : PropertyDrawer { - private const string RAW_REFERENCE = "rawReference"; - private const string MODE = "mode"; - private SerializedProperty serializedProperty; private Type genericType; private IReferenceDrawer activeDrawer; - private object previousReferenceValue; - private string previousPropertyPath; - /// public override bool CanCacheInspectorGUI(SerializedProperty property) => false; @@ -48,48 +42,8 @@ public override float GetPropertyHeight(SerializedProperty property, GUIContent public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { Initialize(property); - AvoidDuplicateReferencesInArray(property); - activeDrawer = GetReferenceDrawer(activeDrawer, property, label); activeDrawer.OnGUI(position); - previousPropertyPath = property.propertyPath; - } - - /// - /// When a new instance of is added in an array using the inspector's gizmo, - /// avoids having their field reference the same instance. - /// - /// The SerializedProperty to make the custom GUI for. - private void AvoidDuplicateReferencesInArray(SerializedProperty property) - { - if (!IsPropertyInArray(property)) return; - if (previousPropertyPath == null) return; - if (previousPropertyPath == property.propertyPath) return; - - var rawReferenceProperty = property.FindPropertyRelative(RAW_REFERENCE); - var currentReferenceValue = rawReferenceProperty.managedReferenceValue; - - if (currentReferenceValue == null) return; - - if (previousReferenceValue == currentReferenceValue) - { - rawReferenceProperty.managedReferenceValue = CreateInstance(currentReferenceValue); - rawReferenceProperty.serializedObject.ApplyModifiedProperties(); - } - - previousReferenceValue = currentReferenceValue; - } - - private static bool IsPropertyInArray(SerializedProperty prop) - { - return prop.propertyPath.Contains(".Array.data["); - } - - private static object CreateInstance(object source) - { - var instance = Activator.CreateInstance(source.GetType()); - EditorUtility.CopySerializedManagedFieldsOnly(source, instance); - return instance; } private Type GetGenericArgument() @@ -134,7 +88,7 @@ private IReferenceDrawer GetReferenceDrawer( GUIContent label ) { - SerializedProperty modeProperty = serializedProperty.FindPropertyRelative(MODE); + SerializedProperty modeProperty = serializedProperty.FindPropertyRelative("mode"); ReferenceMode referenceMode = (ReferenceMode)modeProperty.enumValueIndex; switch (referenceMode) From 0a43f4e4ed76fa42421a7cdfbe22e069f091cc26 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Sat, 9 Jul 2022 19:19:54 -0400 Subject: [PATCH 06/16] Forgot a managedReferenceValue Would only work in UNITY_2021_1_OR_NEWER otherwise --- Editor/Drawers/RawReferenceDrawer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/Drawers/RawReferenceDrawer.cs b/Editor/Drawers/RawReferenceDrawer.cs index a84752b..3f2ce5b 100644 --- a/Editor/Drawers/RawReferenceDrawer.cs +++ b/Editor/Drawers/RawReferenceDrawer.cs @@ -121,7 +121,7 @@ private void AvoidDuplicateReferencesInArray() if (previousReferenceValue == currentReferenceValue) { - rawReferenceProperty.managedReferenceValue = CreateInstance(currentReferenceValue); + RawReferenceValue = CreateInstance(currentReferenceValue); rawReferenceProperty.serializedObject.ApplyModifiedProperties(); } From 9fd9c1898f1522342aa3454882ee9936ef292cf4 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Sun, 10 Jul 2022 17:56:40 -0400 Subject: [PATCH 07/16] Added changes requested --- Editor/Drawers/RawReferenceDrawer.cs | 20 +++++++++++-------- Editor/SerializableInterfacePropertyDrawer.cs | 3 +-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Editor/Drawers/RawReferenceDrawer.cs b/Editor/Drawers/RawReferenceDrawer.cs index 3f2ce5b..c11b9bf 100644 --- a/Editor/Drawers/RawReferenceDrawer.cs +++ b/Editor/Drawers/RawReferenceDrawer.cs @@ -110,14 +110,18 @@ protected override void OnPropertiesClicked() private void AvoidDuplicateReferencesInArray() { - if (!IsPropertyInArray(Property)) return; - if (previousPropertyPath == null) return; - if (previousPropertyPath == Property.propertyPath) return; + if (!IsPropertyInArray(Property)) + return; + if (previousPropertyPath == null) + return; + if (previousPropertyPath == Property.propertyPath) + return; - var rawReferenceProperty = Property.FindPropertyRelative("rawReference"); - var currentReferenceValue = RawReferenceValue; + SerializedProperty rawReferenceProperty = Property.FindPropertyRelative("rawReference"); + object currentReferenceValue = RawReferenceValue; - if (currentReferenceValue == null) return; + if (currentReferenceValue == null) + return; if (previousReferenceValue == currentReferenceValue) { @@ -135,9 +139,9 @@ private static bool IsPropertyInArray(SerializedProperty prop) private static object CreateInstance(object source) { - var instance = Activator.CreateInstance(source.GetType()); + object instance = Activator.CreateInstance(source.GetType()); EditorUtility.CopySerializedManagedFieldsOnly(source, instance); return instance; } } -} \ No newline at end of file +} diff --git a/Editor/SerializableInterfacePropertyDrawer.cs b/Editor/SerializableInterfacePropertyDrawer.cs index 1d23d42..e71019a 100644 --- a/Editor/SerializableInterfacePropertyDrawer.cs +++ b/Editor/SerializableInterfacePropertyDrawer.cs @@ -26,7 +26,6 @@ private void Initialize(SerializedProperty property) activeDrawer = null; serializedProperty = property; genericType = GetGenericArgument(); - Assert.IsNotNull(genericType, "Unable to find generic argument, are you doing some shady inheritance?"); } @@ -106,4 +105,4 @@ GUIContent label } } } -} \ No newline at end of file +} From 8730e50c6d91de72e09d6d1dabef9369770af979 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Sun, 10 Jul 2022 22:06:34 -0400 Subject: [PATCH 08/16] Added null check in RawReferenceDrawer --- Editor/Drawers/RawReferenceDrawer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Editor/Drawers/RawReferenceDrawer.cs b/Editor/Drawers/RawReferenceDrawer.cs index 72fa6e7..4337c3c 100644 --- a/Editor/Drawers/RawReferenceDrawer.cs +++ b/Editor/Drawers/RawReferenceDrawer.cs @@ -76,6 +76,9 @@ public void OnGUI(Rect position) /// protected override void OnPropertiesClicked() { + if (RawReferenceValue == null) + return; + Type type = RawReferenceValue.GetType(); string typeName = type.Name; From 5b8bc589349967225e01616dd1a5805154c06ed2 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Mon, 11 Jul 2022 18:42:30 -0400 Subject: [PATCH 09/16] Added NoneDropdownItem --- Editor/Drawers/CustomObjectDrawer.cs | 1 + Editor/Items/NoneDropdownItem.cs | 17 +++++++++++++++++ Editor/Items/NoneDropdownItem.cs.meta | 3 +++ .../SerializableInterfaceAdvancedDropdown.cs | 12 +++++++++++- 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 Editor/Items/NoneDropdownItem.cs create mode 100644 Editor/Items/NoneDropdownItem.cs.meta diff --git a/Editor/Drawers/CustomObjectDrawer.cs b/Editor/Drawers/CustomObjectDrawer.cs index b1931f2..5b6b27e 100644 --- a/Editor/Drawers/CustomObjectDrawer.cs +++ b/Editor/Drawers/CustomObjectDrawer.cs @@ -94,6 +94,7 @@ private void HandleMouseDown(Rect position, Rect positionWithoutThumb) else if (Event.button == 1 && positionWithoutThumb.Contains(Event.mousePosition)) { GenericMenu menu = new GenericMenu(); + menu.AddItem(new GUIContent("Clear"), false, () => { DeletePressed?.Invoke(); }); menu.AddItem(new GUIContent("Properties..."), false, () => { PropertiesClicked?.Invoke(); }); menu.DropDown(position); Event.Use(); diff --git a/Editor/Items/NoneDropdownItem.cs b/Editor/Items/NoneDropdownItem.cs new file mode 100644 index 0000000..454745c --- /dev/null +++ b/Editor/Items/NoneDropdownItem.cs @@ -0,0 +1,17 @@ +using UnityEditor.IMGUI.Controls; + +namespace TNRD.Items +{ + public class NoneDropdownItem : AdvancedDropdownItem, IDropdownItem + { + private ReferenceMode mode => ReferenceMode.Raw; + public NoneDropdownItem() : base("None") { } + + ReferenceMode IDropdownItem.Mode => mode; + + public object GetValue() + { + return default; + } + } +} \ No newline at end of file diff --git a/Editor/Items/NoneDropdownItem.cs.meta b/Editor/Items/NoneDropdownItem.cs.meta new file mode 100644 index 0000000..2813776 --- /dev/null +++ b/Editor/Items/NoneDropdownItem.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a7015062205d46cbb9cb01b0b88fff55 +timeCreated: 1657572673 \ No newline at end of file diff --git a/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs b/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs index af82ecd..5210503 100644 --- a/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs +++ b/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs @@ -48,6 +48,11 @@ protected override AdvancedDropdownItem BuildRoot() .AddChild(new ClassesItemBuilder(interfaceType).Build()) .AddChild(new SceneItemBuilder(interfaceType, relevantScene).Build()); + foreach (var dropdownItem in item.children) + { + dropdownItem.AddChild(new NoneDropdownItem()); + } + if (canSort) { sortChildrenMethod.Invoke(item, @@ -56,12 +61,17 @@ protected override AdvancedDropdownItem BuildRoot() (Comparison)Sort, true }); } - return item; } private int Sort(AdvancedDropdownItem a, AdvancedDropdownItem b) { + // For aesthetic reasons. Always puts the None first + if (a is NoneDropdownItem) + return -1; + if (b is NoneDropdownItem) + return 1; + int childrenA = a.children.Count(); int childrenB = b.children.Count(); From 4f98193b061b89a8af59a72eacfc11740fdf445c Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Mon, 11 Jul 2022 19:29:09 -0400 Subject: [PATCH 10/16] Small cleanup before PR --- Editor/Items/NoneDropdownItem.cs | 4 ++-- Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Editor/Items/NoneDropdownItem.cs b/Editor/Items/NoneDropdownItem.cs index 454745c..ca05cdc 100644 --- a/Editor/Items/NoneDropdownItem.cs +++ b/Editor/Items/NoneDropdownItem.cs @@ -11,7 +11,7 @@ public NoneDropdownItem() : base("None") { } public object GetValue() { - return default; + return null; } } -} \ No newline at end of file +} diff --git a/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs b/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs index 5210503..a485c08 100644 --- a/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs +++ b/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs @@ -61,6 +61,7 @@ protected override AdvancedDropdownItem BuildRoot() (Comparison)Sort, true }); } + return item; } From 17040d07e8ba69247e55dd5adca658813d43635a Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Tue, 12 Jul 2022 14:12:45 -0400 Subject: [PATCH 11/16] Added proper properties in ReferenceDrawer.cs --- Editor/Drawers/RawReferenceDrawer.cs | 23 +--- Editor/Drawers/ReferenceDrawer.cs | 109 ++++++++++++------ Editor/Drawers/UnityReferenceDrawer.cs | 10 +- Editor/SerializableInterfacePropertyDrawer.cs | 2 +- 4 files changed, 89 insertions(+), 55 deletions(-) diff --git a/Editor/Drawers/RawReferenceDrawer.cs b/Editor/Drawers/RawReferenceDrawer.cs index 72fa6e7..5251d15 100644 --- a/Editor/Drawers/RawReferenceDrawer.cs +++ b/Editor/Drawers/RawReferenceDrawer.cs @@ -9,28 +9,12 @@ namespace TNRD.Drawers internal class RawReferenceDrawer : ReferenceDrawer, IReferenceDrawer { private readonly GUIContent label; - private readonly FieldInfo fieldInfo; - - private object RawReferenceValue - { - get - { -#if UNITY_2021_1_OR_NEWER - return RawReferenceProperty.managedReferenceValue; -#else - ISerializableInterface instance = - (ISerializableInterface)fieldInfo.GetValue(Property.serializedObject.targetObject); - return instance.GetRawReference(); -#endif - } - } /// public RawReferenceDrawer(SerializedProperty property, GUIContent label, Type genericType, FieldInfo fieldInfo) - : base(property, genericType) + : base(property, genericType, fieldInfo) { this.label = label; - this.fieldInfo = fieldInfo; } /// @@ -73,6 +57,11 @@ public void OnGUI(Rect position) HandleDragAndDrop(objectFieldRect); } + protected override void PingObject() + { + // No support for pinging raw objects for now (I guess this would ping the MonoScript?) + } + /// protected override void OnPropertiesClicked() { diff --git a/Editor/Drawers/ReferenceDrawer.cs b/Editor/Drawers/ReferenceDrawer.cs index 984dc05..a2dff79 100644 --- a/Editor/Drawers/ReferenceDrawer.cs +++ b/Editor/Drawers/ReferenceDrawer.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Reflection; using TNRD.Utilities; using UnityEditor; using UnityEditor.IMGUI.Controls; @@ -29,10 +30,72 @@ private enum DragAndDropMode protected SerializedProperty RawReferenceProperty => Property.FindPropertyRelative("rawReference"); protected SerializedProperty UnityReferenceProperty => Property.FindPropertyRelative("unityReference"); - protected ReferenceDrawer(SerializedProperty property, Type genericType) + protected readonly FieldInfo fieldInfo; + + protected ReferenceMode ModeValue + { + get => (ReferenceMode)ReferenceModeProperty.enumValueIndex; + set => ReferenceModeProperty.enumValueIndex = (int)value; + } + + protected object RawReferenceValue + { + get + { +#if UNITY_2021_1_OR_NEWER + return RawReferenceProperty.managedReferenceValue; +#else + ISerializableInterface instance = + (ISerializableInterface)fieldInfo.GetValue(Property.serializedObject.targetObject); + return instance.GetRawReference(); +#endif + } + set + { +#if UNITY_2021_1_OR_NEWER + RawReferenceProperty.managedReferenceValue = value; +#else + fieldInfo.SetValue(Property.serializedObject.targetObject, value); +#endif + } + } + + protected object PropertyValue + { + get + { + return ModeValue switch + { + ReferenceMode.Raw => RawReferenceValue, + ReferenceMode.Unity => UnityReferenceProperty.objectReferenceValue, + _ => throw new ArgumentOutOfRangeException() + }; + } + set + { + switch (ModeValue) + { + case ReferenceMode.Raw: + RawReferenceValue = value; + UnityReferenceProperty.objectReferenceValue = null; + break; + case ReferenceMode.Unity: + UnityReferenceProperty.objectReferenceValue = (Object)value; + RawReferenceValue = null; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + Property.serializedObject.ApplyModifiedProperties(); + } + } + + protected ReferenceDrawer(SerializedProperty property, Type genericType, FieldInfo fieldInfo) { Property = property; GenericType = genericType; + this.fieldInfo = fieldInfo; CustomObjectDrawer = new CustomObjectDrawer(); CustomObjectDrawer.ButtonClicked += OnButtonClicked; @@ -66,43 +129,18 @@ private void OnButtonClicked(Rect position) private void OnClicked() { - switch ((ReferenceMode)ReferenceModeProperty.enumValueIndex) - { - case ReferenceMode.Raw: - // No support for pinging raw objects for now (I guess this would ping the MonoScript?) - break; - case ReferenceMode.Unity: - EditorGUIUtility.PingObject(UnityReferenceProperty.objectReferenceValue); - break; - default: - throw new ArgumentOutOfRangeException(); - } + PingObject(); } private void OnDeletePressed() { - RawReferenceProperty.managedReferenceValue = null; - UnityReferenceProperty.objectReferenceValue = null; - Property.serializedObject.ApplyModifiedProperties(); + PropertyValue = null; } private void OnItemSelected(ReferenceMode mode, object reference) { ReferenceModeProperty.enumValueIndex = (int)mode; - - switch (mode) - { - case ReferenceMode.Raw: - RawReferenceProperty.managedReferenceValue = reference; - break; - case ReferenceMode.Unity: - UnityReferenceProperty.objectReferenceValue = (Object)reference; - break; - default: - throw new ArgumentOutOfRangeException(nameof(mode), mode, null); - } - - Property.serializedObject.ApplyModifiedProperties(); + PropertyValue = reference; } protected abstract void OnPropertiesClicked(); @@ -161,7 +199,7 @@ private void HandleDragUpdated(Rect position) SetDragAndDropMode(false); return; } - + if (!GenericType.IsAssignableFrom(scriptType)) { SetDragAndDropMode(false); @@ -182,18 +220,19 @@ private void HandleDragPerform() switch (dragAndDropMode) { case DragAndDropMode.Raw: - RawReferenceProperty.managedReferenceValue = - Activator.CreateInstance(((MonoScript)DragAndDrop.objectReferences[0]).GetClass()); - ReferenceModeProperty.enumValueIndex = (int)ReferenceMode.Raw; + ModeValue = ReferenceMode.Raw; + PropertyValue = Activator.CreateInstance(((MonoScript)DragAndDrop.objectReferences[0]).GetClass()); break; case DragAndDropMode.Unity: - UnityReferenceProperty.objectReferenceValue = DragAndDrop.objectReferences[0]; - ReferenceModeProperty.enumValueIndex = (int)ReferenceMode.Unity; + ModeValue = ReferenceMode.Unity; + PropertyValue = DragAndDrop.objectReferences[0]; break; case DragAndDropMode.None: default: throw new ArgumentOutOfRangeException(); } } + + protected abstract void PingObject(); } } diff --git a/Editor/Drawers/UnityReferenceDrawer.cs b/Editor/Drawers/UnityReferenceDrawer.cs index b409799..8592c49 100644 --- a/Editor/Drawers/UnityReferenceDrawer.cs +++ b/Editor/Drawers/UnityReferenceDrawer.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection; using TNRD.Utilities; using UnityEditor; using UnityEngine; @@ -10,8 +11,8 @@ internal class UnityReferenceDrawer : ReferenceDrawer, IReferenceDrawer { private readonly GUIContent label; - public UnityReferenceDrawer(SerializedProperty property, GUIContent label, Type genericType) - : base(property, genericType) + public UnityReferenceDrawer(SerializedProperty property, GUIContent label, Type genericType, FieldInfo fieldInfo) + : base(property, genericType, fieldInfo) { this.label = label; } @@ -30,6 +31,11 @@ public void OnGUI(Rect position) HandleDragAndDrop(position); } + protected override void PingObject() + { + EditorGUIUtility.PingObject((Object)PropertyValue); + } + protected override void OnPropertiesClicked() { PropertyEditorUtility.Show(UnityReferenceProperty.objectReferenceValue); diff --git a/Editor/SerializableInterfacePropertyDrawer.cs b/Editor/SerializableInterfacePropertyDrawer.cs index 7ce4953..154c1f7 100644 --- a/Editor/SerializableInterfacePropertyDrawer.cs +++ b/Editor/SerializableInterfacePropertyDrawer.cs @@ -102,7 +102,7 @@ GUIContent label case ReferenceMode.Unity: return original is UnityReferenceDrawer ? original - : new UnityReferenceDrawer(property, label, genericType); + : new UnityReferenceDrawer(property, label, genericType, fieldInfo); default: throw new ArgumentOutOfRangeException(); } From 5495d0078d0c6cd852a940f4ecf68694882ee6cc Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Tue, 12 Jul 2022 15:46:47 -0400 Subject: [PATCH 12/16] Fixed Drag and Drop behaviour --- Editor/Drawers/RawReferenceDrawer.cs | 5 +++-- Editor/Drawers/ReferenceDrawer.cs | 11 ++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Editor/Drawers/RawReferenceDrawer.cs b/Editor/Drawers/RawReferenceDrawer.cs index 72fa6e7..2720df3 100644 --- a/Editor/Drawers/RawReferenceDrawer.cs +++ b/Editor/Drawers/RawReferenceDrawer.cs @@ -59,6 +59,9 @@ public void OnGUI(Rect position) : new GUIContent(rawReferenceValue.GetType().Name, IconUtility.ScriptIcon); CustomObjectDrawer.OnGUI(objectFieldRect, label, content); + + HandleDragAndDrop(objectFieldRect); + if (rawReferenceValue == null) return; @@ -69,8 +72,6 @@ public void OnGUI(Rect position) RawReferenceProperty, new GUIContent(rawReferenceValue.GetType().Name), true); - - HandleDragAndDrop(objectFieldRect); } /// diff --git a/Editor/Drawers/ReferenceDrawer.cs b/Editor/Drawers/ReferenceDrawer.cs index 984dc05..81f7d21 100644 --- a/Editor/Drawers/ReferenceDrawer.cs +++ b/Editor/Drawers/ReferenceDrawer.cs @@ -109,13 +109,17 @@ private void OnItemSelected(ReferenceMode mode, object reference) protected void HandleDragAndDrop(Rect position) { + if (!position.Contains(Event.current.mousePosition)) + return; + if (Event.current.type == EventType.DragPerform) { + HandleDragUpdated(); HandleDragPerform(); } else if (Event.current.type == EventType.DragUpdated) { - HandleDragUpdated(position); + HandleDragUpdated(); } } @@ -134,11 +138,8 @@ private void SetDragAndDropMode(bool success, DragAndDropMode? successMode = nul } } - private void HandleDragUpdated(Rect position) + private void HandleDragUpdated() { - if (!position.Contains(Event.current.mousePosition)) - return; - if (DragAndDrop.objectReferences.Length > 1) { SetDragAndDropMode(false); From 693da105b2bb6342d89334a8838a881e2add2c0b Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Tue, 12 Jul 2022 16:09:12 -0400 Subject: [PATCH 13/16] Update RawReferenceDrawer.cs --- Editor/Drawers/RawReferenceDrawer.cs | 30 +--------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/Editor/Drawers/RawReferenceDrawer.cs b/Editor/Drawers/RawReferenceDrawer.cs index 893581f..1c42b30 100644 --- a/Editor/Drawers/RawReferenceDrawer.cs +++ b/Editor/Drawers/RawReferenceDrawer.cs @@ -9,34 +9,10 @@ namespace TNRD.Drawers internal class RawReferenceDrawer : ReferenceDrawer, IReferenceDrawer { private readonly GUIContent label; - private readonly FieldInfo fieldInfo; private static object previousReferenceValue; private static string previousPropertyPath; - private object RawReferenceValue - { - get - { -#if UNITY_2021_1_OR_NEWER - return RawReferenceProperty.managedReferenceValue; -#else - ISerializableInterface instance = - (ISerializableInterface)fieldInfo.GetValue(Property.serializedObject.targetObject); - return instance.GetRawReference(); -#endif - } - - set - { -#if UNITY_2021_1_OR_NEWER - RawReferenceProperty.managedReferenceValue = value; -#else - fieldInfo.SetValue(Property.serializedObject.targetObject, value); -#endif - } - } - /// public RawReferenceDrawer(SerializedProperty property, GUIContent label, Type genericType, FieldInfo fieldInfo) : base(property, genericType, fieldInfo) @@ -125,17 +101,13 @@ private void AvoidDuplicateReferencesInArray() if (previousPropertyPath == Property.propertyPath) return; - SerializedProperty rawReferenceProperty = Property.FindPropertyRelative("rawReference"); object currentReferenceValue = RawReferenceValue; if (currentReferenceValue == null) return; if (previousReferenceValue == currentReferenceValue) - { - RawReferenceValue = CreateInstance(currentReferenceValue); - rawReferenceProperty.serializedObject.ApplyModifiedProperties(); - } + PropertyValue = CreateInstance(currentReferenceValue); previousReferenceValue = currentReferenceValue; } From 64c42a4e1294183f84bb7af7f3ede9662432e89d Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Tue, 12 Jul 2022 18:21:54 -0400 Subject: [PATCH 14/16] Update ReferenceDrawer.cs --- Editor/Drawers/ReferenceDrawer.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Editor/Drawers/ReferenceDrawer.cs b/Editor/Drawers/ReferenceDrawer.cs index 54166d6..44198db 100644 --- a/Editor/Drawers/ReferenceDrawer.cs +++ b/Editor/Drawers/ReferenceDrawer.cs @@ -226,7 +226,7 @@ private void HandleDragPerform() break; case DragAndDropMode.Unity: ModeValue = ReferenceMode.Unity; - PropertyValue = DragAndDrop.objectReferences[0]; + PropertyValue = GetUnityObject(DragAndDrop.objectReferences[0]); break; case DragAndDropMode.None: default: @@ -234,6 +234,13 @@ private void HandleDragPerform() } } + private Object GetUnityObject(Object objectReference) + { + if(objectReference is GameObject gameObject) + return gameObject.GetComponent(GenericType); + return objectReference; + } + protected abstract void PingObject(); } } From 5c4525162ceb18a02db530ac5bc8c4cafaf0e36d Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Tue, 12 Jul 2022 18:35:05 -0400 Subject: [PATCH 15/16] Forgot to set a ModeValue --- Editor/Drawers/ReferenceDrawer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Editor/Drawers/ReferenceDrawer.cs b/Editor/Drawers/ReferenceDrawer.cs index 44198db..823169d 100644 --- a/Editor/Drawers/ReferenceDrawer.cs +++ b/Editor/Drawers/ReferenceDrawer.cs @@ -139,7 +139,7 @@ private void OnDeletePressed() private void OnItemSelected(ReferenceMode mode, object reference) { - ReferenceModeProperty.enumValueIndex = (int)mode; + ModeValue = mode; PropertyValue = reference; } @@ -195,7 +195,7 @@ private void HandleDragUpdated() { Type scriptType = monoScript.GetClass(); - if (scriptType.IsSubclassOf(typeof(UnityEngine.Object))) + if (scriptType.IsSubclassOf(typeof(Object))) { SetDragAndDropMode(false); return; From a400f57d1b0bdb97ba0670597fc4a235518c3b99 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Girard Date: Thu, 14 Jul 2022 15:50:36 -0400 Subject: [PATCH 16/16] Update ReferenceDrawer.cs PropertyValue setter Should always check if gameObject. This will be useful later on. --- Editor/Drawers/ReferenceDrawer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Editor/Drawers/ReferenceDrawer.cs b/Editor/Drawers/ReferenceDrawer.cs index 823169d..a64eb99 100644 --- a/Editor/Drawers/ReferenceDrawer.cs +++ b/Editor/Drawers/ReferenceDrawer.cs @@ -80,7 +80,7 @@ protected object PropertyValue UnityReferenceProperty.objectReferenceValue = null; break; case ReferenceMode.Unity: - UnityReferenceProperty.objectReferenceValue = (Object)value; + UnityReferenceProperty.objectReferenceValue = GetUnityObject((Object)value); RawReferenceValue = null; break; default: @@ -226,7 +226,7 @@ private void HandleDragPerform() break; case DragAndDropMode.Unity: ModeValue = ReferenceMode.Unity; - PropertyValue = GetUnityObject(DragAndDrop.objectReferences[0]); + PropertyValue = DragAndDrop.objectReferences[0]; break; case DragAndDropMode.None: default: