diff --git a/Packages/Core/Editor/Drawers/AtomBaseReferenceDrawer.cs b/Packages/Core/Editor/Drawers/AtomBaseReferenceDrawer.cs
index f1b82f5a..0db4bb1c 100644
--- a/Packages/Core/Editor/Drawers/AtomBaseReferenceDrawer.cs
+++ b/Packages/Core/Editor/Drawers/AtomBaseReferenceDrawer.cs
@@ -7,7 +7,6 @@ namespace UnityAtoms.Editor
///
/// A custom property drawer for References (Events and regular). Makes it possible to reference a resources (Variable or Event) through multiple options.
///
-
public abstract class AtomBaseReferenceDrawer : PropertyDrawer
{
protected abstract class UsageData
@@ -16,17 +15,60 @@ namespace UnityAtoms.Editor
public abstract string PropertyName { get; }
public abstract string DisplayName { get; }
}
+ private const string USAGE_PROPERTY_NAME = "_usage";
protected abstract UsageData[] GetUsages(SerializedProperty prop = null);
private string[] GetPopupOptions(SerializedProperty prop = null) => GetUsages(prop).Select(u => u.DisplayName).ToArray();
private static GUIStyle _popupStyle;
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ GuiData guiData = new GuiData()
+ {
+ Position = position,
+ Property = property,
+ Label = label
+ };
+
+ if (_popupStyle == null)
+ {
+ _popupStyle = new GUIStyle(GUI.skin.GetStyle("PaneOptions"))
+ {
+ imagePosition = ImagePosition.ImageOnly
+ };
+ }
+
+ using (var scope = new EditorGUI.PropertyScope(position, label, property))
+ {
+ guiData.Label = scope.content;
+ guiData.Position = EditorGUI.PrefixLabel(position, label);
+ // Store old indent level and set it to 0, the PrefixLabel takes care of it
+ int indent = EditorGUI.indentLevel;
+ EditorGUI.indentLevel = 0;
+ {
+ EditorGUI.BeginChangeCheck();
+ {
+ DetermineDragAndDropFieldReferenceType(guiData);
+ DrawConfigurationButton(ref guiData);
+ string currentUsageTypePropertyName = GetUsages(property)[GetUsageIndex(property)].PropertyName;
+ DrawField(currentUsageTypePropertyName, guiData, position);
+ }
+ if (EditorGUI.EndChangeCheck())
+ {
+ property.serializedObject.ApplyModifiedProperties();
+ }
+ }
+ EditorGUI.indentLevel = indent;
+ }
+ }
+
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
- var usageIntVal = property.FindPropertyRelative("_usage").intValue;
+ var usageIntVal = GetUsageIndex(property);
var usageData = GetUsages(property)[0];
- for (var i = 0; i < GetUsages(property).Length; ++i)
+
+ for (int i = 0; i < GetUsages(property).Length; ++i)
{
if (GetUsages(property)[i].Value == usageIntVal)
{
@@ -36,53 +78,44 @@ namespace UnityAtoms.Editor
}
var innerProperty = property.FindPropertyRelative(usageData.PropertyName);
+
return innerProperty == null ?
EditorGUIUtility.singleLineHeight :
EditorGUI.GetPropertyHeight(innerProperty, label);
}
- public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ private void DrawConfigurationButton(ref GuiData guiData)
{
- if (_popupStyle == null)
- {
- _popupStyle = new GUIStyle(GUI.skin.GetStyle("PaneOptions"));
- _popupStyle.imagePosition = ImagePosition.ImageOnly;
- }
+ Rect button = new Rect(guiData.Position);
+ button.yMin += _popupStyle.margin.top;
+ button.yMax = button.yMin + EditorGUIUtility.singleLineHeight;
+ button.width = _popupStyle.fixedWidth + _popupStyle.margin.right;
+ guiData.Position.xMin = button.xMax;
- Rect originalPosition = new Rect(position);
+ var currentUsageIndex = GetUsageIndex(guiData.Property);
+ var newUsageValue = EditorGUI.Popup(button, currentUsageIndex, GetPopupOptions(guiData.Property), _popupStyle);
+ SetUsageIndex(guiData.Property, newUsageValue);
+ }
- label = EditorGUI.BeginProperty(position, label, property);
- position = EditorGUI.PrefixLabel(position, label);
-
- EditorGUI.BeginChangeCheck();
-
- // Calculate rect for configuration button
- Rect buttonRect = new Rect(position);
- buttonRect.yMin += _popupStyle.margin.top;
- buttonRect.yMax = buttonRect.yMin + EditorGUIUtility.singleLineHeight;
- buttonRect.width = _popupStyle.fixedWidth + _popupStyle.margin.right;
- position.xMin = buttonRect.xMax;
-
- // Store old indent level and set it to 0, the PrefixLabel takes care of it
- int indent = EditorGUI.indentLevel;
- EditorGUI.indentLevel = 0;
-
- var currentUsage = property.FindPropertyRelative("_usage");
- var newUsageValue = EditorGUI.Popup(buttonRect, currentUsage.intValue, GetPopupOptions(property), _popupStyle);
- currentUsage.intValue = newUsageValue;
-
- var usageTypePropertyName = GetUsages(property)[newUsageValue].PropertyName;
- var usageTypeProperty = property.FindPropertyRelative(usageTypePropertyName);
+ private static void DrawField(string usageTypePropertyName, in GuiData guiData, in Rect originalPosition)
+ {
+ var usageTypeProperty = guiData.Property.FindPropertyRelative(usageTypePropertyName);
if (usageTypeProperty == null)
{
- EditorGUI.LabelField(position, "[Non serialized value]");
+ EditorGUI.LabelField(guiData.Position, "[Non serialized value]");
}
else
{
var expanded = usageTypeProperty.isExpanded;
usageTypeProperty.isExpanded = true;
- var valueFieldHeight = EditorGUI.GetPropertyHeight(usageTypeProperty, label);
+ var valueFieldHeight = usageTypeProperty.propertyType == SerializedPropertyType.Quaternion ?
+ // In versions prior to 2022.3 GetPropertyHeight returns the wrong value for "SerializedPropertyType.Quaternion"
+ // In later versions, the fix is introduced _but only_ when using the SerializedPropertyType parameter, not when using the SerializedProperty parameter version.
+ // ALSO the SerializedPropertyType parameter version does not work with the isExpanded flag which we set to true exactly for this reason a (few) lines above.
+ EditorGUI.GetPropertyHeight(SerializedPropertyType.Vector3, guiData.Label) :
+ EditorGUI.GetPropertyHeight(usageTypeProperty, guiData.Label);
+
usageTypeProperty.isExpanded = expanded;
if (usageTypePropertyName == "_value" && (valueFieldHeight > EditorGUIUtility.singleLineHeight + 2))
@@ -91,14 +124,127 @@ namespace UnityAtoms.Editor
}
else
{
- EditorGUI.PropertyField(position, usageTypeProperty, GUIContent.none);
+ EditorGUI.PropertyField(guiData.Position, usageTypeProperty, GUIContent.none);
}
}
- if (EditorGUI.EndChangeCheck())
- property.serializedObject.ApplyModifiedProperties();
-
- EditorGUI.indentLevel = indent;
- EditorGUI.EndProperty();
}
+
+ private static void SetUsageIndex(SerializedProperty property, int index)
+ {
+ property.FindPropertyRelative(USAGE_PROPERTY_NAME).intValue = index;
+ }
+
+ private static int GetUsageIndex(SerializedProperty property)
+ {
+ return property.FindPropertyRelative(USAGE_PROPERTY_NAME).intValue;
+ }
+
+
+ #region Auto Drag And Drop Usage Type Detection
+ private void DetermineDragAndDropFieldReferenceType(in GuiData guiData)
+ {
+ EventType mouseEventType = Event.current.type;
+
+ if (mouseEventType != EventType.DragUpdated && mouseEventType != EventType.DragPerform)
+ {
+ return;
+ }
+
+ if (!IsMouseHoveringOverProperty(guiData.Position))
+ {
+ return;
+ }
+
+ var draggedObjects = DragAndDrop.objectReferences;
+ if (draggedObjects.Length < 1)
+ {
+ return;
+ }
+
+ Object draggedObject = draggedObjects[0];
+
+ if (draggedObject is GameObject gameObject)
+ {
+ object[] instancers = gameObject.GetComponents();
+ UpdateUsageConfigurationOption(guiData.Property, instancers);
+ }
+ else
+ {
+ UpdateUsageConfigurationOption(guiData.Property, draggedObject);
+ }
+ }
+
+ private void UpdateUsageConfigurationOption(SerializedProperty property, params object[] draggedObjects)
+ {
+ if (draggedObjects == null || draggedObjects.Length < 1)
+ {
+ return;
+ }
+
+ var usages = GetUsages(property);
+ int currentUsageIndex = GetUsageIndex(property);
+ int newUsageIndex = -1;
+
+ foreach (object draggedObject in draggedObjects)
+ {
+ for (int index = 0; index < usages.Length; index++)
+ {
+ var usage = usages[index];
+ var usageProperty = property.FindPropertyRelative(usage.PropertyName);
+ bool isDraggedTypeSameAsUsageType = AreTypesEqual(usageProperty, draggedObject);
+
+ if (isDraggedTypeSameAsUsageType)
+ {
+ bool isUsageSetByUser = currentUsageIndex == index;
+
+ if (isUsageSetByUser)
+ {
+ return;
+ }
+
+ bool isNewUsageIndexSet = newUsageIndex > -1;
+ if (!isNewUsageIndexSet)
+ {
+ newUsageIndex = index;
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (newUsageIndex > -1)
+ {
+ SetUsageIndex(property, newUsageIndex);
+ }
+ }
+
+ private static bool AreTypesEqual(SerializedProperty property, object otherObject)
+ {
+ string otherObjectTypeName = otherObject.GetType().Name;
+ string propertyObjectTypeName = GetPropertyTypeName(property);
+ return otherObjectTypeName == propertyObjectTypeName;
+ }
+
+ private static readonly string PPTR_GENERIC_PREFIX = "PPtr<$";
+ private static string GetPropertyTypeName(SerializedProperty property)
+ {
+ if (!property.type.StartsWith(PPTR_GENERIC_PREFIX))
+ {
+ return property.type;
+ }
+ string fieldPropertyType = property.type.Replace(PPTR_GENERIC_PREFIX, "");
+ return fieldPropertyType.Remove(fieldPropertyType.Length - 1);
+ }
+
+ private static bool IsMouseHoveringOverProperty(in Rect rectPosition)
+ {
+ const int HEIGHT_OFFSET_TO_AVOID_OVERLAP = 1;
+ Rect controlRect = rectPosition;
+ controlRect.height -= HEIGHT_OFFSET_TO_AVOID_OVERLAP;
+
+ return controlRect.Contains(Event.current.mousePosition);
+ }
+ #endregion
}
}
diff --git a/Packages/Core/Editor/Utils/GuiData.cs b/Packages/Core/Editor/Utils/GuiData.cs
new file mode 100644
index 00000000..9f2a1ea5
--- /dev/null
+++ b/Packages/Core/Editor/Utils/GuiData.cs
@@ -0,0 +1,12 @@
+using UnityEditor;
+using UnityEngine;
+
+namespace UnityAtoms.Editor
+{
+ public struct GuiData
+ {
+ public Rect Position;
+ public SerializedProperty Property;
+ public GUIContent Label;
+ }
+}
\ No newline at end of file
diff --git a/Packages/Core/Editor/Utils/GuiData.cs.meta b/Packages/Core/Editor/Utils/GuiData.cs.meta
new file mode 100644
index 00000000..5371731a
--- /dev/null
+++ b/Packages/Core/Editor/Utils/GuiData.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a1c20882cb5b7ab4e8c3e8fb77d1ebf8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/Core/Runtime/EventInstancers/AtomEventInstancer.cs b/Packages/Core/Runtime/EventInstancers/AtomEventInstancer.cs
index ad6ebdae..d3c3c322 100644
--- a/Packages/Core/Runtime/EventInstancers/AtomEventInstancer.cs
+++ b/Packages/Core/Runtime/EventInstancers/AtomEventInstancer.cs
@@ -13,7 +13,7 @@ namespace UnityAtoms
/// Event of type T.
[EditorIcon("atom-icon-sign-blue")]
[DefaultExecutionOrder(Runtime.ExecutionOrder.VARIABLE_INSTANCER)]
- public abstract class AtomEventInstancer : MonoBehaviour, IGetEvent, ISetEvent
+ public abstract class AtomEventInstancer : MonoBehaviour, IGetEvent, ISetEvent, IAtomInstancer
where E : AtomEvent
{
public T InspectorRaiseValue { get => _inspectorRaiseValue; }
diff --git a/Packages/Core/Runtime/VariableInstancers/AtomBaseVariableInstancer.cs b/Packages/Core/Runtime/VariableInstancers/AtomBaseVariableInstancer.cs
index fd38a01e..d0affbe0 100644
--- a/Packages/Core/Runtime/VariableInstancers/AtomBaseVariableInstancer.cs
+++ b/Packages/Core/Runtime/VariableInstancers/AtomBaseVariableInstancer.cs
@@ -17,7 +17,7 @@ namespace UnityAtoms
/// Function of type T => T
[EditorIcon("atom-icon-hotpink")]
[DefaultExecutionOrder(Runtime.ExecutionOrder.VARIABLE_INSTANCER)]
- public abstract class AtomBaseVariableInstancer : MonoBehaviour, IVariable
+ public abstract class AtomBaseVariableInstancer : MonoBehaviour, IVariable, IAtomInstancer
where V : AtomBaseVariable
{
///
diff --git a/Packages/Core/Runtime/VariableInstancers/IAtomInstancer.cs b/Packages/Core/Runtime/VariableInstancers/IAtomInstancer.cs
new file mode 100644
index 00000000..f9ce25e5
--- /dev/null
+++ b/Packages/Core/Runtime/VariableInstancers/IAtomInstancer.cs
@@ -0,0 +1,5 @@
+namespace UnityAtoms
+{
+ // Currently only used in AtomBaseReferenceDrawer in order to auto set usage type on drag and drop
+ public interface IAtomInstancer { }
+}
diff --git a/Packages/Core/Runtime/VariableInstancers/IAtomInstancer.cs.meta b/Packages/Core/Runtime/VariableInstancers/IAtomInstancer.cs.meta
new file mode 100644
index 00000000..685a28ae
--- /dev/null
+++ b/Packages/Core/Runtime/VariableInstancers/IAtomInstancer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 31198ba3f24bc6c49955d939f8ac29c9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: