public void Controls() { wantsMouseMove = true; Event e = Event.current; switch (e.type) { case EventType.DragUpdated: case EventType.DragPerform: DragAndDrop.visualMode = DragAndDropVisualMode.Generic; if (e.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); graphEditor.OnDropObjects(DragAndDrop.objectReferences); } break; case EventType.MouseMove: //Keyboard commands will not get correct mouse position from Event lastMousePosition = e.mousePosition; break; case EventType.ScrollWheel: float oldZoom = zoom; if (e.delta.y > 0) { zoom += 0.1f * zoom; } else { zoom -= 0.1f * zoom; } if (NodeEditorPreferences.GetSettings().zoomToMouse) { panOffset += (1 - oldZoom / zoom) * (WindowToGridPosition(e.mousePosition) + panOffset); } break; case EventType.MouseDrag: if (e.button == 0) { if (IsDraggingPort) { if (IsHoveringPort && hoveredPort.IsInput && draggedOutput.CanConnectTo(hoveredPort)) { if (!draggedOutput.IsConnectedTo(hoveredPort)) { draggedOutputTarget = hoveredPort; } } else { draggedOutputTarget = null; } Repaint(); } else if (currentActivity == NodeActivity.HoldNode) { RecalculateDragOffsets(e); currentActivity = NodeActivity.DragNode; Repaint(); } if (currentActivity == NodeActivity.DragNode) { // Holding ctrl inverts grid snap bool gridSnap = NodeEditorPreferences.GetSettings().gridSnap; if (e.control) { gridSnap = !gridSnap; } Vector2 mousePos = WindowToGridPosition(e.mousePosition); // Move selected nodes with offset for (int i = 0; i < Selection.objects.Length; i++) { if (Selection.objects[i] is XNode.Node) { XNode.Node node = Selection.objects[i] as XNode.Node; Vector2 initial = node.position; node.position = mousePos + dragOffset[i]; if (gridSnap) { node.position.x = (Mathf.Round((node.position.x + 8) / 16) * 16) - 8; node.position.y = (Mathf.Round((node.position.y + 8) / 16) * 16) - 8; } // Offset portConnectionPoints instantly if a node is dragged so they aren't delayed by a frame. Vector2 offset = node.position - initial; if (offset.sqrMagnitude > 0) { foreach (XNode.NodePort output in node.Outputs) { Rect rect; if (portConnectionPoints.TryGetValue(output, out rect)) { rect.position += offset; portConnectionPoints[output] = rect; } } foreach (XNode.NodePort input in node.Inputs) { Rect rect; if (portConnectionPoints.TryGetValue(input, out rect)) { rect.position += offset; portConnectionPoints[input] = rect; } } } } } // Move selected reroutes with offset for (int i = 0; i < selectedReroutes.Count; i++) { Vector2 pos = mousePos + dragOffset[Selection.objects.Length + i]; if (gridSnap) { pos.x = (Mathf.Round(pos.x / 16) * 16); pos.y = (Mathf.Round(pos.y / 16) * 16); } selectedReroutes[i].SetPoint(pos); } Repaint(); } else if (currentActivity == NodeActivity.HoldGrid) { currentActivity = NodeActivity.DragGrid; preBoxSelection = Selection.objects; preBoxSelectionReroute = selectedReroutes.ToArray(); dragBoxStart = WindowToGridPosition(e.mousePosition); Repaint(); } else if (currentActivity == NodeActivity.DragGrid) { Vector2 boxStartPos = GridToWindowPosition(dragBoxStart); Vector2 boxSize = e.mousePosition - boxStartPos; if (boxSize.x < 0) { boxStartPos.x += boxSize.x; boxSize.x = Mathf.Abs(boxSize.x); } if (boxSize.y < 0) { boxStartPos.y += boxSize.y; boxSize.y = Mathf.Abs(boxSize.y); } selectionBox = new Rect(boxStartPos, boxSize); Repaint(); } } else if (e.button == 1 || e.button == 2) { panOffset += e.delta * zoom; isPanning = true; } break; case EventType.MouseDown: Repaint(); if (e.button == 0) { draggedOutputReroutes.Clear(); if (IsHoveringPort) { if (hoveredPort.IsOutput) { draggedOutput = hoveredPort; autoConnectOutput = hoveredPort; } else { hoveredPort.VerifyConnections(); autoConnectOutput = null; if (hoveredPort.IsConnected) { XNode.Node node = hoveredPort.node; XNode.NodePort output = hoveredPort.Connection; int outputConnectionIndex = output.GetConnectionIndex(hoveredPort); draggedOutputReroutes = output.GetReroutePoints(outputConnectionIndex); hoveredPort.Disconnect(output); draggedOutput = output; draggedOutputTarget = hoveredPort; if (NodeEditor.onUpdateNode != null) { NodeEditor.onUpdateNode(node); } } } } else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) { // If mousedown on node header, select or deselect if (!Selection.Contains(hoveredNode)) { SelectNode(hoveredNode, e.control || e.shift); if (!e.control && !e.shift) { selectedReroutes.Clear(); } } else if (e.control || e.shift) { DeselectNode(hoveredNode); } // Cache double click state, but only act on it in MouseUp - Except ClickCount only works in mouseDown. isDoubleClick = (e.clickCount == 2); e.Use(); currentActivity = NodeActivity.HoldNode; } else if (IsHoveringReroute) { // If reroute isn't selected if (!selectedReroutes.Contains(hoveredReroute)) { // Add it if (e.control || e.shift) { selectedReroutes.Add(hoveredReroute); } // Select it else { selectedReroutes = new List <RerouteReference>() { hoveredReroute }; Selection.activeObject = null; } } // Deselect else if (e.control || e.shift) { selectedReroutes.Remove(hoveredReroute); } e.Use(); currentActivity = NodeActivity.HoldNode; } // If mousedown on grid background, deselect all else if (!IsHoveringNode) { currentActivity = NodeActivity.HoldGrid; if (!e.control && !e.shift) { selectedReroutes.Clear(); Selection.activeObject = null; } } } break; case EventType.MouseUp: if (e.button == 0) { //Port drag release if (IsDraggingPort) { //If connection is valid, save it if (draggedOutputTarget != null) { XNode.Node node = draggedOutputTarget.node; if (graph.nodes.Count != 0) { draggedOutput.Connect(draggedOutputTarget); } // ConnectionIndex can be -1 if the connection is removed instantly after creation int connectionIndex = draggedOutput.GetConnectionIndex(draggedOutputTarget); if (connectionIndex != -1) { draggedOutput.GetReroutePoints(connectionIndex).AddRange(draggedOutputReroutes); if (NodeEditor.onUpdateNode != null) { NodeEditor.onUpdateNode(node); } EditorUtility.SetDirty(graph); } } // Open context menu for auto-connection else if (NodeEditorPreferences.GetSettings().dragToCreate&& autoConnectOutput != null) { GenericMenu menu = new GenericMenu(); graphEditor.AddContextMenuItems(menu); menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); } //Release dragged connection draggedOutput = null; draggedOutputTarget = null; EditorUtility.SetDirty(graph); if (NodeEditorPreferences.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } else if (currentActivity == NodeActivity.DragNode) { IEnumerable <XNode.Node> nodes = Selection.objects.Where(x => x is XNode.Node).Select(x => x as XNode.Node); foreach (XNode.Node node in nodes) { EditorUtility.SetDirty(node); } if (NodeEditorPreferences.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } else if (!IsHoveringNode) { // If click outside node, release field focus if (!isPanning) { EditorGUI.FocusTextInControl(null); EditorGUIUtility.editingTextField = false; } if (NodeEditorPreferences.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } // If click node header, select it. if (currentActivity == NodeActivity.HoldNode && !(e.control || e.shift)) { selectedReroutes.Clear(); SelectNode(hoveredNode, false); // Double click to center node if (isDoubleClick) { Vector2 nodeDimension = nodeSizes.ContainsKey(hoveredNode) ? nodeSizes[hoveredNode] / 2 : Vector2.zero; panOffset = -hoveredNode.position - nodeDimension; } } // If click reroute, select it. if (IsHoveringReroute && !(e.control || e.shift)) { selectedReroutes = new List <RerouteReference>() { hoveredReroute }; Selection.activeObject = null; } Repaint(); currentActivity = NodeActivity.Idle; } else if (e.button == 1 || e.button == 2) { if (!isPanning) { if (IsDraggingPort) { draggedOutputReroutes.Add(WindowToGridPosition(e.mousePosition)); } else if (currentActivity == NodeActivity.DragNode && Selection.activeObject == null && selectedReroutes.Count == 1) { selectedReroutes[0].InsertPoint(selectedReroutes[0].GetPoint()); selectedReroutes[0] = new RerouteReference(selectedReroutes[0].port, selectedReroutes[0].connectionIndex, selectedReroutes[0].pointIndex + 1); } else if (IsHoveringReroute) { ShowRerouteContextMenu(hoveredReroute); } else if (IsHoveringPort) { ShowPortContextMenu(hoveredPort); } else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) { if (!Selection.Contains(hoveredNode)) { SelectNode(hoveredNode, false); } autoConnectOutput = null; GenericMenu menu = new GenericMenu(); NodeEditor.GetEditor(hoveredNode, this).AddContextMenuItems(menu); menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); e.Use(); // Fixes copy/paste context menu appearing in Unity 5.6.6f2 - doesn't occur in 2018.3.2f1 Probably needs to be used in other places. } else if (!IsHoveringNode) { autoConnectOutput = null; GenericMenu menu = new GenericMenu(); graphEditor.AddContextMenuItems(menu); menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); } } isPanning = false; } // Reset DoubleClick isDoubleClick = false; break; case EventType.KeyDown: if (EditorGUIUtility.editingTextField) { break; } else if (e.keyCode == KeyCode.F) { Home(); } if (NodeEditorUtilities.IsMac()) { if (e.keyCode == KeyCode.Return) { RenameSelectedNode(); } } else { if (e.keyCode == KeyCode.F2) { RenameSelectedNode(); } } if (e.keyCode == KeyCode.A) { if (Selection.objects.Any(x => graph.nodes.Contains(x as XNode.Node))) { foreach (XNode.Node node in graph.nodes) { DeselectNode(node); } } else { foreach (XNode.Node node in graph.nodes) { SelectNode(node, true); } } Repaint(); } break; case EventType.ValidateCommand: case EventType.ExecuteCommand: if (e.commandName == "SoftDelete") { if (e.type == EventType.ExecuteCommand) { RemoveSelectedNodes(); } e.Use(); } else if (NodeEditorUtilities.IsMac() && e.commandName == "Delete") { if (e.type == EventType.ExecuteCommand) { RemoveSelectedNodes(); } e.Use(); } else if (e.commandName == "Duplicate") { if (e.type == EventType.ExecuteCommand) { DuplicateSelectedNodes(); } e.Use(); } else if (e.commandName == "Copy") { if (e.type == EventType.ExecuteCommand) { CopySelectedNodes(); } e.Use(); } else if (e.commandName == "Paste") { if (e.type == EventType.ExecuteCommand) { PasteNodes(WindowToGridPosition(lastMousePosition)); } e.Use(); } Repaint(); break; case EventType.Ignore: // If release mouse outside window if (e.rawType == EventType.MouseUp && currentActivity == NodeActivity.DragGrid) { Repaint(); currentActivity = NodeActivity.Idle; } break; } }
public void Controls() { wantsMouseMove = true; Event e = Event.current; switch (e.type) { case EventType.MouseMove: break; case EventType.ScrollWheel: if (e.delta.y > 0) { zoom += 0.1f * zoom; } else { zoom -= 0.1f * zoom; } break; case EventType.MouseDrag: if (e.button == 0) { if (IsDraggingPort) { if (IsHoveringPort && hoveredPort.IsInput) { if (!draggedOutput.IsConnectedTo(hoveredPort)) { draggedOutputTarget = hoveredPort; } } else { draggedOutputTarget = null; } Repaint(); } else if (currentActivity == NodeActivity.HoldHeader || currentActivity == NodeActivity.DragHeader) { for (int i = 0; i < Selection.objects.Length; i++) { if (Selection.objects[i] is XNode.Node) { XNode.Node node = Selection.objects[i] as XNode.Node; node.position = WindowToGridPosition(e.mousePosition) + dragOffset[i]; bool gridSnap = NodeEditorPreferences.GetSettings().gridSnap; if (e.control) { gridSnap = !gridSnap; } if (gridSnap) { node.position.x = (Mathf.Round((node.position.x + 8) / 16) * 16) - 8; node.position.y = (Mathf.Round((node.position.y + 8) / 16) * 16) - 8; } } } currentActivity = NodeActivity.DragHeader; Repaint(); } else if (currentActivity == NodeActivity.HoldGrid) { currentActivity = NodeActivity.DragGrid; preBoxSelection = Selection.objects; dragBoxStart = WindowToGridPosition(e.mousePosition); Repaint(); } else if (currentActivity == NodeActivity.DragGrid) { foreach (XNode.Node node in graph.nodes) { } Repaint(); } } else if (e.button == 1 || e.button == 2) { Vector2 tempOffset = panOffset; tempOffset += e.delta * zoom; // Round value to increase crispyness of UI text tempOffset.x = Mathf.Round(tempOffset.x); tempOffset.y = Mathf.Round(tempOffset.y); panOffset = tempOffset; isPanning = true; } break; case EventType.MouseDown: Repaint(); if (e.button == 0) { if (IsHoveringPort) { if (hoveredPort.IsOutput) { draggedOutput = hoveredPort; } else { hoveredPort.VerifyConnections(); if (hoveredPort.IsConnected) { XNode.Node node = hoveredPort.node; XNode.NodePort output = hoveredPort.Connection; hoveredPort.Disconnect(output); draggedOutput = output; draggedOutputTarget = hoveredPort; if (NodeEditor.onUpdateNode != null) { NodeEditor.onUpdateNode(node); } } } } else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) { // If mousedown on node header, select or deselect if (!Selection.Contains(hoveredNode)) { SelectNode(hoveredNode, e.control || e.shift); } else if (e.control || e.shift) { DeselectNode(hoveredNode); } e.Use(); currentActivity = NodeActivity.HoldHeader; dragOffset = new Vector2[Selection.objects.Length]; for (int i = 0; i < dragOffset.Length; i++) { if (Selection.objects[i] is XNode.Node) { XNode.Node node = Selection.objects[i] as XNode.Node; dragOffset[i] = node.position - WindowToGridPosition(e.mousePosition); } } } // If mousedown on grid background, deselect all else if (!IsHoveringNode) { currentActivity = NodeActivity.HoldGrid; if (!e.control && !e.shift) { Selection.activeObject = null; } } } break; case EventType.MouseUp: if (e.button == 0) { //Port drag release if (IsDraggingPort) { //If connection is valid, save it if (draggedOutputTarget != null) { XNode.Node node = draggedOutputTarget.node; if (graph.nodes.Count != 0) { draggedOutput.Connect(draggedOutputTarget); } if (NodeEditor.onUpdateNode != null) { NodeEditor.onUpdateNode(node); } EditorUtility.SetDirty(graph); } //Release dragged connection draggedOutput = null; draggedOutputTarget = null; EditorUtility.SetDirty(graph); AssetDatabase.SaveAssets(); } else if (currentActivity == NodeActivity.DragHeader) { AssetDatabase.SaveAssets(); } else if (!IsHoveringNode) { // If click outside node, release field focus if (!isPanning) { // I've got no idea which of these do what, so we'll just reset all of it. GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; EditorGUIUtility.editingTextField = false; EditorGUIUtility.keyboardControl = 0; EditorGUIUtility.hotControl = 0; } AssetDatabase.SaveAssets(); } // If click node header, select single node. if (currentActivity == NodeActivity.HoldHeader && !(e.control || e.shift)) { SelectNode(hoveredNode, false); } Repaint(); currentActivity = NodeActivity.Idle; } else if (e.button == 1) { if (!isPanning) { if (IsHoveringNode && IsHoveringTitle(hoveredNode)) { if (!Selection.Contains(hoveredNode)) { SelectNode(hoveredNode, false); } ShowNodeContextMenu(); } else if (!IsHoveringNode) { ShowGraphContextMenu(); } } isPanning = false; } break; case EventType.KeyDown: if (EditorGUIUtility.editingTextField) { break; } else if (e.keyCode == KeyCode.F) { Home(); } break; case EventType.ValidateCommand: if (e.commandName == "SoftDelete") { RemoveSelectedNodes(); } else if (e.commandName == "Duplicate") { DublicateSelectedNodes(); } Repaint(); break; case EventType.Ignore: // If release mouse outside window if (e.rawType == EventType.MouseUp && currentActivity == NodeActivity.DragGrid) { Repaint(); currentActivity = NodeActivity.Idle; } break; } }
public void Controls() { wantsMouseMove = true; Event e = Event.current; switch (e.type) { case EventType.MouseMove: break; case EventType.ScrollWheel: if (e.delta.y > 0) { zoom += 0.1f * zoom; } else { zoom -= 0.1f * zoom; } break; case EventType.MouseDrag: if (e.button == 0) { if (IsDraggingPort) { if (IsHoveringPort) { if (hoveredPort.IsInput) { if (!draggedOutput.IsConnectedTo(hoveredPort)) { draggedOutputTarget = hoveredPort; } } } else { draggedOutputTarget = null; } Repaint(); } else if (currentActivity == NodeActivity.HoldNode) { RecalculateDragOffsets(e); currentActivity = NodeActivity.DragNode; Repaint(); } if (currentActivity == NodeActivity.DragNode) { // Holding ctrl inverts grid snap bool gridSnap = NodeEditorPreferences.GetSettings().gridSnap; if (e.control) { gridSnap = !gridSnap; } Vector2 mousePos = WindowToGridPosition(e.mousePosition); // Move selected nodes with offset for (int i = 0; i < Selection.objects.Length; i++) { if (Selection.objects[i] is XNode.Node) { XNode.Node node = Selection.objects[i] as XNode.Node; Vector2 initial = node.position; node.position = mousePos + dragOffset[i]; if (gridSnap) { node.position.x = (Mathf.Round((node.position.x + 8) / 16) * 16) - 8; node.position.y = (Mathf.Round((node.position.y + 8) / 16) * 16) - 8; } // Offset portConnectionPoints instantly if a node is dragged so they aren't delayed by a frame. Vector2 offset = node.position - initial; if (offset.sqrMagnitude > 0) { foreach (XNode.NodePort output in node.Outputs) { Rect rect; if (portConnectionPoints.TryGetValue(output, out rect)) { rect.position += offset; portConnectionPoints[output] = rect; } } foreach (XNode.NodePort input in node.Inputs) { Rect rect; if (portConnectionPoints.TryGetValue(input, out rect)) { rect.position += offset; portConnectionPoints[input] = rect; } } } } } // Move selected reroutes with offset for (int i = 0; i < selectedReroutes.Count; i++) { Vector2 pos = mousePos + dragOffset[Selection.objects.Length + i]; if (gridSnap) { pos.x = (Mathf.Round(pos.x / 16) * 16); pos.y = (Mathf.Round(pos.y / 16) * 16); } selectedReroutes[i].SetPoint(pos); } Repaint(); } else if (currentActivity == NodeActivity.HoldGrid) { currentActivity = NodeActivity.DragGrid; preBoxSelection = Selection.objects; preBoxSelectionReroute = selectedReroutes.ToArray(); dragBoxStart = WindowToGridPosition(e.mousePosition); Repaint(); } else if (currentActivity == NodeActivity.DragGrid) { Vector2 boxStartPos = GridToWindowPosition(dragBoxStart); Vector2 boxSize = e.mousePosition - boxStartPos; if (boxSize.x < 0) { boxStartPos.x += boxSize.x; boxSize.x = Mathf.Abs(boxSize.x); } if (boxSize.y < 0) { boxStartPos.y += boxSize.y; boxSize.y = Mathf.Abs(boxSize.y); } selectionBox = new Rect(boxStartPos, boxSize); Repaint(); } } else if (e.button == 1 || e.button == 2) { Vector2 tempOffset = panOffset; tempOffset += e.delta * zoom; // Round value to increase crispyness of UI text tempOffset.x = Mathf.Round(tempOffset.x); tempOffset.y = Mathf.Round(tempOffset.y); panOffset = tempOffset; isPanning = true; } break; case EventType.MouseDown: Repaint(); if (e.button == 0) { draggedOutputReroutes.Clear(); if (IsHoveringPort) { if (hoveredPort.IsOutput) { draggedOutput = hoveredPort; } else { hoveredPort.VerifyConnections(); if (hoveredPort.IsConnected) { XNode.Node node = hoveredPort.node; XNode.NodePort output = hoveredPort.Connection; int outputConnectionIndex = output.GetConnectionIndex(hoveredPort); draggedOutputReroutes = output.GetReroutePoints(outputConnectionIndex); hoveredPort.Disconnect(output); draggedOutput = output; draggedOutputTarget = hoveredPort; if (NodeEditor.onUpdateNode != null) { NodeEditor.onUpdateNode(node); } } } } else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) { // If mousedown on node header, select or deselect if (!Selection.Contains(hoveredNode)) { SelectNode(hoveredNode, e.control || e.shift); if (!e.control && !e.shift) { selectedReroutes.Clear(); } } else if (e.control || e.shift) { DeselectNode(hoveredNode); } e.Use(); currentActivity = NodeActivity.HoldNode; } else if (IsHoveringReroute) { // If reroute isn't selected if (!selectedReroutes.Contains(hoveredReroute)) { // Add it if (e.control || e.shift) { selectedReroutes.Add(hoveredReroute); } // Select it else { selectedReroutes = new List <RerouteReference>() { hoveredReroute }; Selection.activeObject = null; } } // Deselect else if (e.control || e.shift) { selectedReroutes.Remove(hoveredReroute); } e.Use(); currentActivity = NodeActivity.HoldNode; } // If mousedown on grid background, deselect all else if (!IsHoveringNode) { currentActivity = NodeActivity.HoldGrid; if (!e.control && !e.shift) { selectedReroutes.Clear(); Selection.activeObject = null; } if (e.clickCount == 2) { // Add a new node on double click // Start by making it the "ObjectSelector" node var pos = WindowToGridPosition(Event.current.mousePosition); var offset = new Vector2(-110, -30); ObjectSelectorEditor.Position = pos + offset; CreateNode(typeof(ObjectSelector), pos + offset); e.Use(); } } } break; case EventType.MouseUp: if (e.button == 0) { //Port drag release if (IsDraggingPort) { //If connection is valid, save it if (draggedOutputTarget != null) { XNode.Node node = draggedOutputTarget.node; if (graph.nodes.Count != 0) { draggedOutput.Connect(draggedOutputTarget); } // ConnectionIndex can be -1 if the connection is removed instantly after creation int connectionIndex = draggedOutput.GetConnectionIndex(draggedOutputTarget); if (connectionIndex != -1) { draggedOutput.GetReroutePoints(connectionIndex).AddRange(draggedOutputReroutes); if (NodeEditor.onUpdateNode != null) { NodeEditor.onUpdateNode(node); } EditorUtility.SetDirty(graph); } } //Release dragged connection draggedOutput = null; draggedOutputTarget = null; EditorUtility.SetDirty(graph); if (NodeEditorPreferences.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } else if (currentActivity == NodeActivity.DragNode) { IEnumerable <XNode.Node> nodes = Selection.objects.Where(x => x is XNode.Node).Select(x => x as XNode.Node); foreach (XNode.Node node in nodes) { EditorUtility.SetDirty(node); } if (NodeEditorPreferences.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } else if (!IsHoveringNode) { // If click outside node, release field focus if (!isPanning) { EditorGUI.FocusTextInControl(null); } if (NodeEditorPreferences.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } // If click node header, select it. if (currentActivity == NodeActivity.HoldNode && !(e.control || e.shift)) { selectedReroutes.Clear(); SelectNode(hoveredNode, false); } // If click reroute, select it. if (IsHoveringReroute && !(e.control || e.shift)) { selectedReroutes = new List <RerouteReference>() { hoveredReroute }; Selection.activeObject = null; } Repaint(); currentActivity = NodeActivity.Idle; } else if (e.button == 1 || e.button == 2) { if (!isPanning) { if (IsDraggingPort) { draggedOutputReroutes.Add(WindowToGridPosition(e.mousePosition)); } else if (currentActivity == NodeActivity.DragNode && Selection.activeObject == null && selectedReroutes.Count == 1) { selectedReroutes[0].InsertPoint(selectedReroutes[0].GetPoint()); selectedReroutes[0] = new RerouteReference(selectedReroutes[0].port, selectedReroutes[0].connectionIndex, selectedReroutes[0].pointIndex + 1); } else if (IsHoveringReroute) { ShowRerouteContextMenu(hoveredReroute); } else if (IsHoveringPort) { ShowPortContextMenu(hoveredPort); } else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) { if (!Selection.Contains(hoveredNode)) { SelectNode(hoveredNode, false); } ShowNodeContextMenu(); } else if (!IsHoveringNode) { ShowGraphContextMenu(); } } isPanning = false; } break; case EventType.KeyDown: if (EditorGUIUtility.editingTextField) { break; } else if (e.keyCode == KeyCode.F) { Home(); } if (SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX) { if (e.keyCode == KeyCode.Return) { RenameSelectedNode(); } } else { if (e.keyCode == KeyCode.F2) { RenameSelectedNode(); } } break; case EventType.ValidateCommand: if (e.commandName == "SoftDelete") { RemoveSelectedNodes(); } else if (SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX && e.commandName == "Delete") { RemoveSelectedNodes(); } else if (e.commandName == "Duplicate") { DublicateSelectedNodes(); } Repaint(); break; case EventType.Ignore: // If release mouse outside window if (e.rawType == EventType.MouseUp && currentActivity == NodeActivity.DragGrid) { Repaint(); currentActivity = NodeActivity.Idle; } break; } }
public void Controls() { wantsMouseMove = true; var e = Event.current; switch (e.type) { case EventType.MouseMove: break; case EventType.ScrollWheel: if (e.delta.y > 0) { Zoom += 0.1f * Zoom; } else { Zoom -= 0.1f * Zoom; } break; case EventType.MouseDrag: if (e.button == 0) { if (IsDraggingPort) { if (IsHoveringPort && hoveredPort.Direction == PortIO.Input) { if (!draggedOutput.IsConnectedTo(hoveredPort)) { draggedOutputTarget = hoveredPort; } } else { draggedOutputTarget = null; } Repaint(); } else if (currentActivity == NodeActivity.HoldNode) { RecalculateDragOffsets(e); currentActivity = NodeActivity.DragNode; Repaint(); } if (currentActivity == NodeActivity.DragNode) { // Holding ctrl inverts grid snap var gridSnap = this.GetSettings().gridSnap; if (e.control) { gridSnap = !gridSnap; } var mousePos = WindowToGridPosition(e.mousePosition); // Move selected nodes with offset for (var i = 0; i < selection.Count; i++) { var node = selection[i]; var initial = node.Position; node.Position = mousePos + dragOffset[i]; if (gridSnap) { var newPosition = new Vector2( (Mathf.Round((node.Position.x + 8) / 16) * 16) - 8, (Mathf.Round((node.Position.y + 8) / 16) * 16) - 8); node.Position = newPosition; } // Offset portConnectionPoints instantly if a node is dragged so they aren't delayed by a frame. var offset = node.Position - initial; if (!(offset.sqrMagnitude > 0)) { continue; } // foreach (var output in node.Outputs) { // if (PortConnectionPoints.TryGetValue(output, out var rect)) { // rect.position += offset; // PortConnectionPoints[output] = rect; // } // } // // foreach (var input in node.Inputs) { // if (!PortConnectionPoints.TryGetValue(input, out var rect)) { // continue; // } // // rect.position += offset; // PortConnectionPoints[input] = rect; // } } // Move selected reroutes with offset for (var i = 0; i < selectedReroutes.Count; i++) { var pos = mousePos + dragOffset[selection.Count + i]; if (gridSnap) { pos.x = (Mathf.Round(pos.x / 16) * 16); pos.y = (Mathf.Round(pos.y / 16) * 16); } selectedReroutes[i].SetPoint(pos); } Repaint(); } else if (currentActivity == NodeActivity.HoldGrid) { currentActivity = NodeActivity.DragGrid; preBoxSelection = selection. Select(x => x.Id). ToArray(); preBoxSelectionReroute = selectedReroutes.ToArray(); dragBoxStart = WindowToGridPosition(e.mousePosition); Repaint(); } else if (currentActivity == NodeActivity.DragGrid) { var boxStartPos = GridToWindowPosition(dragBoxStart); var boxSize = e.mousePosition - boxStartPos; if (boxSize.x < 0) { boxStartPos.x += boxSize.x; boxSize.x = Mathf.Abs(boxSize.x); } if (boxSize.y < 0) { boxStartPos.y += boxSize.y; boxSize.y = Mathf.Abs(boxSize.y); } selectionBox = new Rect(boxStartPos, boxSize); Repaint(); } } else if (e.button == 1 || e.button == 2) { var tempOffset = PanOffset; tempOffset += e.delta * Zoom; // Round value to increase crispyness of UI text tempOffset.x = Mathf.Round(tempOffset.x); tempOffset.y = Mathf.Round(tempOffset.y); PanOffset = tempOffset; isPanning = true; } break; case EventType.MouseDown: Repaint(); if (e.button == 0) { draggedOutputReroutes.Clear(); if (IsHoveringPort) { if (hoveredPort.IsOutput) { draggedOutput = hoveredPort; } else { hoveredPort.VerifyConnections(); if (hoveredPort.IsConnected) { var node = hoveredPort.Node; var output = hoveredPort.Connection as NodePort; var outputConnectionIndex = output.GetConnectionIndex(hoveredPort); draggedOutputReroutes = output.GetReroutePoints(outputConnectionIndex); hoveredPort.Disconnect(output); draggedOutput = output; draggedOutputTarget = hoveredPort; if (NodeEditor.OnUpdateNode != null) { NodeEditor.OnUpdateNode(node); } } } } else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) { // If mousedown on node header, select or deselect if (!IsSelected(hoveredNode)) { Select(hoveredNode, e.control || e.shift); if (!e.control && !e.shift) { selectedReroutes.Clear(); } } else if (e.control || e.shift) { Deselect(hoveredNode); } e.Use(); currentActivity = NodeActivity.HoldNode; } else if (IsHoveringReroute) { // If reroute isn't selected if (!selectedReroutes.Contains(hoveredReroute)) { // Add it if (e.control || e.shift) { selectedReroutes.Add(hoveredReroute); } // Select it else { selectedReroutes = new List <RerouteReference> { hoveredReroute }; DeselectAll(); } } // Deselect else if (e.control || e.shift) { selectedReroutes.Remove(hoveredReroute); } e.Use(); currentActivity = NodeActivity.HoldNode; } // If mousedown on grid background, deselect all else if (!IsHoveringNode) { currentActivity = NodeActivity.HoldGrid; if (!e.control && !e.shift) { selectedReroutes.Clear(); DeselectAll(); } } } break; case EventType.MouseUp: if (e.button == 0) { //Port drag release if (IsDraggingPort) { //If connection is valid, save it if (draggedOutputTarget != null) { var node = draggedOutputTarget.Node; if (ActiveGraph.Nodes.Count != 0) { draggedOutput.Connect(draggedOutputTarget); } // ConnectionIndex can be -1 if the connection is removed instantly after creation var connectionIndex = draggedOutput.GetConnectionIndex(draggedOutputTarget); if (connectionIndex != -1) { draggedOutput.GetReroutePoints(connectionIndex).AddRange(draggedOutputReroutes); if (NodeEditor.OnUpdateNode != null) { NodeEditor.OnUpdateNode(node); } EditorUtility.SetDirty(ActiveGraph); } } //Release dragged connection draggedOutput = null; draggedOutputTarget = null; EditorUtility.SetDirty(ActiveGraph); if (this.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } else if (currentActivity == NodeActivity.DragNode) { var nodes = selection; foreach (var node in nodes) { node.SetDirty(); } if (this.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } else if (!IsHoveringNode) { // If click outside node, release field focus if (!isPanning) { EditorGUI.FocusTextInControl(null); } if (this.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } // If click node header, select it. if (currentActivity == NodeActivity.HoldNode && !(e.control || e.shift)) { selectedReroutes.Clear(); Select(hoveredNode, false); } // If click reroute, select it. if (IsHoveringReroute && !(e.control || e.shift)) { selectedReroutes = new List <RerouteReference> { hoveredReroute }; } Repaint(); currentActivity = NodeActivity.Idle; } else if (e.button == 1 || e.button == 2) { if (!isPanning) { if (IsDraggingPort) { draggedOutputReroutes.Add(WindowToGridPosition(e.mousePosition)); } else if (currentActivity == NodeActivity.DragNode && selection.Count > 0 && selectedReroutes.Count == 1) { selectedReroutes[0].InsertPoint(selectedReroutes[0].GetPoint()); selectedReroutes[0] = new RerouteReference(selectedReroutes[0].port, selectedReroutes[0].connectionIndex, selectedReroutes[0].pointIndex + 1); } else if (IsHoveringReroute) { ShowRerouteContextMenu(hoveredReroute); } else if (IsHoveringPort) { ShowPortContextMenu(hoveredPort); } else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) { if (!hoveredNode.IsSelected()) { Select(hoveredNode, false); } ShowNodeContextMenu(); } else if (!IsHoveringNode) { ShowGraphContextMenu(); } } isPanning = false; } break; case EventType.KeyDown: if (EditorGUIUtility.editingTextField) { break; } else if (e.keyCode == KeyCode.F) { Home(); } if (SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX) { if (e.keyCode == KeyCode.Return) { RenameSelectedNode(); } } else { if (e.keyCode == KeyCode.F2) { RenameSelectedNode(); } } break; case EventType.ValidateCommand: if (e.commandName == "SoftDelete") { RemoveSelectedNodes(); } else if (SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX && e.commandName == "Delete") { RemoveSelectedNodes(); } else if (e.commandName == "Duplicate") { DublicateSelectedNodes(); } Repaint(); break; case EventType.Ignore: // If release mouse outside window if (e.rawType == EventType.MouseUp && currentActivity == NodeActivity.DragGrid) { Repaint(); currentActivity = NodeActivity.Idle; } break; } }
public void Controls() { this.wantsMouseMove = true; var e = Event.current; switch (e.type) { case EventType.DragUpdated: case EventType.DragPerform: DragAndDrop.visualMode = DragAndDropVisualMode.Generic; if (e.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); this.graphEditor.OnDropObjects(DragAndDrop.objectReferences); } break; case EventType.MouseMove: //Keyboard commands will not get correct mouse position from Event this.lastMousePosition = e.mousePosition; break; case EventType.ScrollWheel: var oldZoom = this.zoom; if (e.delta.y > 0) { this.zoom += 0.1f * this.zoom; } else { this.zoom -= 0.1f * this.zoom; } if (NodeEditorPreferences.GetSettings().zoomToMouse) { this.panOffset += (1 - oldZoom / this.zoom) * (this.WindowToGridPosition(e.mousePosition) + this.panOffset); } break; case EventType.MouseDrag: switch (e.button) { case 0: { if (this.IsDraggingPort) { // Set target even if we can't connect, so as to prevent auto-conn menu from opening erroneously if (this.IsHoveringPort && this.hoveredPort.IsInput && !this.draggedOutput.IsConnectedTo(this.hoveredPort)) { this.draggedOutputTarget = this.hoveredPort; } else { this.draggedOutputTarget = null; } this.Repaint(); } else if (currentActivity == NodeActivity.HoldNode) { this.RecalculateDragOffsets(e); currentActivity = NodeActivity.DragNode; this.Repaint(); } switch (currentActivity) { case NodeActivity.DragNode: { // Holding ctrl inverts grid snap var gridSnap = NodeEditorPreferences.GetSettings().gridSnap; if (e.control) { gridSnap = !gridSnap; } var mousePos = this.WindowToGridPosition(e.mousePosition); // Move selected nodes with offset for (var i = 0; i < Selection.objects.Length; i++) { if (!(Selection.objects[i] is xNode.Node node)) { continue; } Undo.RecordObject(node, "Moved Node"); var initial = node.position; node.position = mousePos + dragOffset[i]; if (gridSnap) { node.position.x = (Mathf.Round((node.position.x + 8) / 16) * 16) - 8; node.position.y = (Mathf.Round((node.position.y + 8) / 16) * 16) - 8; } // Offset portConnectionPoints instantly if a node is dragged so they aren't delayed by a frame. var offset = node.position - initial; if (!(offset.sqrMagnitude > 0)) { continue; } foreach (var output in node.Outputs) { if (this.portConnectionPoints.TryGetValue(output, out var rect)) { rect.position += offset; this.portConnectionPoints[output] = rect; } } foreach (var input in node.Inputs) { if (this.portConnectionPoints.TryGetValue(input, out var rect)) { rect.position += offset; this.portConnectionPoints[input] = rect; } } } // Move selected reroutes with offset for (var i = 0; i < this.selectedReroutes.Count; i++) { var pos = mousePos + dragOffset[Selection.objects.Length + i]; if (gridSnap) { pos.x = (Mathf.Round(pos.x / 16) * 16); pos.y = (Mathf.Round(pos.y / 16) * 16); } this.selectedReroutes[i].SetPoint(pos); } this.Repaint(); break; } case NodeActivity.HoldGrid: currentActivity = NodeActivity.DragGrid; this.preBoxSelection = Selection.objects; this.preBoxSelectionReroute = this.selectedReroutes.ToArray(); this.dragBoxStart = this.WindowToGridPosition(e.mousePosition); this.Repaint(); break; case NodeActivity.DragGrid: { var boxStartPos = this.GridToWindowPosition(this.dragBoxStart); var boxSize = e.mousePosition - boxStartPos; if (boxSize.x < 0) { boxStartPos.x += boxSize.x; boxSize.x = Mathf.Abs(boxSize.x); } if (boxSize.y < 0) { boxStartPos.y += boxSize.y; boxSize.y = Mathf.Abs(boxSize.y); } this.selectionBox = new Rect(boxStartPos, boxSize); this.Repaint(); break; } } break; } case 1: case 2: { //check drag threshold for larger screens if (e.delta.magnitude > this.dragThreshold) { this.panOffset += e.delta * this.zoom; isPanning = true; } break; } } break; case EventType.MouseDown: this.Repaint(); if (e.button == 0) { this.draggedOutputReroutes.Clear(); if (this.IsHoveringPort) { if (this.hoveredPort.IsOutput) { this.draggedOutput = this.hoveredPort; this.autoConnectOutput = this.hoveredPort; } else { this.hoveredPort.VerifyConnections(); this.autoConnectOutput = null; if (this.hoveredPort.IsConnected) { var node = this.hoveredPort.node; var output = this.hoveredPort.Connection; var outputConnectionIndex = output.GetConnectionIndex(this.hoveredPort); this.draggedOutputReroutes = output.GetReroutePoints(outputConnectionIndex); this.hoveredPort.Disconnect(output); this.draggedOutput = output; this.draggedOutputTarget = this.hoveredPort; if (NodeEditor.onUpdateNode != null) { NodeEditor.onUpdateNode(node); } } } } else if (this.IsHoveringNode && this.IsHoveringTitle(this.hoveredNode)) { // If mousedown on node header, select or deselect if (!Selection.Contains(this.hoveredNode)) { this.SelectNode(this.hoveredNode, e.control || e.shift); if (!e.control && !e.shift) { this.selectedReroutes.Clear(); } } else if (e.control || e.shift) { this.DeselectNode(this.hoveredNode); } // Cache double click state, but only act on it in MouseUp - Except ClickCount only works in mouseDown. this.isDoubleClick = (e.clickCount == 2); e.Use(); currentActivity = NodeActivity.HoldNode; } else if (this.IsHoveringReroute) { // If reroute isn't selected if (!this.selectedReroutes.Contains(this.hoveredReroute)) { // Add it if (e.control || e.shift) { this.selectedReroutes.Add(this.hoveredReroute); } // Select it else { this.selectedReroutes = new List <RerouteReference>() { this.hoveredReroute }; Selection.activeObject = null; } } // Deselect else if (e.control || e.shift) { this.selectedReroutes.Remove(this.hoveredReroute); } e.Use(); currentActivity = NodeActivity.HoldNode; } // If mousedown on grid background, deselect all else if (!this.IsHoveringNode) { currentActivity = NodeActivity.HoldGrid; if (!e.control && !e.shift) { this.selectedReroutes.Clear(); Selection.activeObject = null; } } } break; case EventType.MouseUp: if (e.button == 0) { //Port drag release if (this.IsDraggingPort) { // If connection is valid, save it if (this.draggedOutputTarget != null && this.draggedOutput.CanConnectTo(this.draggedOutputTarget)) { var node = this.draggedOutputTarget.node; if (this.graph.nodes.Count != 0) { this.draggedOutput.Connect(this.draggedOutputTarget); } // ConnectionIndex can be -1 if the connection is removed instantly after creation var connectionIndex = this.draggedOutput.GetConnectionIndex(this.draggedOutputTarget); if (connectionIndex != -1) { this.draggedOutput.GetReroutePoints(connectionIndex).AddRange(this.draggedOutputReroutes); if (NodeEditor.onUpdateNode != null) { NodeEditor.onUpdateNode(node); } EditorUtility.SetDirty(this.graph); } } // Open context menu for auto-connection if there is no target node else if (this.draggedOutputTarget == null && NodeEditorPreferences.GetSettings().dragToCreate&& this.autoConnectOutput != null) { var menu = new GenericMenu(); this.graphEditor.AddContextMenuItems(menu); menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); } //Release dragged connection this.draggedOutput = null; this.draggedOutputTarget = null; EditorUtility.SetDirty(this.graph); if (NodeEditorPreferences.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } else if (currentActivity == NodeActivity.DragNode) { var nodes = Selection.objects.Where(x => x is xNode.Node).Select(x => x as xNode.Node); foreach (var node in nodes) { EditorUtility.SetDirty(node); } if (NodeEditorPreferences.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } else if (!this.IsHoveringNode) { // If click outside node, release field focus if (!isPanning) { EditorGUI.FocusTextInControl(null); EditorGUIUtility.editingTextField = false; } if (NodeEditorPreferences.GetSettings().autoSave) { AssetDatabase.SaveAssets(); } } // If click node header, select it. if (currentActivity == NodeActivity.HoldNode && !(e.control || e.shift)) { this.selectedReroutes.Clear(); this.SelectNode(this.hoveredNode, false); // Double click to center node if (this.isDoubleClick) { var nodeDimension = this.nodeSizes.ContainsKey(this.hoveredNode) ? this.nodeSizes[this.hoveredNode] / 2 : Vector2.zero; this.panOffset = -this.hoveredNode.position - nodeDimension; } } // If click reroute, select it. if (this.IsHoveringReroute && !(e.control || e.shift)) { this.selectedReroutes = new List <RerouteReference>() { this.hoveredReroute }; Selection.activeObject = null; } this.Repaint(); currentActivity = NodeActivity.Idle; } else if (e.button == 1 || e.button == 2) { if (!isPanning) { if (this.IsDraggingPort) { this.draggedOutputReroutes.Add(this.WindowToGridPosition(e.mousePosition)); } else if (currentActivity == NodeActivity.DragNode && Selection.activeObject == null && this.selectedReroutes.Count == 1) { this.selectedReroutes[0].InsertPoint(this.selectedReroutes[0].GetPoint()); this.selectedReroutes[0] = new RerouteReference(this.selectedReroutes[0].port, this.selectedReroutes[0].connectionIndex, this.selectedReroutes[0].pointIndex + 1); } else if (this.IsHoveringReroute) { this.ShowRerouteContextMenu(this.hoveredReroute); } else if (this.IsHoveringPort) { this.ShowPortContextMenu(this.hoveredPort); } else if (this.IsHoveringNode && this.IsHoveringTitle(this.hoveredNode)) { if (!Selection.Contains(this.hoveredNode)) { this.SelectNode(this.hoveredNode, false); } this.autoConnectOutput = null; var menu = new GenericMenu(); NodeEditor.GetEditor(this.hoveredNode, this).AddContextMenuItems(menu); menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); e.Use(); // Fixes copy/paste context menu appearing in Unity 5.6.6f2 - doesn't occur in 2018.3.2f1 Probably needs to be used in other places. } else if (!this.IsHoveringNode) { this.autoConnectOutput = null; var menu = new GenericMenu(); this.graphEditor.AddContextMenuItems(menu); menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); } } isPanning = false; } // Reset DoubleClick this.isDoubleClick = false; break; case EventType.KeyDown: if (EditorGUIUtility.editingTextField) { break; } else if (e.keyCode == KeyCode.F) { this.Home(); } if (NodeEditorUtilities.IsMac()) { if (e.keyCode == KeyCode.Return) { this.RenameSelectedNode(); } } else { if (e.keyCode == KeyCode.F2) { this.RenameSelectedNode(); } } if (e.keyCode == KeyCode.A) { if (Selection.objects.Any(x => this.graph.nodes.Contains(x as xNode.Node))) { foreach (var node in this.graph.nodes) { this.DeselectNode(node); } } else { foreach (var node in this.graph.nodes) { this.SelectNode(node, true); } } this.Repaint(); } break; case EventType.ValidateCommand: case EventType.ExecuteCommand: if (e.commandName == "SoftDelete") { if (e.type == EventType.ExecuteCommand) { this.RemoveSelectedNodes(); } e.Use(); } else if (NodeEditorUtilities.IsMac() && e.commandName == "Delete") { if (e.type == EventType.ExecuteCommand) { this.RemoveSelectedNodes(); } e.Use(); } else if (e.commandName == "Duplicate") { if (e.type == EventType.ExecuteCommand) { this.DuplicateSelectedNodes(); } e.Use(); } else if (e.commandName == "Copy") { if (e.type == EventType.ExecuteCommand) { this.CopySelectedNodes(); } e.Use(); } else if (e.commandName == "Paste") { if (e.type == EventType.ExecuteCommand) { this.PasteNodes(this.WindowToGridPosition(this.lastMousePosition)); } e.Use(); } this.Repaint(); break; case EventType.Ignore: // If release mouse outside window if (e.rawType == EventType.MouseUp && currentActivity == NodeActivity.DragGrid) { this.Repaint(); currentActivity = NodeActivity.Idle; } break; } }
public void Controls() { wantsMouseMove = true; Event e = Event.current; switch (e.type) { case EventType.MouseMove: break; case EventType.ScrollWheel: if (e.delta.y > 0) { zoom += 0.1f * zoom; } else { zoom -= 0.1f * zoom; } break; case EventType.MouseDrag: if (e.button == 0) { if (IsDraggingPort) { if (IsHoveringPort && hoveredPort.IsInput) { if (!draggedOutput.IsConnectedTo(hoveredPort)) { draggedOutputTarget = hoveredPort; } } else { draggedOutputTarget = null; } Repaint(); } else if (currentActivity == NodeActivity.HoldNode) { RecalculateDragOffsets(e); currentActivity = NodeActivity.DragNode; Repaint(); } if (currentActivity == NodeActivity.DragNode) { // Holding ctrl inverts grid snap bool gridSnap = NodeEditorPreferences.GetSettings().gridSnap; if (e.control) { gridSnap = !gridSnap; } Vector2 mousePos = WindowToGridPosition(e.mousePosition); // Move selected nodes with offset for (int i = 0; i < Selection.objects.Length; i++) { if (Selection.objects[i] is XNode.Node) { XNode.Node node = Selection.objects[i] as XNode.Node; node.position = mousePos + dragOffset[i]; if (gridSnap) { node.position.x = (Mathf.Round((node.position.x + 8) / 16) * 16) - 8; node.position.y = (Mathf.Round((node.position.y + 8) / 16) * 16) - 8; } } } // Move selected reroutes with offset for (int i = 0; i < selectedReroutes.Count; i++) { Vector2 pos = mousePos + dragOffset[Selection.objects.Length + i]; pos.x -= 8; pos.y -= 8; if (gridSnap) { pos.x = (Mathf.Round((pos.x + 8) / 16) * 16); pos.y = (Mathf.Round((pos.y + 8) / 16) * 16); } selectedReroutes[i].SetPoint(pos); } Repaint(); } else if (currentActivity == NodeActivity.HoldGrid) { currentActivity = NodeActivity.DragGrid; preBoxSelection = Selection.objects; preBoxSelectionReroute = selectedReroutes.ToArray(); dragBoxStart = WindowToGridPosition(e.mousePosition); Repaint(); } else if (currentActivity == NodeActivity.DragGrid) { Vector2 boxStartPos = GridToWindowPosition(dragBoxStart); Vector2 boxSize = e.mousePosition - boxStartPos; if (boxSize.x < 0) { boxStartPos.x += boxSize.x; boxSize.x = Mathf.Abs(boxSize.x); } if (boxSize.y < 0) { boxStartPos.y += boxSize.y; boxSize.y = Mathf.Abs(boxSize.y); } selectionBox = new Rect(boxStartPos, boxSize); Repaint(); } } else if (e.button == 1 || e.button == 2) { Vector2 tempOffset = panOffset; tempOffset += e.delta * zoom; // Round value to increase crispyness of UI text tempOffset.x = Mathf.Round(tempOffset.x); tempOffset.y = Mathf.Round(tempOffset.y); panOffset = tempOffset; isPanning = true; } break; case EventType.MouseDown: Repaint(); if (e.button == 0) { draggedOutputReroutes.Clear(); if (IsHoveringPort) { if (hoveredPort.IsOutput) { draggedOutput = hoveredPort; } else { hoveredPort.VerifyConnections(); if (hoveredPort.IsConnected) { XNode.Node node = hoveredPort.node; XNode.NodePort output = hoveredPort.Connection; int outputConnectionIndex = output.GetConnectionIndex(hoveredPort); draggedOutputReroutes = output.GetReroutePoints(outputConnectionIndex); hoveredPort.Disconnect(output); draggedOutput = output; draggedOutputTarget = hoveredPort; if (NodeEditor.onUpdateNode != null) { NodeEditor.onUpdateNode(node); } } } } else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) { // If mousedown on node header, select or deselect if (!Selection.Contains(hoveredNode)) { SelectNode(hoveredNode, e.control || e.shift); if (!e.control && !e.shift) { selectedReroutes.Clear(); } } else if (e.control || e.shift) { DeselectNode(hoveredNode); } e.Use(); currentActivity = NodeActivity.HoldNode; } else if (IsHoveringReroute) { // If reroute isn't selected if (!selectedReroutes.Contains(hoveredReroute)) { // Add it if (e.control || e.shift) { selectedReroutes.Add(hoveredReroute); } // Select it else { selectedReroutes = new List <RerouteReference>() { hoveredReroute }; Selection.activeObject = null; } } // Deselect else if (e.control || e.shift) { selectedReroutes.Remove(hoveredReroute); } e.Use(); currentActivity = NodeActivity.HoldNode; } // If mousedown on grid background, deselect all else if (!IsHoveringNode) { currentActivity = NodeActivity.HoldGrid; if (!e.control && !e.shift) { selectedReroutes.Clear(); Selection.activeObject = null; } } } break; case EventType.MouseUp: if (e.button == 0) { //Port drag release if (IsDraggingPort) { //If connection is valid, save it if (draggedOutputTarget != null) { XNode.Node node = draggedOutputTarget.node; if (graph.nodes.Count != 0) { draggedOutput.Connect(draggedOutputTarget); } // ConnectionIndex can be -1 if the connection is removed instantly after creation int connectionIndex = draggedOutput.GetConnectionIndex(draggedOutputTarget); if (connectionIndex != -1) { draggedOutput.GetReroutePoints(connectionIndex).AddRange(draggedOutputReroutes); if (NodeEditor.onUpdateNode != null) { NodeEditor.onUpdateNode(node); } EditorUtility.SetDirty(graph); } } //Release dragged connection draggedOutput = null; draggedOutputTarget = null; EditorUtility.SetDirty(graph); AssetDatabase.SaveAssets(); } else if (currentActivity == NodeActivity.DragNode) { AssetDatabase.SaveAssets(); } else if (!IsHoveringNode) { // If click outside node, release field focus if (!isPanning) { // I've got no idea which of these do what, so we'll just reset all of it. GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; EditorGUIUtility.editingTextField = false; EditorGUIUtility.keyboardControl = 0; EditorGUIUtility.hotControl = 0; } AssetDatabase.SaveAssets(); } // If click node header, select it. if (currentActivity == NodeActivity.HoldNode && !(e.control || e.shift)) { selectedReroutes.Clear(); SelectNode(hoveredNode, false); } // If click reroute, select it. if (IsHoveringReroute && !(e.control || e.shift)) { selectedReroutes = new List <RerouteReference>() { hoveredReroute }; Selection.activeObject = null; } Repaint(); currentActivity = NodeActivity.Idle; } else if (e.button == 1) { if (!isPanning) { if (IsDraggingPort) { draggedOutputReroutes.Add(WindowToGridPosition(e.mousePosition)); } else if (currentActivity == NodeActivity.DragNode && Selection.activeObject == null && selectedReroutes.Count == 1) { selectedReroutes[0].InsertPoint(selectedReroutes[0].GetPoint()); selectedReroutes[0] = new RerouteReference(selectedReroutes[0].port, selectedReroutes[0].connectionIndex, selectedReroutes[0].pointIndex + 1); } else if (IsHoveringReroute) { ShowRerouteContextMenu(hoveredReroute); } else if (IsHoveringPort) { ShowPortContextMenu(hoveredPort); } else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) { if (!Selection.Contains(hoveredNode)) { SelectNode(hoveredNode, false); } ShowNodeContextMenu(); } else if (!IsHoveringNode) { ShowGraphContextMenu(); } } isPanning = false; } break; case EventType.KeyDown: if (EditorGUIUtility.editingTextField) { break; } else if (e.keyCode == KeyCode.F) { Home(); } break; case EventType.ValidateCommand: if (e.commandName == "SoftDelete") { RemoveSelectedNodes(); } else if (e.commandName == "Duplicate") { DublicateSelectedNodes(); } Repaint(); break; case EventType.Ignore: // If release mouse outside window if (e.rawType == EventType.MouseUp && currentActivity == NodeActivity.DragGrid) { Repaint(); currentActivity = NodeActivity.Idle; } break; } }