protected override void ConstructFieldTemplates(NodeProvider nodeProvider, Dictionary <Type, NodeFieldTemplate> templates) { NodeLibrary library = nodeProvider.GetNodeLibrary(); foreach (var nodeTemplate in library.nodeTemplates) { Type type = nodeTemplate.RuntimeNodeType; var template = new NodeFieldTemplate(); var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (var field in fields) { bool isPrivate = field.IsPrivate; if (IsOutput(field)) { template.OutputPorts.Add(new Ports.PortDescription(field.Name, field.FieldType, PortDirection.Output, false, false)); } else if (IsInput(field)) { template.OutputPorts.Add(new Ports.PortDescription(field.Name, field.FieldType, PortDirection.Input, false, false)); } else { template.Properties.Add(new PropertyDescription { FieldType = field }); } } templates.Add(type, template); } }
protected override void ConstructFieldTemplates(NodeProvider nodeProvider, Dictionary <Type, NodeFieldTemplate> templates) { NodeLibrary library = nodeProvider.GetNodeLibrary(); foreach (var nodeTemplate in library.nodeTemplates) { Type type = nodeTemplate.RuntimeNodeType; var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); var template = new NodeFieldTemplate(); var supressInput = type.GetCustomAttribute <SupressInputAttribute>(); // All tasks (nodes in this case) need to have an input, that isnt in the code of the behaviours // so we just add it in the first thing we do. if (supressInput == null) { template.InputPorts.Add(new PortDescription("Input", typeof(Task), PortDirection.Input, false, false)); } foreach (var field in fields) { OutputAttribute output = field.GetCustomAttribute <OutputAttribute>(); InputAttribute input = field.GetCustomAttribute <InputAttribute>(); SerializeField property = field.GetCustomAttribute <SerializeField>(); bool autoAdd = false; bool isInput = input == null ? false : true; bool isOutput = output == null ? false : true; if (output != null) { autoAdd = output.AutoAddPortOnConnect; } if (input != null) { autoAdd = input.AutoAddPortOnConnect; } bool isList = IsListType(field); if (output != null || input != null) { if (IsListType(field)) { AddGenericPort(template, field, isInput, isOutput, autoAdd); } else { AddNonGenericPort(template, field.FieldType, field.Name, field.Name, isInput, isOutput, autoAdd); } } else if (property != null) { AddNonGenericProperty(template, field, field.Name, field.Name); } } templates.Add(type, template); } }
public List <SearchTreeEntry> CreateSearchTree(SearchWindowContext context) { // First build up temporary data structure containing group & title as an array of strings (the last one is the actual title) and associated node type. if (m_nodeProvider == null) { Debug.LogError("NodeProvider in Node Search Window is null cant construct search tree!"); return(new List <SearchTreeEntry>()); } NodeLibrary nodeLibrary = m_nodeProvider.GetNodeLibrary(); // Sort the entries lexicographically by group then title with the requirement that items always comes before sub-groups in the same group. // Example result: // - Art/BlendMode // - Art/Adjustments/ColorBalance // - Art/Adjustments/Contrast nodeLibrary.nodeTemplates.Sort((entry1, entry2) => { for (var i = 0; i < entry1.Title.Length; i++) { if (i >= entry2.Title.Length) { return(1); } var value = entry1.Title[i].CompareTo(entry2.Title[i]); if (value != 0) { // Make sure that leaves go before nodes if (entry1.Title.Length != entry2.Title.Length && (i == entry1.Title.Length - 1 || i == entry2.Title.Length - 1)) { return(entry1.Title.Length < entry2.Title.Length ? -1 : 1); } return(value); } } return(0); }); //* Build up the data structure needed by SearchWindow. // `groups` contains the current group path we're in. var groups = new List <string>(); // First item in the tree is the title of the window. var tree = new List <SearchTreeEntry> { new SearchTreeGroupEntry(new GUIContent("Add Node"), 0), }; foreach (var nodeEntry in nodeLibrary.nodeTemplates) { // `createIndex` represents from where we should add new group entries from the current entry's group path. var createIndex = int.MaxValue; // Compare the group path of the current entry to the current group path. for (var i = 0; i < nodeEntry.Title.Length - 1; i++) { var group = nodeEntry.Title[i]; if (i >= groups.Count) { // The current group path matches a prefix of the current entry's group path, so we add the // rest of the group path from the currrent entry. createIndex = i; break; } if (groups[i] != group) { // A prefix of the current group path matches a prefix of the current entry's group path, // so we remove everyfrom from the point where it doesn't match anymore, and then add the rest // of the group path from the current entry. groups.RemoveRange(i, groups.Count - i); createIndex = i; break; } } // Create new group entries as needed. // If we don't need to modify the group path, `createIndex` will be `int.MaxValue` and thus the loop won't run. for (var i = createIndex; i < nodeEntry.Title.Length - 1; i++) { var group = nodeEntry.Title[i]; groups.Add(group); tree.Add(new SearchTreeGroupEntry(new GUIContent(group)) { level = i + 1 }); } // Finally, add the actual entry. tree.Add(new SearchTreeEntry(new GUIContent(nodeEntry.Title.Last(), m_icon)) { level = nodeEntry.Title.Length, userData = nodeEntry }); } return(tree); }