private static void HandleNodeDraggingEnd(NodeEditorInputInfo inputInfo) { if (inputInfo.editorState.dragUserID == "node") { Vector2 dragStart = inputInfo.editorState.dragObjectStart; Vector2 dragEnd = inputInfo.editorState.EndDrag("node"); if (inputInfo.editorState.dragNode && inputInfo.editorState.selectedNode) { if ((dragStart - dragEnd).magnitude > 10) { inputInfo.editorState.selectedNode.position = dragEnd; #if UNITY_EDITOR // Important: Copy variables used within anonymous functions within same level (this if block) for correct serialization! float prevX = dragStart.x, prevY = dragStart.y, newX = dragEnd.x, newY = dragEnd.y; Node draggedNode = inputInfo.editorState.selectedNode; UndoPro.UndoProManager.RecordOperation( () => NodeEditorUndoActions.SetNodePosition(draggedNode, new Vector2(newX, newY)), () => NodeEditorUndoActions.SetNodePosition(draggedNode, new Vector2(prevX, prevY)), "Node Drag", true, false); #endif NodeEditorCallbacks.IssueOnMoveNode(inputInfo.editorState.selectedNode); } else { inputInfo.editorState.selectedNode.position = dragStart; } } } inputInfo.editorState.dragNode = false; }
private static void HandleNodeDragging(NodeEditorInputInfo inputInfo) { NodeEditorState state = inputInfo.editorState; if (state.dragNode) { // If conditions apply, drag the selected node, else disable dragging if (state.selectedNode != null && GUIUtility.hotControl == 0) { // Calculate new position for the dragged object state.dragOffset = inputInfo.inputPos - state.dragStart; Vector2 delta = (state.dragPos + state.dragOffset * state.zoom) - state.selectedNode.rect.position; state.selectedNode.rect.position = state.dragPos + state.dragOffset * state.zoom; if (inputInfo.inputEvent.alt) { Dictionary <Node, int> d = new Dictionary <Node, int>(); d[state.selectedNode] = 1; MoveChildren(ref d, state.selectedNode, delta); } NodeEditorCallbacks.IssueOnMoveNode(state.selectedNode); NodeEditor.RepaintClients(); } else { state.dragNode = false; } } }
private static void HandleNodeDraggingEnd(NodeEditorInputInfo inputInfo) { if (inputInfo.editorState.dragUserID == "node") { Vector2 totalDrag = inputInfo.editorState.EndDrag("node"); if (inputInfo.editorState.dragNode && inputInfo.editorState.selectedNode != null) { inputInfo.editorState.selectedNode.position = totalDrag; NodeEditorCallbacks.IssueOnMoveNode(inputInfo.editorState.selectedNode); } } inputInfo.editorState.dragNode = false; }
static void MoveChildren(ref Dictionary <Node, int> _dic, Node _n, Vector2 _delta) { foreach (var input in _n.Inputs) { Node cn = input.connection.body; if (!_dic.ContainsKey(cn)) { cn.rect.position += _delta; NodeEditorCallbacks.IssueOnMoveNode(cn); MoveChildren(ref _dic, cn, _delta); _dic[cn] = 1; } } }
private static void HandleNodeDraggingEnd(NodeEditorInputInfo inputInfo) { if (inputInfo.editorState.dragUserID == "node") { Vector2 totalDrag = inputInfo.editorState.EndDrag("node"); if (inputInfo.editorState.dragNode && inputInfo.editorState.selectedNodes.Count > 0) { foreach (var node in inputInfo.editorState.selectedNodes) { node.position += inputInfo.editorState.dragOffset; NodeEditorCallbacks.IssueOnMoveNode(node); } } } inputInfo.editorState.dragNode = false; }
private static void HandleNodeDragging(NodeEditorInputInfo inputInfo) { NodeEditorState state = inputInfo.editorState; if (state.dragNode) { // If conditions apply, drag the selected node, else disable dragging if (state.selectedNode != null && GUIUtility.hotControl == 0) { // Calculate new position for the dragged object state.dragOffset = inputInfo.inputPos - state.dragStart; state.selectedNode.rect.position = state.dragPos + state.dragOffset * state.zoom; NodeEditorCallbacks.IssueOnMoveNode(state.selectedNode); NodeEditor.RepaintClients(); } else { state.dragNode = false; } } }
private static void HandleNodeDragging(NodeEditorInputInfo inputInfo) { NodeEditorState editorState = inputInfo.editorState; if (editorState.dragNode) { if ((UnityEngine.Object)editorState.selectedNode != (UnityEngine.Object)null && GUIUtility.hotControl == 0) { editorState.dragOffset = inputInfo.inputPos - editorState.dragStart; editorState.selectedNode.rect.position = editorState.dragPos + editorState.dragOffset * editorState.zoom; NodeEditorCallbacks.IssueOnMoveNode(editorState.selectedNode); NodeEditor.RepaintClients(); } else { editorState.dragNode = false; } } }
/// <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> /// Processes input events /// </summary> public static void InputEvents() { Event e = Event.current; mousePos = e.mousePosition; bool leftClick = e.button == 0, rightClick = e.button == 1, mouseDown = e.type == EventType.MouseDown, mousUp = e.type == EventType.MouseUp; if (ignoreInput(mousePos)) { return; } #region Change Node selection and focus // Choose focused and selected Node, accounting for focus changes curEditorState.focusedNode = null; if (mouseDown || mousUp) { curEditorState.focusedNode = NodeEditor.NodeAtPosition(mousePos); if (curEditorState.focusedNode != curEditorState.selectedNode) { unfocusControls = true; } if (mouseDown && leftClick) { curEditorState.selectedNode = curEditorState.focusedNode; RepaintClients(); } } // Perform above mentioned focus changes in Repaint, which is the only suitable time to do this if (unfocusControls && Event.current.type == EventType.Repaint) { GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; unfocusControls = false; } #if UNITY_EDITOR if (curEditorState.focusedNode != null) { UnityEditor.Selection.activeObject = curEditorState.focusedNode; } #endif #endregion switch (e.type) { case EventType.MouseDown: curEditorState.dragNode = false; curEditorState.panWindow = false; if (curEditorState.focusedNode != null) { // Clicked a Node if (rightClick) { // Node Context Click GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Delete Node"), false, ContextCallback, new NodeEditorMenuCallback("deleteNode", curNodeCanvas, curEditorState)); menu.AddItem(new GUIContent("Duplicate Node"), false, ContextCallback, new NodeEditorMenuCallback("duplicateNode", curNodeCanvas, curEditorState)); if (curEditorState.focusedNode.AcceptsTranstitions) { menu.AddSeparator("Seperator"); menu.AddItem(new GUIContent("Make Transition"), false, ContextCallback, new NodeEditorMenuCallback("startTransition", curNodeCanvas, curEditorState)); } menu.ShowAsContext(); e.Use(); } else if (leftClick) { // Detect click on a connection knob if (!CanvasGUIToScreenRect(curEditorState.focusedNode.rect).Contains(mousePos)) { // Clicked NodeEdge, check Node Inputs and Outputs NodeOutput nodeOutput = curEditorState.focusedNode.GetOutputAtPos(e.mousePosition); if (nodeOutput != null) { // Output clicked -> New Connection drawn from this curEditorState.connectOutput = nodeOutput; e.Use(); return; } NodeInput nodeInput = curEditorState.focusedNode.GetInputAtPos(e.mousePosition); if (nodeInput != null && nodeInput.connection != null) { // Input clicked -> Loose and edit Connection // TODO: Draw input from NodeInput curEditorState.connectOutput = nodeInput.connection; nodeInput.RemoveConnection(); e.Use(); } } } } else { // Clicked on canvas // NOTE: Panning is not done here but in LateEvents, so buttons on the canvas won't be blocked when clicking if (rightClick) { // Editor Context Click GenericMenu menu = new GenericMenu(); if (curEditorState.connectOutput != null) { // A connection is drawn, so provide a context menu with apropriate nodes to auto-connect foreach (Node node in NodeTypes.nodes.Keys) { // Iterate through all nodes and check for compability foreach (NodeInput input in node.Inputs) { if (input.type == curEditorState.connectOutput.type) { menu.AddItem(new GUIContent("Add " + NodeTypes.nodes[node].adress), false, ContextCallback, new NodeEditorMenuCallback(node.GetID, curNodeCanvas, curEditorState)); break; } } } } else if (curEditorState.makeTransition != null && curEditorState.makeTransition.AcceptsTranstitions) { // A transition is drawn, so provide a context menu with nodes to auto-connect foreach (Node node in NodeTypes.nodes.Keys) { // Iterate through all nodes and check for compability if (node.AcceptsTranstitions) { menu.AddItem(new GUIContent("Add " + NodeTypes.nodes[node].adress), false, ContextCallback, new NodeEditorMenuCallback(node.GetID, curNodeCanvas, curEditorState)); } } } else { // Ordinary context click, add all nodes to add foreach (Node node in NodeTypes.nodes.Keys) { menu.AddItem(new GUIContent("Add " + NodeTypes.nodes [node].adress), false, ContextCallback, new NodeEditorMenuCallback(node.GetID, curNodeCanvas, curEditorState)); } } menu.ShowAsContext(); e.Use(); } } break; case EventType.MouseUp: if (curEditorState.focusedNode != null && curEditorState.connectOutput != null) { // Apply Drawn connections on node if theres a clicked input if (!curEditorState.focusedNode.Outputs.Contains(curEditorState.connectOutput)) { // An input was clicked, it'll will now be connected NodeInput clickedInput = curEditorState.focusedNode.GetInputAtPos(e.mousePosition); if (clickedInput.CanApplyConnection(curEditorState.connectOutput)) { // It can connect (type is equals, it does not cause recursion, ...) clickedInput.ApplyConnection(curEditorState.connectOutput); } } e.Use(); } curEditorState.makeTransition = null; curEditorState.connectOutput = null; curEditorState.dragNode = false; curEditorState.panWindow = false; break; case EventType.ScrollWheel: // Apply Zoom curEditorState.zoom = (float)Math.Round(Math.Min(2.0f, Math.Max(0.6f, curEditorState.zoom + e.delta.y / 15)), 2); RepaintClients(); 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.selectedNode != null) { // Snap selected Node's position to multiples of 10 Vector2 pos = curEditorState.selectedNode.rect.position; pos = (pos - curEditorState.panOffset) / 10; pos = new Vector2(Mathf.RoundToInt(pos.x), Mathf.RoundToInt(pos.y)); curEditorState.selectedNode.rect.position = pos * 10 + curEditorState.panOffset; } RepaintClients(); break; case EventType.KeyUp: if (e.keyCode == KeyCode.N) // Stop Navigating { curEditorState.navigate = false; } RepaintClients(); break; case EventType.MouseDrag: if (curEditorState.panWindow) { // Scroll everything with the current mouse delta curEditorState.panOffset += e.delta * curEditorState.zoom; foreach (Node node in curNodeCanvas.nodes) { node.rect.position += e.delta * curEditorState.zoom; } e.delta = Vector2.zero; RepaintClients(); } if (curEditorState.dragNode && curEditorState.selectedNode != null && GUIUtility.hotControl == 0) { // Drag the active node with the current mouse delta curEditorState.selectedNode.rect.position += e.delta * curEditorState.zoom; NodeEditorCallbacks.IssueOnMoveNode(curEditorState.selectedNode); e.delta = Vector2.zero; RepaintClients(); } else { curEditorState.dragNode = false; } break; } }