void AddNode(ClassTypeDropdownItem item) { // In case there is nothing to add if (currentMBT == null || item.classType == null) { return; } // Allow only one root if (item.classType.IsAssignableFrom(typeof(Root)) && currentMBT.GetComponent <Root>() != null) { Debug.LogWarning("You can not add more than one Root node."); return; } Undo.SetCurrentGroupName("Create Node"); Node node = (Node)Undo.AddComponent(currentMBT.gameObject, item.classType); node.title = item.name; node.hideFlags = HideFlags.HideInInspector; node.rect.position = nodeDropdownTargetPosition - new Vector2(node.rect.width / 2, 0); UpdateSelection(); if (dropdownHandleCache != null) { // Add additonal offset (3,3) to be sure that point is inside rect TryConnectNodes(dropdownHandleCache, nodeDropdownTargetPosition + workspaceOffset + new Vector2(3, 3)); } }
/// <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); }
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); }