/// <summary> /// Creates a node of the specified ID at pos on the specified canvas, optionally auto-connecting the specified output to a matching input /// silent disables any events, init specifies whether OnCreate should be called /// </summary> public static Node Create(string nodeID, Vector2 pos, NodeCanvas hostCanvas, ConnectionPort connectingPort = null, bool silent = false, bool init = true) { if (string.IsNullOrEmpty(nodeID) || hostCanvas == null) { throw new ArgumentException(); } if (!NodeCanvasManager.CheckCanvasCompability(nodeID, hostCanvas.GetType())) { throw new UnityException("Cannot create Node with ID '" + nodeID + "' as it is not compatible with the current canavs type (" + hostCanvas.GetType().ToString() + ")!"); } if (!hostCanvas.CanAddNode(nodeID)) { throw new UnityException("Cannot create Node with ID '" + nodeID + "' on the current canvas of type (" + hostCanvas.GetType().ToString() + ")!"); } // Create node from data NodeTypeData data = NodeTypes.getNodeData(nodeID); Node node = (Node)CreateInstance(data.type); if (node == null) { return(null); } // Init node state node.name = node.Title; node.autoSize = node.DefaultSize; node.position = pos; node.Canvas = hostCanvas; ConnectionPortManager.UpdateConnectionPorts(node); if (init) { node.OnCreate(); } if (connectingPort != null) { // Handle auto-connection and link the output to the first compatible input for (int i = 0; i < node.connectionPorts.Count; i++) { if (node.connectionPorts[i].TryApplyConnection(connectingPort, silent)) { break; } } } // Add node to host canvas hostCanvas.nodes.Add(node); if (!silent) { // Callbacks hostCanvas.OnNodeChange(connectingPort != null ? connectingPort.body : node); NodeEditorCallbacks.IssueOnAddNode(node); hostCanvas.Validate(); NodeEditor.RepaintClients(); } return(node); }
private static void FillAddNodes(NodeEditorInputInfo inputInfo, GenericMenu canvasContextMenu) { // Fill context menu with nodes to add to the canvas NodeEditorState state = inputInfo.editorState; List <string> nodes = NodeTypes.getCompatibleNodes(state.connectKnob); foreach (string node in nodes) { // Only add nodes to the context menu that are compatible if (NodeCanvasManager.CheckCanvasCompability(node, inputInfo.editorState.canvas.GetType()) && inputInfo.editorState.canvas.CanAddNode(node)) { canvasContextMenu.AddItem(new GUIContent("Add " + NodeTypes.getNodeData(node).adress), false, CreateNodeCallback, new NodeEditorInputInfo(node, state)); } } }
public static Transition Create(Node from, Node to) { if (NodeTypes.getNodeData(from).transitions == false || NodeTypes.getNodeData(to).transitions == false) { return(null); } Transition transition = CreateInstance <Transition> (); transition.name = "Transition " + from.name + "-" + to.name; transition.startNode = from; transition.endNode = to; transition.conditions = new List <Func <Transition, bool> > (); return(transition); }
public static Node MoveNext(Node node) { if (NodeTypes.getNodeData(node).transitions == false) { Debug.LogError("Node " + node.ToString() + " does not accept Transitions!"); return(null); } for (int transCnt = 0; transCnt < node.transitions.Count; transCnt++) { if (node.transitions[transCnt].conditionsMet()) { return(node.transitions[transCnt].endNode); } } return(node); }
/// <summary> /// Checks whether the süecified nodeID is compatible with the given canvas type /// </summary> public static bool CheckCanvasCompability(string nodeID, Type canvasType) { NodeTypeData data = NodeTypes.getNodeData(nodeID); return(data.limitToCanvasTypes == null || data.limitToCanvasTypes.Length == 0 || data.limitToCanvasTypes.Contains(canvasType)); }
/// <summary> /// Processes input events /// </summary> public static void InputEvents(List <Rect> ignoreInput) { Event e = Event.current; mousePos = e.mousePosition; if (OverlayGUI.HasPopupControl()) { return; } bool insideCanvas = curEditorState.canvasRect.Contains(e.mousePosition); for (int ignoreCnt = 0; ignoreCnt < ignoreInput.Count; ignoreCnt++) { if (ignoreInput [ignoreCnt].Contains(e.mousePosition)) { insideCanvas = false; break; } } if (!insideCanvas) { return; } curEditorState.focusedNode = null; if (insideCanvas && (e.type == EventType.MouseDown || e.type == EventType.MouseUp)) { curEditorState.focusedNode = NodeEditor.NodeAtPosition(e.mousePosition); if (e.button == 0) { curEditorState.activeNode = curEditorState.focusedNode; if (Repaint != null) { Repaint(); } } } #if UNITY_EDITOR if (curEditorState.focusedNode != null) { UnityEditor.Selection.activeObject = curEditorState.focusedNode; } #endif switch (e.type) { case EventType.MouseDown: curEditorState.dragNode = false; curEditorState.panWindow = false; if (curEditorState.focusedNode != null) { // A click on a node if (e.button == 1) { // Right click -> Node Context Click // TODO: Node Editor: Editor-Independancy - GenericMenu conversion // #if UNITY_EDITOR // UnityEditor.GenericMenu menu = new UnityEditor.GenericMenu (); // #else GenericMenu menu = new GenericMenu(); // #endif menu.AddItem(new GUIContent("Delete Node"), false, ContextCallback, new callbackObject("deleteNode", curNodeCanvas, curEditorState)); menu.AddItem(new GUIContent("Duplicate Node"), false, ContextCallback, new callbackObject("duplicateNode", curNodeCanvas, curEditorState)); if (NodeTypes.getNodeData(curEditorState.focusedNode).transitions) { menu.AddSeparator("Seperator"); menu.AddItem(new GUIContent("Make Transition"), false, ContextCallback, new callbackObject("startTransition", curNodeCanvas, curEditorState)); } menu.ShowAsContext(); e.Use(); } else if (e.button == 0) { if (!GUIToScreenRect(curEditorState.focusedNode.rect).Contains(e.mousePosition)) { // Left click at node edges -> Check for clicked connections to edit NodeOutput nodeOutput = curEditorState.focusedNode.GetOutputAtPos(e.mousePosition); if (nodeOutput != null) { // Output Node -> New Connection drawn from this curEditorState.connectOutput = nodeOutput; e.Use(); } else { // no output clicked, check input NodeInput nodeInput = curEditorState.focusedNode.GetInputAtPos(e.mousePosition); if (nodeInput != null && nodeInput.connection != null) { // Input node -> Loose and edit Connection curEditorState.connectOutput = nodeInput.connection; Node.RemoveConnection(nodeInput); e.Use(); } } } } } else { // A click on the empty canvas if (e.button == 2 || e.button == 0) { // Left/Middle Click -> Start scrolling curEditorState.panWindow = true; e.delta = Vector2.zero; } else if (e.button == 1) { // Right click -> Editor Context Click // TODO: Node Editor: Editor-Independancy - GenericMenu conversion if (curEditorState.connectOutput != null || curEditorState.makeTransition != null) { // #if UNITY_EDITOR // UnityEditor.GenericMenu menu = new UnityEditor.GenericMenu (); // #else GenericMenu menu = new GenericMenu(); // #endif // Iterate through all compatible nodes foreach (Node node in NodeTypes.nodes.Keys) { if (curEditorState.connectOutput != null) { foreach (var input in node.Inputs) { if (input.type == curEditorState.connectOutput.type) { menu.AddItem(new GUIContent("Add " + NodeTypes.nodes[node].adress), false, ContextCallback, new callbackObject(node.GetID, curNodeCanvas, curEditorState)); break; } } } else if (curEditorState.makeTransition != null && NodeTypes.nodes [node].transitions) { menu.AddItem(new GUIContent("Add " + NodeTypes.nodes[node].adress), false, ContextCallback, new callbackObject(node.GetID, curNodeCanvas, curEditorState)); } } menu.ShowAsContext(); } else { // #if UNITY_EDITOR // UnityEditor.GenericMenu menu = new UnityEditor.GenericMenu (); // #else GenericMenu menu = new GenericMenu(); // #endif foreach (Node node in NodeTypes.nodes.Keys) { menu.AddItem(new GUIContent("Add " + NodeTypes.nodes [node].adress), false, ContextCallback, new callbackObject(node.GetID, curNodeCanvas, curEditorState)); } menu.ShowAsContext(); } e.Use(); } } break; case EventType.MouseUp: if (curEditorState.focusedNode != null) { if (curEditorState.makeTransition != null) { Node.CreateTransition(curEditorState.makeTransition, curEditorState.focusedNode); } else if (curEditorState.connectOutput != null) { // Apply a connection if theres a clicked input if (!curEditorState.focusedNode.Outputs.Contains(curEditorState.connectOutput)) { // If an input was clicked, it'll will now be connected NodeInput clickedInput = curEditorState.focusedNode.GetInputAtPos(e.mousePosition); if (Node.CanApplyConnection(curEditorState.connectOutput, clickedInput)) { // If it can connect (type is equals, it does not cause recursion, ...) Node.ApplyConnection(curEditorState.connectOutput, clickedInput); } } e.Use(); } } curEditorState.makeTransition = null; curEditorState.connectOutput = null; curEditorState.dragNode = false; curEditorState.panWindow = false; break; case EventType.ScrollWheel: curEditorState.zoom = (float)Math.Round(Math.Min(2.0f, Math.Max(0.6f, curEditorState.zoom + e.delta.y / 15)), 2); if (Repaint != null) { Repaint(); } break; case EventType.KeyDown: // TODO: Node Editor: Shortcuts if (e.keyCode == KeyCode.N) // Start Navigating (curve to origin / active Node) { curEditorState.navigate = true; } if (e.keyCode == KeyCode.LeftControl && curEditorState.activeNode != null) // Snap { curEditorState.activeNode.rect.position = new Vector2(Mathf.RoundToInt((curEditorState.activeNode.rect.position.x - curEditorState.panOffset.x) / 10) * 10 + curEditorState.panOffset.x, Mathf.RoundToInt((curEditorState.activeNode.rect.position.y - curEditorState.panOffset.y) / 10) * 10 + curEditorState.panOffset.y); } if (Repaint != null) { Repaint(); } break; case EventType.KeyUp: if (e.keyCode == KeyCode.N) // Stop Navigating { curEditorState.navigate = false; } if (Repaint != null) { Repaint(); } break; case EventType.MouseDrag: if (curEditorState.panWindow) { // Scroll everything with the current mouse delta curEditorState.panOffset += e.delta * curEditorState.zoom; for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { curNodeCanvas.nodes [nodeCnt].rect.position += e.delta * curEditorState.zoom; } e.delta = Vector2.zero; if (Repaint != null) { Repaint(); } } else { curEditorState.panWindow = false; } if (curEditorState.dragNode && curEditorState.activeNode != null && GUIUtility.hotControl == 0) { // Drag the active node with the current mouse delta curEditorState.activeNode.rect.position += e.delta * curEditorState.zoom; NodeEditorCallbacks.IssueOnMoveNode(curEditorState.activeNode); e.delta = Vector2.zero; if (Repaint != null) { Repaint(); } } else { curEditorState.dragNode = false; } break; } }
/// <summary> /// Creates a node of the specified ID at pos on the specified canvas, optionally auto-connecting the specified output to a matching input /// silent disables any events, init specifies whether OnCreate should be called /// </summary> public static Node Create(string nodeID, Vector2 pos, NodeCanvas hostCanvas, ConnectionPort connectingPort = null, bool silent = false, bool init = true) { if (string.IsNullOrEmpty(nodeID) || hostCanvas == null) { throw new ArgumentException(); } if (!NodeCanvasManager.CheckCanvasCompability(nodeID, hostCanvas.GetType())) { throw new UnityException("Cannot create Node with ID '" + nodeID + "' as it is not compatible with the current canavs type (" + hostCanvas.GetType().ToString() + ")!"); } if (!hostCanvas.CanAddNode(nodeID)) { throw new UnityException("Cannot create Node with ID '" + nodeID + "' on the current canvas of type (" + hostCanvas.GetType().ToString() + ")!"); } // Create node from data NodeTypeData data = NodeTypes.getNodeData(nodeID); Node node = (Node)CreateInstance(data.type); if (node == null) { return(null); } // Init node state node.canvas = hostCanvas; node.name = node.Title; node.autoSize = node.DefaultSize; node.position = pos; ConnectionPortManager.UpdateConnectionPorts(node); if (init) { node.OnCreate(); } if (connectingPort != null) { // Handle auto-connection and link the output to the first compatible input for (int i = 0; i < node.connectionPorts.Count; i++) { if (node.connectionPorts[i].TryApplyConnection(connectingPort, true)) { break; } } } // Add node to host canvas hostCanvas.nodes.Add(node); if (!silent) { // Callbacks hostCanvas.OnNodeChange(connectingPort != null ? connectingPort.body : node); NodeEditorCallbacks.IssueOnAddNode(node); hostCanvas.Validate(); NodeEditor.RepaintClients(); } #if UNITY_EDITOR if (!silent) { List <ConnectionPort> connectedPorts = new List <ConnectionPort>(); foreach (ConnectionPort port in node.connectionPorts) { // 'Encode' connected ports in one list (double level cannot be serialized) foreach (ConnectionPort conn in port.connections) { connectedPorts.Add(conn); } connectedPorts.Add(null); } Node createdNode = node; UndoPro.UndoProManager.RecordOperation( () => NodeEditorUndoActions.ReinstateNode(createdNode, connectedPorts), () => NodeEditorUndoActions.RemoveNode(createdNode), "Create Node"); // Make sure the new node is in the memory dump NodeEditorUndoActions.CompleteSOMemoryDump(hostCanvas); } #endif return(node); }