144 lines
5.3 KiB
C#
144 lines
5.3 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using UnityEditor.IMGUI.Controls;
|
|
using MBT;
|
|
|
|
namespace MBTEditor
|
|
{
|
|
public class ClassTypeDropdownItem : AdvancedDropdownItem
|
|
{
|
|
public Type classType;
|
|
public int order;
|
|
public string path;
|
|
|
|
public ClassTypeDropdownItem(string name, Type type = null, int order = 1000, string path = "") : base(name)
|
|
{
|
|
this.classType = type;
|
|
this.order = order;
|
|
this.path = path;
|
|
}
|
|
}
|
|
|
|
public class NodeDropdown : AdvancedDropdown
|
|
{
|
|
protected Action<ClassTypeDropdownItem> Callback;
|
|
|
|
public NodeDropdown(AdvancedDropdownState state, Action<ClassTypeDropdownItem> callback) : base(state)
|
|
{
|
|
this.Callback = callback;
|
|
minimumSize = new Vector2(230,320);
|
|
}
|
|
|
|
protected override AdvancedDropdownItem BuildRoot()
|
|
{
|
|
var root = new ClassTypeDropdownItem("Nodes");
|
|
|
|
// List for all found subclasses
|
|
List<Type> results = new List<Type>();
|
|
|
|
// Search all assemblies
|
|
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
|
{
|
|
// Find all subclasses of Node
|
|
IEnumerable<Type> enumerable = assembly.GetTypes()
|
|
.Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(Node)));
|
|
results.AddRange(enumerable);
|
|
}
|
|
|
|
// Keep track of all paths to correctly build tree later
|
|
Dictionary<string, ClassTypeDropdownItem> nodePathsDictionary = new Dictionary<string, ClassTypeDropdownItem>();
|
|
nodePathsDictionary.Add("", root);
|
|
// Create list of items
|
|
List<ClassTypeDropdownItem> items = new List<ClassTypeDropdownItem>();
|
|
foreach (Type type in results)
|
|
{
|
|
if(type.IsDefined(typeof(MBTNode), false))
|
|
{
|
|
MBTNode nodeMeta = type.GetCustomAttribute<MBTNode>();
|
|
string itemName;
|
|
string nodePath = "";
|
|
if (String.IsNullOrEmpty(nodeMeta.name))
|
|
{
|
|
itemName = type.Name;
|
|
}
|
|
else
|
|
{
|
|
string[] path = nodeMeta.name.Split('/');
|
|
itemName = path[path.Length-1];
|
|
nodePath = BuildPathIfNotExists(path, ref nodePathsDictionary);
|
|
}
|
|
ClassTypeDropdownItem classTypeDropdownItem = new ClassTypeDropdownItem(itemName, type, nodeMeta.order, nodePath);
|
|
if (nodeMeta.icon != null)
|
|
{
|
|
classTypeDropdownItem.icon = Resources.Load(nodeMeta.icon, typeof(Texture2D)) as Texture2D;
|
|
}
|
|
items.Add(classTypeDropdownItem);
|
|
}
|
|
}
|
|
|
|
// Sort items
|
|
items.Sort((x, y) => {
|
|
int result = x.order.CompareTo(y.order);
|
|
return result != 0 ? result : x.name.CompareTo(y.name);
|
|
});
|
|
|
|
// Add all nodes to menu
|
|
for (int i = 0; i < items.Count; i++)
|
|
{
|
|
nodePathsDictionary[items[i].path].AddChild(items[i]);
|
|
}
|
|
|
|
// Remove root to avoid infinite root folder loop
|
|
nodePathsDictionary.Remove("");
|
|
List<ClassTypeDropdownItem> parentNodes = nodePathsDictionary.Values.ToList();
|
|
parentNodes.Sort((x, y) => {
|
|
return x.name.CompareTo(y.name);
|
|
});
|
|
|
|
// Add folders
|
|
for (int i = 0; i < parentNodes.Count(); i++)
|
|
{
|
|
root.AddChild(parentNodes[i]);
|
|
}
|
|
|
|
return root;
|
|
}
|
|
|
|
protected override void ItemSelected(AdvancedDropdownItem item)
|
|
{
|
|
Callback(item as ClassTypeDropdownItem);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates nodes if path does not exists. Supports only signle level folders.
|
|
/// </summary>
|
|
/// <param name="path">Path to build. Last element should be actual node name.</param>
|
|
/// <param name="dictionary">Reference to dictionary to store references to items</param>
|
|
/// <returns>Path to provided node in path</returns>
|
|
protected string BuildPathIfNotExists(string[] path, ref Dictionary<string, ClassTypeDropdownItem> dictionary)
|
|
{
|
|
// IMPORTANT: This code supports only single level folders. Nodes can't be nested more than one level.
|
|
if (path.Length != 2)
|
|
{
|
|
return "";
|
|
}
|
|
AdvancedDropdownItem root = dictionary[""];
|
|
// // This code assumes the last element of path is actual name of node
|
|
// string nodePath = String.Join("/", path, 0, path.Length-1);
|
|
string nodePath = path[0];
|
|
// Create path nodes if does not exists
|
|
if(!dictionary.ContainsKey(nodePath))
|
|
{
|
|
ClassTypeDropdownItem node = new ClassTypeDropdownItem(nodePath);
|
|
dictionary.Add(nodePath, node);
|
|
}
|
|
return nodePath;
|
|
}
|
|
}
|
|
}
|