You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
376 lines
15 KiB
C#
376 lines
15 KiB
C#
// UltEvents // Copyright 2020 Kybernetik //
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using UnityEditor;
|
|
|
|
namespace UltEvents.Editor
|
|
{
|
|
/// <summary>[Editor-Only]
|
|
/// Manages the GUI state used when drawing events.
|
|
/// </summary>
|
|
internal sealed class DrawerState
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>The currently active state.</summary>
|
|
public static readonly DrawerState Current = new DrawerState();
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>The <see cref="SerializedProperty"/> for the event currently being drawn.</summary>
|
|
public SerializedProperty EventProperty { get; private set; }
|
|
|
|
/// <summary>The event currently being drawn.</summary>
|
|
public UltEventBase Event { get; private set; }
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>The <see cref="SerializedProperty"/> for the call currently being drawn.</summary>
|
|
public SerializedProperty CallProperty { get; private set; }
|
|
|
|
/// <summary>The <see cref="SerializedProperty"/> for the target of the call currently being drawn.</summary>
|
|
public SerializedProperty TargetProperty { get; private set; }
|
|
|
|
/// <summary>The <see cref="SerializedProperty"/> for the method name of the call currently being drawn.</summary>
|
|
public SerializedProperty MethodNameProperty { get; private set; }
|
|
|
|
/// <summary>The <see cref="SerializedProperty"/> for the persistent arguments array of the call currently being drawn.</summary>
|
|
public SerializedProperty PersistentArgumentsProperty { get; private set; }
|
|
|
|
/// <summary>The index of the call currently being drawn.</summary>
|
|
public int callIndex = -1;
|
|
|
|
/// <summary>The call currently being drawn.</summary>
|
|
public PersistentCall call;
|
|
|
|
/// <summary>The parameters of the call currently being drawn.</summary>
|
|
public ParameterInfo[] callParameters;
|
|
|
|
/// <summary>The index of the parameter currently being drawn.</summary>
|
|
public int parameterIndex;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>If true, each call will be stored so that subsequent calls can link to their return value.</summary>
|
|
public bool CachePreviousCalls { get; private set; }
|
|
|
|
/// <summary>The calls of the current event that come before the current call currently being drawn.</summary>
|
|
private readonly List<PersistentCall> PreviousCalls = new List<PersistentCall>();
|
|
|
|
/// <summary>The methods targeted by the calls of the event currently being drawn.</summary>
|
|
private readonly List<MethodBase> PersistentMethodCache = new List<MethodBase>();
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>The parameter currently being drawn.</summary>
|
|
public ParameterInfo CurrentParameter
|
|
{
|
|
get { return callParameters[parameterIndex]; }
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Caches the event from the specified property and returns true as long as it is not null.</summary>
|
|
public bool TryBeginEvent(SerializedProperty eventProperty)
|
|
{
|
|
Event = eventProperty.GetValue<UltEventBase>();
|
|
if (Event == null)
|
|
return false;
|
|
|
|
EventProperty = eventProperty;
|
|
return true;
|
|
}
|
|
|
|
/// <summary>Cancels out a call to <see cref="TryBeginEvent"/>.</summary>
|
|
public void EndEvent()
|
|
{
|
|
EventProperty = null;
|
|
Event = null;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Starts caching calls so that subsequent calls can link to earlier return values.</summary>
|
|
public void BeginCache()
|
|
{
|
|
CacheLinkedArguments();
|
|
CachePreviousCalls = true;
|
|
}
|
|
|
|
/// <summary>Cancels out a call to <see cref="EndCache"/>.</summary>
|
|
public void EndCache()
|
|
{
|
|
CachePreviousCalls = false;
|
|
PreviousCalls.Clear();
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Caches the call from the specified property.</summary>
|
|
public void BeginCall(SerializedProperty callProperty)
|
|
{
|
|
CallProperty = callProperty;
|
|
|
|
TargetProperty = GetTargetProperty(callProperty);
|
|
MethodNameProperty = GetMethodNameProperty(callProperty);
|
|
PersistentArgumentsProperty = GetPersistentArgumentsProperty(callProperty);
|
|
|
|
call = GetCall(callProperty);
|
|
}
|
|
|
|
/// <summary>Cancels out a call to <see cref="BeginCall"/>.</summary>
|
|
public void EndCall()
|
|
{
|
|
if (CachePreviousCalls)
|
|
PreviousCalls.Add(call);
|
|
|
|
call = null;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Returns the property encapsulating the <see cref="PersistentCall.Target"/>.</summary>
|
|
public static SerializedProperty GetTargetProperty(SerializedProperty callProperty)
|
|
{
|
|
return callProperty.FindPropertyRelative(Names.PersistentCall.Target);
|
|
}
|
|
|
|
/// <summary>Returns the property encapsulating the <see cref="PersistentCall.MethodName"/>.</summary>
|
|
public static SerializedProperty GetMethodNameProperty(SerializedProperty callProperty)
|
|
{
|
|
return callProperty.FindPropertyRelative(Names.PersistentCall.MethodName);
|
|
}
|
|
|
|
/// <summary>Returns the property encapsulating the <see cref="PersistentCall.PersistentArguments"/>.</summary>
|
|
public static SerializedProperty GetPersistentArgumentsProperty(SerializedProperty callProperty)
|
|
{
|
|
return callProperty.FindPropertyRelative(Names.PersistentCall.PersistentArguments);
|
|
}
|
|
|
|
/// <summary>Returns the call encapsulated by the specified property.</summary>
|
|
public static PersistentCall GetCall(SerializedProperty callProperty)
|
|
{
|
|
return callProperty.GetValue<PersistentCall>();
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
#region Linked Argument Cache
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Stores all the persistent methods in the current event.</summary>
|
|
public void CacheLinkedArguments()
|
|
{
|
|
PersistentMethodCache.Clear();
|
|
|
|
if (Event == null || Event._PersistentCalls == null)
|
|
return;
|
|
|
|
for (int i = 0; i < Event._PersistentCalls.Count; i++)
|
|
{
|
|
var call = Event._PersistentCalls[i];
|
|
PersistentMethodCache.Add(call != null ? call.GetMethodSafe() : null);
|
|
}
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Ensures that any linked parameters remain linked to the correct target index.</summary>
|
|
public void UpdateLinkedArguments()
|
|
{
|
|
if (Event == null ||
|
|
PersistentMethodCache.Count == 0)
|
|
return;
|
|
|
|
for (int i = 0; i < Event._PersistentCalls.Count; i++)
|
|
{
|
|
var call = Event._PersistentCalls[i];
|
|
if (call == null)
|
|
continue;
|
|
|
|
for (int j = 0; j < call._PersistentArguments.Length; j++)
|
|
{
|
|
var argument = call._PersistentArguments[j];
|
|
if (argument == null || argument._Type != PersistentArgumentType.ReturnValue)
|
|
continue;
|
|
|
|
var linkedMethod = PersistentMethodCache[argument.ReturnedValueIndex];
|
|
|
|
if (argument.ReturnedValueIndex < Event._PersistentCalls.Count)
|
|
{
|
|
var linkedCall = Event._PersistentCalls[argument.ReturnedValueIndex];
|
|
if (linkedMethod == (linkedCall != null ? linkedCall.GetMethodSafe() : null))
|
|
continue;
|
|
}
|
|
|
|
var index = IndexOfMethod(linkedMethod);
|
|
if (index >= 0)
|
|
argument.ReturnedValueIndex = index;
|
|
}
|
|
}
|
|
|
|
PersistentMethodCache.Clear();
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Returns the index of the persistent call that targets the specified `method` or -1 if there is none.</summary>
|
|
public int IndexOfMethod(MethodBase method)
|
|
{
|
|
for (int i = 0; i < Event._PersistentCalls.Count; i++)
|
|
{
|
|
var call = Event._PersistentCalls[i];
|
|
if ((call != null ? call.GetMethodSafe() : null) == method)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Returns the method cached from the persistent call at the specified `index`.</summary>
|
|
public MethodBase GetLinkedMethod(int index)
|
|
{
|
|
if (index >= 0 && index < PersistentMethodCache.Count)
|
|
return PersistentMethodCache[index];
|
|
else
|
|
return null;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
#endregion
|
|
/************************************************************************************************************************/
|
|
#region Previous Call Cache
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Tries to get the details of the a parameter or return value of the specified `type`.</summary>
|
|
public bool TryGetLinkable(Type type, out int linkIndex, out PersistentArgumentType linkType)
|
|
{
|
|
if (Event != null)
|
|
{
|
|
// Parameters.
|
|
var parameterTypes = Event.ParameterTypes;
|
|
for (int i = 0; i < parameterTypes.Length; i++)
|
|
{
|
|
if (type.IsAssignableFrom(parameterTypes[i]))
|
|
{
|
|
linkIndex = i;
|
|
linkType = PersistentArgumentType.Parameter;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Return Values.
|
|
for (int i = 0; i < PreviousCalls.Count; i++)
|
|
{
|
|
var method = PreviousCalls[i].GetMethodSafe();
|
|
if (method == null)
|
|
continue;
|
|
|
|
if (type.IsAssignableFrom(method.GetReturnType()))
|
|
{
|
|
linkIndex = i;
|
|
linkType = PersistentArgumentType.ReturnValue;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
linkIndex = -1;
|
|
linkType = PersistentArgumentType.None;
|
|
return false;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Tries to get the details of the a parameter or return value of the current parameter type.</summary>
|
|
public bool TryGetLinkable(out int linkIndex, out PersistentArgumentType linkType)
|
|
{
|
|
if (callParameters != null)
|
|
{
|
|
return TryGetLinkable(CurrentParameter.ParameterType, out linkIndex, out linkType);
|
|
}
|
|
else
|
|
{
|
|
linkIndex = -1;
|
|
linkType = PersistentArgumentType.None;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>The number of persistent calls that came earlier in the current event.</summary>
|
|
public int PreviousCallCount
|
|
{
|
|
get { return PreviousCalls.Count; }
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Returns the persistent call at the specified index in the current event.</summary>
|
|
public PersistentCall GetPreviousCall(int index)
|
|
{
|
|
if (index >= 0 && index < PreviousCalls.Count)
|
|
return PreviousCalls[index];
|
|
else
|
|
return null;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
#endregion
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Copies the contents of the `other` state to overwrite this one.</summary>
|
|
public void CopyFrom(DrawerState other)
|
|
{
|
|
EventProperty = other.EventProperty;
|
|
Event = other.Event;
|
|
|
|
CallProperty = other.CallProperty;
|
|
TargetProperty = other.TargetProperty;
|
|
MethodNameProperty = other.MethodNameProperty;
|
|
PersistentArgumentsProperty = other.PersistentArgumentsProperty;
|
|
|
|
callIndex = other.callIndex;
|
|
call = other.call;
|
|
callParameters = other.callParameters;
|
|
parameterIndex = other.parameterIndex;
|
|
|
|
PreviousCalls.Clear();
|
|
PreviousCalls.AddRange(other.PreviousCalls);
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Clears all the details of this state.</summary>
|
|
public void Clear()
|
|
{
|
|
EventProperty = null;
|
|
Event = null;
|
|
|
|
CallProperty = null;
|
|
TargetProperty = null;
|
|
MethodNameProperty = null;
|
|
PersistentArgumentsProperty = null;
|
|
|
|
callIndex = -1;
|
|
call = null;
|
|
callParameters = null;
|
|
parameterIndex = 0;
|
|
|
|
PreviousCalls.Clear();
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
}
|
|
|
|
#endif
|