123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using UnityEngine;
- using UnityEditor.UIElements;
- using UnityEditor.Experimental.GraphView;
- using UnityEngine.UIElements;
- using UnityEditor;
- namespace GraphProcessor
- {
- // TODO: replace this by the new UnityEditor.Searcher package
- class CreateNodeMenuWindow : ScriptableObject, ISearchWindowProvider
- {
- BaseGraphView graphView;
- EditorWindow window;
- Texture2D icon;
- EdgeView edgeFilter;
- PortView inputPortView;
- PortView outputPortView;
- public void Initialize(BaseGraphView graphView, EditorWindow window, EdgeView edgeFilter = null)
- {
- this.graphView = graphView;
- this.window = window;
- this.edgeFilter = edgeFilter;
- this.inputPortView = edgeFilter?.input as PortView;
- this.outputPortView = edgeFilter?.output as PortView;
- // Transparent icon to trick search window into indenting items
- if (icon == null)
- icon = new Texture2D(1, 1);
- icon.SetPixel(0, 0, new Color(0, 0, 0, 0));
- icon.Apply();
- }
- void OnDestroy()
- {
- if (icon != null)
- {
- DestroyImmediate(icon);
- icon = null;
- }
- }
- public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
- {
- var tree = new List<SearchTreeEntry>
- {
- new SearchTreeGroupEntry(new GUIContent("Create Node"), 0),
- };
- if (edgeFilter == null)
- CreateStandardNodeMenu(tree);
- else
- CreateEdgeNodeMenu(tree);
- return tree;
- }
- void CreateStandardNodeMenu(List<SearchTreeEntry> tree)
- {
- // Sort menu by alphabetical order and submenus
- var nodeEntries = graphView.FilterCreateNodeMenuEntries().OrderBy(k => k.path);
- var titlePaths = new HashSet< string >();
-
- foreach (var nodeMenuItem in nodeEntries)
- {
- var nodePath = nodeMenuItem.path;
- var nodeName = nodePath;
- var level = 0;
- var parts = nodePath.Split('/');
- if(parts.Length > 1)
- {
- level++;
- nodeName = parts[parts.Length - 1];
- var fullTitleAsPath = "";
-
- for(var i = 0; i < parts.Length - 1; i++)
- {
- var title = parts[i];
- fullTitleAsPath += title;
- level = i + 1;
-
- // Add section title if the node is in subcategory
- if (!titlePaths.Contains(fullTitleAsPath))
- {
- tree.Add(new SearchTreeGroupEntry(new GUIContent(title)){
- level = level
- });
- titlePaths.Add(fullTitleAsPath);
- }
- }
- }
-
- tree.Add(new SearchTreeEntry(new GUIContent(nodeName, icon))
- {
- level = level + 1,
- userData = nodeMenuItem.type
- });
- }
- }
- void CreateEdgeNodeMenu(List<SearchTreeEntry> tree)
- {
- var entries = NodeProvider.GetEdgeCreationNodeMenuEntry((edgeFilter.input ?? edgeFilter.output) as PortView, graphView.graph);
- var titlePaths = new HashSet< string >();
- var nodePaths = NodeProvider.GetNodeMenuEntries(graphView.graph);
- tree.Add(new SearchTreeEntry(new GUIContent($"Relay", icon))
- {
- level = 1,
- userData = new NodeProvider.PortDescription{
- nodeType = typeof(RelayNode),
- portType = typeof(System.Object),
- isInput = inputPortView != null,
- portFieldName = inputPortView != null ? nameof(RelayNode.output) : nameof(RelayNode.input),
- portIdentifier = "0",
- portDisplayName = inputPortView != null ? "Out" : "In",
- }
- });
- var sortedMenuItems = entries.Select(port => (port, nodePaths.FirstOrDefault(kp => kp.type == port.nodeType).path)).OrderBy(e => e.path);
- // Sort menu by alphabetical order and submenus
- foreach (var nodeMenuItem in sortedMenuItems)
- {
- var nodePath = nodePaths.FirstOrDefault(kp => kp.type == nodeMenuItem.port.nodeType).path;
- // Ignore the node if it's not in the create menu
- if (String.IsNullOrEmpty(nodePath))
- continue;
- var nodeName = nodePath;
- var level = 0;
- var parts = nodePath.Split('/');
- if (parts.Length > 1)
- {
- level++;
- nodeName = parts[parts.Length - 1];
- var fullTitleAsPath = "";
-
- for (var i = 0; i < parts.Length - 1; i++)
- {
- var title = parts[i];
- fullTitleAsPath += title;
- level = i + 1;
- // Add section title if the node is in subcategory
- if (!titlePaths.Contains(fullTitleAsPath))
- {
- tree.Add(new SearchTreeGroupEntry(new GUIContent(title)){
- level = level
- });
- titlePaths.Add(fullTitleAsPath);
- }
- }
- }
- tree.Add(new SearchTreeEntry(new GUIContent($"{nodeName}: {nodeMenuItem.port.portDisplayName}", icon))
- {
- level = level + 1,
- userData = nodeMenuItem.port
- });
- }
- }
- // Node creation when validate a choice
- public bool OnSelectEntry(SearchTreeEntry searchTreeEntry, SearchWindowContext context)
- {
- // window to graph position
- var windowRoot = window.rootVisualElement;
- var windowMousePosition = windowRoot.ChangeCoordinatesTo(windowRoot.parent, context.screenMousePosition - window.position.position);
- var graphMousePosition = graphView.contentViewContainer.WorldToLocal(windowMousePosition);
- var nodeType = searchTreeEntry.userData is Type ? (Type)searchTreeEntry.userData : ((NodeProvider.PortDescription)searchTreeEntry.userData).nodeType;
-
- graphView.RegisterCompleteObjectUndo("Added " + nodeType);
- var view = graphView.AddNode(BaseNode.CreateFromType(nodeType, graphMousePosition));
- if (searchTreeEntry.userData is NodeProvider.PortDescription desc)
- {
- var targetPort = view.GetPortViewFromFieldName(desc.portFieldName, desc.portIdentifier);
- if (inputPortView == null)
- graphView.Connect(targetPort, outputPortView);
- else
- graphView.Connect(inputPortView, targetPort);
- }
- return true;
- }
- }
- }
|