Files
Unity-Serializable-Func/Editor/Extensions/DropdownField/DropdownFieldExtensions.cs

129 lines
4.4 KiB
C#

#if UNITY_EDITOR
using System;
using System.Linq.Expressions;
using System.Reflection;
using UnityEditor;
namespace SerializableFunc.Editor.Extensions.DropdownField
{
public static class DropdownFieldExtensions
{
private static Type genericOSMenuType;
private static Type iGenericMenuInterfaceType;
private const string CreateMenuCallback_Property_Name = "createMenuCallback";
private const string GenericOsMenu_Type_Name = "UnityEditor.UIElements.GenericOSMenu";
private const string IGenericMenu_Type_Name = "IGenericMenu";
private const string FormatSelectedValueCallback_Property_Name = "formatSelectedValueCallback";
#region Generic Menu Assigning
public static void AssignGenericMenu(this UnityEngine.UIElements.DropdownField dropdownField,
Func<GenericMenu> genericMenuBuildingFunc)
{
Func<object> genericOSMenuFunc = () =>
{
GenericMenu menu = genericMenuBuildingFunc();
return GetGenericOSMenu(menu);
};
object boxedfunc = ConvertFuncToDesiredType(genericOSMenuFunc);
FieldInfo createMenuCallbackFieldInfo = typeof(UnityEngine.UIElements.DropdownField)
.GetField(CreateMenuCallback_Property_Name, BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
createMenuCallbackFieldInfo.SetValue(dropdownField, boxedfunc);
}
#region Generic OS Menu Creation
private static object GetGenericOSMenu(GenericMenu menu)
{
Type type = GetGenericOSMenuType();
object[] args = new object[] { menu };
return Activator.CreateInstance(type, args);
}
#endregion
#region Type helpers
private static Type GetGenericOSMenuType()
{
if (genericOSMenuType == null)
{
genericOSMenuType = typeof(UnityEditor.UIElements.ColorField).Assembly.GetType(GenericOsMenu_Type_Name, false, true);
}
return genericOSMenuType;
}
private static Type GetIGenericMenuInterfaceType()
{
if (iGenericMenuInterfaceType == null)
{
Type genericOSType = GetGenericOSMenuType();
iGenericMenuInterfaceType = genericOSType.GetInterface(IGenericMenu_Type_Name);
}
return iGenericMenuInterfaceType;
}
#endregion
#region Func Conversion
private static Delegate ConvertFuncToDesiredType(Func<object> func)
{
Type interfaceType = GetIGenericMenuInterfaceType();
Type resultType = typeof(Func<>).MakeGenericType(interfaceType);
Expression<Func<object>> expressionFunc = FuncToExpression(func);
InvocationExpression invokedExpression = Expression.Invoke(expressionFunc);
UnaryExpression convertedReturnValue = Expression.Convert(invokedExpression, interfaceType);
LambdaExpression lambda = Expression.Lambda(delegateType: resultType, body: convertedReturnValue);
return lambda.Compile();
}
private static Expression<Func<T>> FuncToExpression<T>(Func<T> f)
{
return () => f();
}
#endregion
#endregion
#region Formatting Callback Assigning
public static void AssignFormattingCallback(this UnityEngine.UIElements.DropdownField dropdownField,
Func<string, string> formattingCallback)
{
#if UNITY_2022_2_OR_NEWER
dropdownField.formatSelectedValueCallback = formattingCallback;
#else
AssignFormattingCallbackViaReflection(dropdownField, formattingCallback);
#endif
}
private static void AssignFormattingCallbackViaReflection(this UnityEngine.UIElements.DropdownField functionDropdown,
Func<string, string> formattingCallback)
{
PropertyInfo propertyInfo = typeof(UnityEngine.UIElements.DropdownField)
.GetProperty(FormatSelectedValueCallback_Property_Name, BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
object[] args = new object[] { formattingCallback };
propertyInfo.SetMethod.Invoke(functionDropdown, args);
}
#endregion
}
}
#endif