Initial Commit
This commit is contained in:
8
Editor/Extensions/Dropdown Field.meta
Normal file
8
Editor/Extensions/Dropdown Field.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49fcc97bf68f1be43af4476942bfc60e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
130
Editor/Extensions/Dropdown Field/DropdownFieldExtensions.cs
Normal file
130
Editor/Extensions/Dropdown Field/DropdownFieldExtensions.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Utilities.Extensions.UIToolkit
|
||||
{
|
||||
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 DropdownField dropdownField,
|
||||
Func<GenericMenu> genericMenuBuildingFunc)
|
||||
{
|
||||
Func<object> genericOSMenuFunc = () =>
|
||||
{
|
||||
GenericMenu menu = genericMenuBuildingFunc();
|
||||
return GetGenericOSMenu(menu);
|
||||
};
|
||||
|
||||
object boxedfunc = ConvertFuncToDesiredType(genericOSMenuFunc);
|
||||
|
||||
FieldInfo createMenuCallbackFieldInfo = typeof(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 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 DropdownField functionDropdown,
|
||||
Func<string, string> formattingCallback)
|
||||
{
|
||||
PropertyInfo propertyInfo = typeof(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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f923456164a309c4d81abab46ab3f8ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Editor/Extensions/SerializedProperty.meta
Normal file
8
Editor/Extensions/SerializedProperty.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4950e11fcaa85be40ba5df654ee71efb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,147 @@
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Utilities.SerializableData.SerializableFunc.UnityEditorUtilities
|
||||
{
|
||||
public static class SerializedPropertyExtensions
|
||||
{
|
||||
static readonly Regex rgx = new Regex(@"\[\d+\]", RegexOptions.Compiled);
|
||||
|
||||
public static object GetBoxedValue(this SerializedProperty property)
|
||||
{
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
#if UNITY_2023_2_OR_NEWER
|
||||
return property.boxedValue;
|
||||
#else
|
||||
return GetValue<object>(property);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void SetBoxedValue(this SerializedProperty property, object value)
|
||||
{
|
||||
property.serializedObject.Update();
|
||||
#if UNITY_2023_2_OR_NEWER
|
||||
property.boxedValue = value;
|
||||
#else
|
||||
SetValue<object>(property, value);
|
||||
#endif
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
public static T GetValue<T>(this SerializedProperty property) where T : class
|
||||
{
|
||||
object obj = property.serializedObject.targetObject;
|
||||
string path = property.propertyPath.Replace(".Array.data", string.Empty);
|
||||
string[] fieldStructure = path.Split('.');
|
||||
for (int i = 0; i < fieldStructure.Length; i++)
|
||||
{
|
||||
if (fieldStructure[i].Contains("["))
|
||||
{
|
||||
int index = System.Convert.ToInt32(new string(fieldStructure[i].Where(c => char.IsDigit(c)).ToArray()));
|
||||
obj = GetFieldValueWithIndex(rgx.Replace(fieldStructure[i], string.Empty), obj, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = GetFieldValue(fieldStructure[i], obj);
|
||||
}
|
||||
}
|
||||
return (T)obj;
|
||||
}
|
||||
|
||||
public static bool SetValue<T>(this SerializedProperty property, T value) where T : class
|
||||
{
|
||||
object obj = property.serializedObject.targetObject;
|
||||
string path = property.propertyPath.Replace(".Array.data", "");
|
||||
string[] fieldStructure = path.Split('.');
|
||||
for (int i = 0; i < fieldStructure.Length - 1; i++)
|
||||
{
|
||||
if (fieldStructure[i].Contains("["))
|
||||
{
|
||||
int index = System.Convert.ToInt32(new string(fieldStructure[i].Where(c => char.IsDigit(c)).ToArray()));
|
||||
obj = GetFieldValueWithIndex(rgx.Replace(fieldStructure[i], ""), obj, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = GetFieldValue(fieldStructure[i], obj);
|
||||
}
|
||||
}
|
||||
|
||||
string fieldName = fieldStructure.Last();
|
||||
if (fieldName.Contains("["))
|
||||
{
|
||||
int index = System.Convert.ToInt32(new string(fieldName.Where(c => char.IsDigit(c)).ToArray()));
|
||||
return SetFieldValueWithIndex(rgx.Replace(fieldName, ""), obj, index, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return SetFieldValue(fieldName, obj, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static object GetFieldValue(string fieldName, object obj, BindingFlags bindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
{
|
||||
FieldInfo field = obj.GetType().GetField(fieldName, bindings);
|
||||
if (field != null)
|
||||
{
|
||||
return field.GetValue(obj);
|
||||
}
|
||||
return default(object);
|
||||
}
|
||||
|
||||
private static object GetFieldValueWithIndex(string fieldName, object obj, int index, BindingFlags bindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
{
|
||||
FieldInfo field = obj.GetType().GetField(fieldName, bindings);
|
||||
if (field != null)
|
||||
{
|
||||
object list = field.GetValue(obj);
|
||||
if (list.GetType().IsArray)
|
||||
{
|
||||
return ((object[])list)[index];
|
||||
}
|
||||
else if (list is IEnumerable)
|
||||
{
|
||||
return ((IList)list)[index];
|
||||
}
|
||||
}
|
||||
return default(object);
|
||||
}
|
||||
|
||||
public static bool SetFieldValue(string fieldName, object obj, object value, bool includeAllBases = false, BindingFlags bindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
{
|
||||
FieldInfo field = obj.GetType().GetField(fieldName, bindings);
|
||||
if (field != null)
|
||||
{
|
||||
field.SetValue(obj, value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool SetFieldValueWithIndex(string fieldName, object obj, int index, object value, bool includeAllBases = false, BindingFlags bindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
{
|
||||
FieldInfo field = obj.GetType().GetField(fieldName, bindings);
|
||||
if (field != null)
|
||||
{
|
||||
object list = field.GetValue(obj);
|
||||
if (list.GetType().IsArray)
|
||||
{
|
||||
((object[])list)[index] = value;
|
||||
return true;
|
||||
}
|
||||
else if (list is IEnumerable)
|
||||
{
|
||||
((IList)list)[index] = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9092eebd24b0d8d4985c409afe2768d4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Editor/Extensions/Type Extensions.meta
Normal file
8
Editor/Extensions/Type Extensions.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8bb44bb4f5e72344b87845ac17958288
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
60
Editor/Extensions/Type Extensions/TypeExtensions.cs
Normal file
60
Editor/Extensions/Type Extensions/TypeExtensions.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Utilities.Extensions.SystemExtensions
|
||||
{
|
||||
public static class TypeExtensions
|
||||
{
|
||||
private static Dictionary<Type, string> PrimitiveTypesLookup = new Dictionary<Type, string>
|
||||
{
|
||||
{ typeof(bool), "Bool" },
|
||||
{ typeof(byte), "Byte" },
|
||||
{ typeof(char), "Char" },
|
||||
{ typeof(decimal), "Decimal" },
|
||||
{ typeof(double), "Double" },
|
||||
{ typeof(float), "Float" },
|
||||
{ typeof(int), "Int" },
|
||||
{ typeof(long), "Long" },
|
||||
{ typeof(sbyte), "Sbyte" },
|
||||
{ typeof(short), "Short" },
|
||||
{ typeof(string), "String" },
|
||||
{ typeof(uint), "Uint" },
|
||||
{ typeof(ulong), "Ulong" },
|
||||
{ typeof(ushort), "Ushort" },
|
||||
};
|
||||
|
||||
public static string NicifyTypeName(this Type type)
|
||||
{
|
||||
if (type.IsArray)
|
||||
{
|
||||
Type elementType = type.GetElementType();
|
||||
string elementTypeString = NicifyTypeName(elementType);
|
||||
return $"{elementTypeString}[]";
|
||||
}
|
||||
|
||||
if (!type.IsGenericType)
|
||||
{
|
||||
return GetSingleTypeName(type);
|
||||
}
|
||||
|
||||
if (type.IsNested && type.DeclaringType.IsGenericType) return type.Name;
|
||||
|
||||
string genericTypeString = $"{type.Name[..type.Name.IndexOf('`')]}";
|
||||
|
||||
IEnumerable<string> genericArgumentNames = type.GetGenericArguments()
|
||||
.Select(x => NicifyTypeName(x));
|
||||
|
||||
string genericArgumentsString = string.Join(", ", genericArgumentNames);
|
||||
|
||||
return $"{genericTypeString}<{genericArgumentsString}>";
|
||||
}
|
||||
|
||||
private static string GetSingleTypeName(Type type)
|
||||
{
|
||||
if (PrimitiveTypesLookup.TryGetValue(type, out string result)) return result;
|
||||
|
||||
return type.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Editor/Extensions/Type Extensions/TypeExtensions.cs.meta
Normal file
11
Editor/Extensions/Type Extensions/TypeExtensions.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46fcb395397539e4f99e257852dcaaa7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user