diff --git a/InterfaceRef.cs b/InterfaceRef.cs
index da87c61..a47b4db 100644
--- a/InterfaceRef.cs
+++ b/InterfaceRef.cs
@@ -8,7 +8,7 @@ namespace KBCore.Refs
///
/// Component type to find and serialize.
[Serializable]
- public class InterfaceRef : ISerializableRef
+ public class InterfaceRef : ISerializableRef, IEquatable>
where T : class
{
@@ -57,5 +57,12 @@ void ISerializableRef.Clear()
this._value = null;
this._implementer = null;
}
+
+ public override bool Equals(object obj) => obj is InterfaceRef casted && Equals(casted);
+
+ public bool Equals(InterfaceRef other)
+ {
+ return other != null && _implementer == other._implementer;
+ }
}
}
\ No newline at end of file
diff --git a/InterfaceRefPropertyDrawer.cs b/InterfaceRefPropertyDrawer.cs
index a6fc52f..bc1ef32 100644
--- a/InterfaceRefPropertyDrawer.cs
+++ b/InterfaceRefPropertyDrawer.cs
@@ -1,8 +1,10 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
+using Object = UnityEngine.Object;
#if UNITY_2022_2_OR_NEWER
+using System;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
#endif
@@ -13,18 +15,107 @@ namespace KBCore.Refs
public class InterfaceRefPropertyDrawer : PropertyDrawer
{
private const string IMPLEMENTER_PROP = "_implementer";
-
+
// unity 2022.2 makes UIToolkit the default for inspectors
#if UNITY_2022_2_OR_NEWER
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
- return new PropertyField(property.FindPropertyRelative(IMPLEMENTER_PROP), property.displayName);
+ var field = new PropertyField(property.FindPropertyRelative(IMPLEMENTER_PROP), property.displayName);
+ field.RegisterCallback(DragPerformEvent, property,
+ TrickleDown.TrickleDown);
+ field.RegisterCallback(DragUpdatedEvent, property,
+ TrickleDown.TrickleDown);
+
+ return field;
+ }
+
+ private void DragUpdatedEvent(DragUpdatedEvent evt, SerializedProperty serializedProperty)
+ {
+ evt.StopImmediatePropagation();
+ if (!TryGetDraggedComponent(serializedProperty, out _))
+ {
+ DragAndDrop.visualMode = DragAndDropVisualMode.Rejected;
+ return;
+ }
+
+ DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
+ }
+
+ private void DragPerformEvent(DragPerformEvent evt, SerializedProperty serializedProperty)
+ {
+ if (!TryGetDraggedComponent(serializedProperty, out var component))
+ return;
+
+ DragAndDrop.AcceptDrag();
+
+ serializedProperty.FindPropertyRelative(IMPLEMENTER_PROP).objectReferenceValue = component;
+ serializedProperty.serializedObject.ApplyModifiedProperties();
+
+ evt.StopImmediatePropagation();
}
+
#endif
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
- EditorGUI.PropertyField(position, property.FindPropertyRelative(IMPLEMENTER_PROP), label, true);
+ EditorGUI.BeginProperty(position, label, property);
+
+ EditorGUI.ObjectField(position, property.FindPropertyRelative(IMPLEMENTER_PROP), label);
+ HandleIMGUIObjectDrag(position, property);
+
+ EditorGUI.EndProperty();
+ }
+
+ private void HandleIMGUIObjectDrag(Rect position, SerializedProperty property)
+ {
+ var evt = Event.current;
+
+ if ((evt.type != EventType.DragUpdated && evt.type != EventType.DragPerform) || !position.Contains(evt.mousePosition))
+ return;
+
+ evt.Use();
+
+ if (!TryGetDraggedComponent(property, out var component))
+ {
+ DragAndDrop.visualMode = DragAndDropVisualMode.Rejected;
+ return;
+ }
+
+ DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
+
+ if (evt.type == EventType.DragPerform)
+ {
+ DragAndDrop.AcceptDrag();
+
+ property.FindPropertyRelative(IMPLEMENTER_PROP).objectReferenceValue = component;
+ property.serializedObject.ApplyModifiedProperties();
+
+ GUI.changed = true;
+ }
+
+ evt.Use();
+ }
+
+ private static bool TryGetDraggedComponent(SerializedProperty property, out Component component)
+ {
+ component = null;
+
+ if (DragAndDrop.objectReferences.Length != 1)
+ return false;
+
+ var targetType = ((ISerializableRef)property.boxedValue).RefType;
+ Object checkedObject = DragAndDrop.objectReferences[0];
+
+ if (checkedObject is Component draggedComponent && targetType.IsAssignableFrom(draggedComponent.GetType()))
+ {
+ component = draggedComponent;
+ return true;
+ }
+
+ if (checkedObject is GameObject go && go.TryGetComponent(targetType, out component))
+ return true;
+
+ return false;
}
}
}