implements "Auto DragAndDrop UsageTypeDetection" for reference fields based on PR from @toasterhead-master

- contains only changes regarding to the feature itself without any of the refactoring
    - reduces the amount of boilerplate classes

Closes: #441
Co-authored-by: ToasterHead<toasterhead-master>
This commit is contained in:
Oliver Biwer 2023-11-03 22:33:04 +01:00
parent 37ead24dbb
commit 2ddefb7f4a
10 changed files with 99 additions and 12 deletions

View File

@ -7,7 +7,7 @@ namespace UnityAtoms.BaseAtoms.Editor
/// A custom property drawer for AtomCollectionReference. Makes it possible to choose between a Collection or a Collection Instancer. /// A custom property drawer for AtomCollectionReference. Makes it possible to choose between a Collection or a Collection Instancer.
/// </summary> /// </summary>
[CustomPropertyDrawer(typeof(AtomCollectionReference), true)] [CustomPropertyDrawer(typeof(AtomCollectionReference), true)]
public class AtomCollectionReferenceDrawer : AtomBaseReferenceDrawer public class AtomCollectionReferenceDrawer : AtomBaseReferenceDrawer<AtomCollectionInstancer>
{ {
protected class UsageCollection : UsageData protected class UsageCollection : UsageData
{ {

View File

@ -7,7 +7,7 @@ namespace UnityAtoms.BaseAtoms.Editor
/// A custom property drawer for AtomListReference. Makes it possible to choose between a List or a List Instancer. /// A custom property drawer for AtomListReference. Makes it possible to choose between a List or a List Instancer.
/// </summary> /// </summary>
[CustomPropertyDrawer(typeof(AtomListReference), true)] [CustomPropertyDrawer(typeof(AtomListReference), true)]
public class AtomListReferenceDrawer : AtomBaseReferenceDrawer public class AtomListReferenceDrawer : AtomBaseReferenceDrawer<AtomListInstancer>
{ {
protected class UsageList : UsageData protected class UsageList : UsageData
{ {

View File

@ -7,7 +7,7 @@ namespace UnityAtoms.BaseAtoms.Editor
/// A custom property drawer for AtomBaseVariable BaseEventReferences. Makes it possible to choose between an Event, Event Instancer, Collection Added, Collection Removed, List Added, List Removed, Collection Instancer Added, Collection Instancer Removed, List Instancer Added or List Instancer Removed. /// A custom property drawer for AtomBaseVariable BaseEventReferences. Makes it possible to choose between an Event, Event Instancer, Collection Added, Collection Removed, List Added, List Removed, Collection Instancer Added, Collection Instancer Removed, List Instancer Added or List Instancer Removed.
/// </summary> /// </summary>
[CustomPropertyDrawer(typeof(AtomBaseVariableBaseEventReference), true)] [CustomPropertyDrawer(typeof(AtomBaseVariableBaseEventReference), true)]
public class AtomBaseVariableBaseEventReferenceDrawer : AtomBaseReferenceDrawer public class AtomBaseVariableBaseEventReferenceDrawer : AtomBaseReferenceDrawer<AtomBaseVariableEventInstancer>
{ {
protected class UsageEvent : UsageData protected class UsageEvent : UsageData
{ {

View File

@ -7,7 +7,7 @@ namespace UnityAtoms.BaseAtoms.Editor
/// A custom property drawer for Void BaseEventReferences. Makes it possible to choose between an Event, Event Instancer, Collection Cleared, List Cleared, Collection Instancer Cleared or List Instancer Cleared. /// A custom property drawer for Void BaseEventReferences. Makes it possible to choose between an Event, Event Instancer, Collection Cleared, List Cleared, Collection Instancer Cleared or List Instancer Cleared.
/// </summary> /// </summary>
[CustomPropertyDrawer(typeof(VoidBaseEventReference), true)] [CustomPropertyDrawer(typeof(VoidBaseEventReference), true)]
public class VoidBaseEventReferenceDrawer : AtomBaseReferenceDrawer public class VoidBaseEventReferenceDrawer : AtomBaseReferenceDrawer<VoidEventInstancer>
{ {
protected class UsageEvent : UsageData protected class UsageEvent : UsageData
{ {

View File

@ -8,7 +8,8 @@ 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. /// A custom property drawer for References (Events and regular). Makes it possible to reference a resources (Variable or Event) through multiple options.
/// </summary> /// </summary>
public abstract class AtomBaseReferenceDrawer : PropertyDrawer public abstract class AtomBaseReferenceDrawer<TInstancerType> : PropertyDrawer
where TInstancerType : MonoBehaviour
{ {
protected abstract class UsageData protected abstract class UsageData
{ {
@ -16,6 +17,7 @@ namespace UnityAtoms.Editor
public abstract string PropertyName { get; } public abstract string PropertyName { get; }
public abstract string DisplayName { get; } public abstract string DisplayName { get; }
} }
const string USAGE_PROPERTY_NAME = "_usage";
protected abstract UsageData[] GetUsages(SerializedProperty prop = null); protected abstract UsageData[] GetUsages(SerializedProperty prop = null);
@ -24,7 +26,7 @@ namespace UnityAtoms.Editor
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{ {
var usageIntVal = property.FindPropertyRelative("_usage").intValue; var usageIntVal = property.FindPropertyRelative(USAGE_PROPERTY_NAME).intValue;
var usageData = GetUsages(property)[0]; var usageData = GetUsages(property)[0];
for (var i = 0; i < GetUsages(property).Length; ++i) for (var i = 0; i < GetUsages(property).Length; ++i)
{ {
@ -67,8 +69,9 @@ namespace UnityAtoms.Editor
int indent = EditorGUI.indentLevel; int indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0; EditorGUI.indentLevel = 0;
var currentUsage = property.FindPropertyRelative("_usage"); var currentUsage = property.FindPropertyRelative(USAGE_PROPERTY_NAME);
var newUsageValue = EditorGUI.Popup(buttonRect, currentUsage.intValue, GetPopupOptions(property), _popupStyle); var newUsageValue = EditorGUI.Popup(buttonRect, currentUsage.intValue, GetPopupOptions(property), _popupStyle);
DetermineDragAndDropFieldReferenceType(position, property, ref newUsageValue);
currentUsage.intValue = newUsageValue; currentUsage.intValue = newUsageValue;
var usageTypePropertyName = GetUsages(property)[newUsageValue].PropertyName; var usageTypePropertyName = GetUsages(property)[newUsageValue].PropertyName;
@ -100,5 +103,63 @@ namespace UnityAtoms.Editor
EditorGUI.indentLevel = indent; EditorGUI.indentLevel = indent;
EditorGUI.EndProperty(); EditorGUI.EndProperty();
} }
#region Auto DragAndDrop UsageTypeDetection
private void DetermineDragAndDropFieldReferenceType(in Rect position, SerializedProperty property,
ref int newUsageValue)
{
EventType mouseEventType = Event.current.type;
if (mouseEventType != EventType.DragUpdated && mouseEventType != EventType.DragPerform)
return;
if (!IsMouseHoveringOverProperty(position))
return;
var draggedObjects = DragAndDrop.objectReferences;
if (draggedObjects.Length < 1)
return;
Object draggedObject = draggedObjects[0];
if (draggedObject is GameObject gameObject)
draggedObject = gameObject.GetComponent<TInstancerType>();
UpdateConfigurationOption(property, draggedObject, ref newUsageValue);
}
private void UpdateConfigurationOption(SerializedProperty property, Object draggedObject, ref int newUsageValue)
{
if (!draggedObject)
return;
var usages = GetUsages(property);
for (int index = 0; index < usages.Length; index++)
{
var usage = usages[index];
SerializedProperty fieldProperty = property.FindPropertyRelative(usage.PropertyName);
string draggedObjectType = draggedObject.GetType().Name;
string fieldPropertyType = fieldProperty.type.Replace("PPtr<$", "").Replace(">", "");
if (draggedObjectType == fieldPropertyType)
{
newUsageValue = index;
break;
}
}
}
private static bool IsMouseHoveringOverProperty(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
} }
} }

View File

@ -6,7 +6,7 @@ namespace UnityAtoms.Editor
/// A custom property drawer for Event References. Makes it possible to choose between an Event, Event Instancer, Variable or a Variable Instancer. /// A custom property drawer for Event References. Makes it possible to choose between an Event, Event Instancer, Variable or a Variable Instancer.
/// </summary> /// </summary>
[CustomPropertyDrawer(typeof(AtomBaseEventReference), true)] [CustomPropertyDrawer(typeof(AtomBaseEventReference), true)]
public class AtomEventReferenceDrawer : AtomBaseReferenceDrawer public class AtomEventReferenceDrawer : AtomBaseReferenceDrawer<AtomEventInstancer>
{ {
protected class UsageEvent : UsageData protected class UsageEvent : UsageData
{ {

View File

@ -7,7 +7,7 @@ namespace UnityAtoms.Editor
/// </summary> /// </summary>
[CustomPropertyDrawer(typeof(AtomBaseReference), true)] [CustomPropertyDrawer(typeof(AtomBaseReference), true)]
public class AtomReferenceDrawer : AtomBaseReferenceDrawer public class AtomReferenceDrawer : AtomBaseReferenceDrawer<AtomBaseVariableInstancer>
{ {
protected class UsageValue : UsageData protected class UsageValue : UsageData
{ {

View File

@ -5,6 +5,11 @@ using UnityEngine.Assertions;
namespace UnityAtoms namespace UnityAtoms
{ {
public abstract class AtomEventInstancer : MonoBehaviour
{
}
/// <summary> /// <summary>
/// An Event Instancer is a MonoBehaviour that takes an Event as a base and creates an in memory copy of it on OnEnable. /// An Event Instancer is a MonoBehaviour that takes an Event as a base and creates an in memory copy of it on OnEnable.
/// This is handy when you want to use Events for prefabs that are instantiated at runtime. /// This is handy when you want to use Events for prefabs that are instantiated at runtime.
@ -13,7 +18,7 @@ namespace UnityAtoms
/// <typeparam name="E">Event of type T.</typeparam> /// <typeparam name="E">Event of type T.</typeparam>
[EditorIcon("atom-icon-sign-blue")] [EditorIcon("atom-icon-sign-blue")]
[DefaultExecutionOrder(Runtime.ExecutionOrder.VARIABLE_INSTANCER)] [DefaultExecutionOrder(Runtime.ExecutionOrder.VARIABLE_INSTANCER)]
public abstract class AtomEventInstancer<T, E> : MonoBehaviour, IGetEvent, ISetEvent public abstract class AtomEventInstancer<T, E> : AtomEventInstancer, IGetEvent, ISetEvent
where E : AtomEvent<T> where E : AtomEvent<T>
{ {
public T InspectorRaiseValue { get => _inspectorRaiseValue; } public T InspectorRaiseValue { get => _inspectorRaiseValue; }

View File

@ -4,6 +4,11 @@ using UnityEngine.Assertions;
namespace UnityAtoms namespace UnityAtoms
{ {
public abstract class AtomBaseVariableInstancer : MonoBehaviour
{
}
/// <summary> /// <summary>
/// A Variable Instancer is a MonoBehaviour that takes a variable as a base and creates an in memory copy of it OnEnable. /// A Variable Instancer is a MonoBehaviour that takes a variable as a base and creates an in memory copy of it OnEnable.
/// This is handy when you want to use atoms for prefabs that are instantiated at runtime. Use together with AtomCollection to /// This is handy when you want to use atoms for prefabs that are instantiated at runtime. Use together with AtomCollection to
@ -17,7 +22,7 @@ namespace UnityAtoms
/// <typeparam name="F">Function of type T => T</typeparam> /// <typeparam name="F">Function of type T => T</typeparam>
[EditorIcon("atom-icon-hotpink")] [EditorIcon("atom-icon-hotpink")]
[DefaultExecutionOrder(Runtime.ExecutionOrder.VARIABLE_INSTANCER)] [DefaultExecutionOrder(Runtime.ExecutionOrder.VARIABLE_INSTANCER)]
public abstract class AtomBaseVariableInstancer<T, V> : MonoBehaviour, IVariable<V> public abstract class AtomBaseVariableInstancer<T, V> : AtomBaseVariableInstancer, IVariable<V>
where V : AtomBaseVariable<T> where V : AtomBaseVariable<T>
{ {
/// <summary> /// <summary>
@ -25,6 +30,22 @@ namespace UnityAtoms
/// </summary> /// </summary>
public V Variable { get => _inMemoryCopy; } public V Variable { get => _inMemoryCopy; }
public void SetSource(V variable)
{
_base = variable;
if (Application.isPlaying)
{
Debug.LogWarning("Setting the underlying variable of an instancers at runtime can result in hard to find issues. be careful.");
if (_inMemoryCopy != null)
{
Destroy(_inMemoryCopy);
_inMemoryCopy = null;
}
OnEnable();
}
}
/// <summary> /// <summary>
/// Getter for retrieving the value of the in memory runtime variable. /// Getter for retrieving the value of the in memory runtime variable.
/// </summary> /// </summary>

View File

@ -7,7 +7,7 @@ namespace UnityAtoms.FSM.Editor
/// A custom property drawer for FiniteStateMachineReference. Makes it possible to choose between a FSM or a FSM Instancer. /// A custom property drawer for FiniteStateMachineReference. Makes it possible to choose between a FSM or a FSM Instancer.
/// </summary> /// </summary>
[CustomPropertyDrawer(typeof(FiniteStateMachineReference), true)] [CustomPropertyDrawer(typeof(FiniteStateMachineReference), true)]
public class FiniteStateMachineReferenceDrawer : AtomBaseReferenceDrawer public class FiniteStateMachineReferenceDrawer : AtomBaseReferenceDrawer<FiniteStateMachineInstancer>
{ {
protected class UsageFSM : UsageData protected class UsageFSM : UsageData
{ {