Initial commit
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
namespace MackySoft.SerializeReferenceExtensions.Editor {
|
||||
|
||||
public class AdvancedTypePopupItem : AdvancedDropdownItem {
|
||||
|
||||
public Type Type { get; }
|
||||
|
||||
public AdvancedTypePopupItem (Type type,string name) : base(name) {
|
||||
Type = type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A type popup with a fuzzy finder.
|
||||
/// </summary>
|
||||
public class AdvancedTypePopup : AdvancedDropdown {
|
||||
|
||||
public static void AddTo (AdvancedDropdownItem root,IEnumerable<Type> types) {
|
||||
int itemCount = 0;
|
||||
|
||||
// Add null item.
|
||||
var nullItem = new AdvancedTypePopupItem(null,TypeMenuUtility.k_NullDisplayName) {
|
||||
id = itemCount++
|
||||
};
|
||||
root.AddChild(nullItem);
|
||||
|
||||
// Add type items.
|
||||
foreach (Type type in types.OrderByType()) {
|
||||
string[] splittedTypePath = TypeMenuUtility.GetSplittedTypePath(type);
|
||||
if (splittedTypePath.Length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AdvancedDropdownItem parent = root;
|
||||
|
||||
// Add namespace items.
|
||||
for (int k = 0;(splittedTypePath.Length - 1) > k;k++) {
|
||||
AdvancedDropdownItem foundItem = GetItem(parent,splittedTypePath[k]);
|
||||
if (foundItem != null) {
|
||||
parent = foundItem;
|
||||
} else {
|
||||
var newItem = new AdvancedDropdownItem(splittedTypePath[k]) {
|
||||
id = itemCount++,
|
||||
};
|
||||
parent.AddChild(newItem);
|
||||
parent = newItem;
|
||||
}
|
||||
}
|
||||
|
||||
// Add type item.
|
||||
var item = new AdvancedTypePopupItem(type,ObjectNames.NicifyVariableName(splittedTypePath[splittedTypePath.Length - 1])) {
|
||||
id = itemCount++
|
||||
};
|
||||
parent.AddChild(item);
|
||||
}
|
||||
}
|
||||
|
||||
static AdvancedDropdownItem GetItem (AdvancedDropdownItem parent,string name) {
|
||||
foreach (AdvancedDropdownItem item in parent.children) {
|
||||
if (item.name == name) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static readonly float k_HeaderHeight = EditorGUIUtility.singleLineHeight * 2f;
|
||||
|
||||
Type[] m_Types;
|
||||
|
||||
public event Action<AdvancedTypePopupItem> OnItemSelected;
|
||||
|
||||
public AdvancedTypePopup (IEnumerable<Type> types,int maxLineCount,AdvancedDropdownState state) : base(state) {
|
||||
SetTypes(types);
|
||||
minimumSize = new Vector2(minimumSize.x,EditorGUIUtility.singleLineHeight * maxLineCount + k_HeaderHeight);
|
||||
}
|
||||
|
||||
public void SetTypes (IEnumerable<Type> types) {
|
||||
m_Types = types.ToArray();
|
||||
}
|
||||
|
||||
protected override AdvancedDropdownItem BuildRoot () {
|
||||
var root = new AdvancedDropdownItem("Select Type");
|
||||
AddTo(root,m_Types);
|
||||
return root;
|
||||
}
|
||||
|
||||
protected override void ItemSelected (AdvancedDropdownItem item) {
|
||||
base.ItemSelected(item);
|
||||
if (item is AdvancedTypePopupItem typePopupItem) {
|
||||
OnItemSelected?.Invoke(typePopupItem);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d8065888a2f3464e9252691fa1376a2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "MackySoft.SerializeReferenceExtensions.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:49b49c76ee64f6b41bf28ef951cb0e50"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [
|
||||
"UNITY_2019_3_OR_NEWER"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6234d6c1f7bf4e4db20eddc411c00b8
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
|
||||
namespace MackySoft.SerializeReferenceExtensions.Editor {
|
||||
public static class ManagedReferenceUtility {
|
||||
|
||||
public static Type GetManagedReferenceFieldType (this SerializedProperty property) {
|
||||
if (property.propertyType != SerializedPropertyType.ManagedReference) {
|
||||
throw SerializedPropertyTypeMustBeManagedReference(nameof(property));
|
||||
}
|
||||
return GetType(property.managedReferenceFieldTypename);
|
||||
}
|
||||
|
||||
public static Type GetManagedReferenceType (this SerializedProperty property) {
|
||||
if (property.propertyType != SerializedPropertyType.ManagedReference) {
|
||||
throw SerializedPropertyTypeMustBeManagedReference(nameof(property));
|
||||
}
|
||||
return GetType(property.managedReferenceFullTypename);
|
||||
}
|
||||
|
||||
public static object SetManagedReference (this SerializedProperty property,Type type) {
|
||||
object obj = (type != null) ? Activator.CreateInstance(type) : null;
|
||||
property.managedReferenceValue = obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
static Type GetType (string typeName) {
|
||||
int splitIndex = typeName.IndexOf(' ');
|
||||
var assembly = Assembly.Load(typeName.Substring(0,splitIndex));
|
||||
return assembly.GetType(typeName.Substring(splitIndex + 1));
|
||||
}
|
||||
|
||||
static ArgumentException SerializedPropertyTypeMustBeManagedReference (string paramName) {
|
||||
return new ArgumentException("The serialized property type must be SerializedPropertyType.ManagedReference.",paramName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 065a93e92875c4440b7c2168bead041a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
namespace MackySoft.SerializeReferenceExtensions.Editor {
|
||||
|
||||
[CustomPropertyDrawer(typeof(SubclassSelectorAttribute))]
|
||||
public class SubclassSelectorDrawer : PropertyDrawer {
|
||||
|
||||
struct TypePopupCache {
|
||||
public AdvancedTypePopup TypePopup { get; }
|
||||
public AdvancedDropdownState State { get; }
|
||||
public TypePopupCache (AdvancedTypePopup typePopup,AdvancedDropdownState state) {
|
||||
TypePopup = typePopup;
|
||||
State = state;
|
||||
}
|
||||
}
|
||||
|
||||
const int k_MaxTypePopupLineCount = 13;
|
||||
static readonly Type k_UnityObjectType = typeof(UnityEngine.Object);
|
||||
static readonly GUIContent k_IsNotManagedReferenceLabel = new GUIContent("The property type is not manage reference.");
|
||||
|
||||
readonly Dictionary<string,TypePopupCache> m_TypePopups = new Dictionary<string,TypePopupCache>();
|
||||
|
||||
SerializedProperty m_TargetProperty;
|
||||
|
||||
public override void OnGUI (Rect position,SerializedProperty property,GUIContent label) {
|
||||
EditorGUI.BeginProperty(position,label,property);
|
||||
|
||||
if (property.propertyType == SerializedPropertyType.ManagedReference) {
|
||||
TypePopupCache popup = GetTypePopup(property);
|
||||
|
||||
// Draw the subclass selector popup.
|
||||
Rect popupPosition = new Rect(position);
|
||||
popupPosition.width -= EditorGUIUtility.labelWidth;
|
||||
popupPosition.x += EditorGUIUtility.labelWidth;
|
||||
popupPosition.height = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
if (EditorGUI.DropdownButton(popupPosition,new GUIContent(GetTypeName(property)),FocusType.Keyboard)) {
|
||||
m_TargetProperty = property;
|
||||
popup.TypePopup.Show(popupPosition);
|
||||
}
|
||||
|
||||
// Draw the managed reference property.
|
||||
EditorGUI.PropertyField(position,property,label,true);
|
||||
} else {
|
||||
EditorGUI.LabelField(position,label,k_IsNotManagedReferenceLabel);
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
TypePopupCache GetTypePopup (SerializedProperty property) {
|
||||
if (!m_TypePopups.TryGetValue(property.managedReferenceFieldTypename,out TypePopupCache result)) {
|
||||
var state = new AdvancedDropdownState();
|
||||
|
||||
Type baseType = property.GetManagedReferenceFieldType();
|
||||
var popup = new AdvancedTypePopup(
|
||||
AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(assembly => assembly.GetTypes())
|
||||
.Where(p =>
|
||||
p.IsClass &&
|
||||
(p.IsPublic || p.IsNestedPublic) &&
|
||||
!p.IsAbstract &&
|
||||
!p.IsGenericType &&
|
||||
baseType.IsAssignableFrom(p) &&
|
||||
!k_UnityObjectType.IsAssignableFrom(p) &&
|
||||
Attribute.IsDefined(p,typeof(SerializableAttribute))
|
||||
),
|
||||
k_MaxTypePopupLineCount,
|
||||
state
|
||||
);
|
||||
popup.OnItemSelected += item => {
|
||||
Type type = item.Type;
|
||||
object obj = m_TargetProperty.SetManagedReference(type);
|
||||
m_TargetProperty.isExpanded = (obj != null);
|
||||
m_TargetProperty.serializedObject.ApplyModifiedProperties();
|
||||
};
|
||||
|
||||
m_TypePopups.Add(property.managedReferenceFieldTypename,new TypePopupCache(popup,state));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static string GetTypeName (SerializedProperty property) {
|
||||
if (string.IsNullOrEmpty(property.managedReferenceFullTypename)) {
|
||||
return TypeMenuUtility.k_NullDisplayName;
|
||||
}
|
||||
|
||||
Type type = property.GetManagedReferenceType();
|
||||
|
||||
AddTypeMenuAttribute typeMenu = TypeMenuUtility.GetAttribute(type);
|
||||
if (typeMenu != null) {
|
||||
string typeName = typeMenu.GetTypeNameWithoutPath();
|
||||
if (!string.IsNullOrWhiteSpace(typeName)) {
|
||||
return ObjectNames.NicifyVariableName(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
return ObjectNames.NicifyVariableName(type.Name);
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight (SerializedProperty property,GUIContent label) {
|
||||
return EditorGUI.GetPropertyHeight(property,true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 976888d4f5359f94d8c5417f313acf29
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MackySoft.SerializeReferenceExtensions.Editor {
|
||||
public static class TypeMenuUtility {
|
||||
|
||||
public const string k_NullDisplayName = "<null>";
|
||||
|
||||
public static AddTypeMenuAttribute GetAttribute (Type type) {
|
||||
return Attribute.GetCustomAttribute(type,typeof(AddTypeMenuAttribute)) as AddTypeMenuAttribute;
|
||||
}
|
||||
|
||||
public static string[] GetSplittedTypePath (Type type) {
|
||||
AddTypeMenuAttribute typeMenu = GetAttribute(type);
|
||||
if (typeMenu != null) {
|
||||
return typeMenu.GetSplittedMenuName();
|
||||
} else {
|
||||
int splitIndex = type.FullName.LastIndexOf('.');
|
||||
if (splitIndex >= 0) {
|
||||
return new string[] { type.FullName.Substring(0,splitIndex),type.FullName.Substring(splitIndex + 1) };
|
||||
} else {
|
||||
return new string[] { type.Name };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> OrderByType (this IEnumerable<Type> source) {
|
||||
return source.OrderBy(type => {
|
||||
if (type == null) {
|
||||
return -999;
|
||||
}
|
||||
return GetAttribute(type)?.Order ?? 0;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e692b945af3941745a7004b5b25c5f3b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user