diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs index 85b0417..a2b95b7 100644 --- a/Scripts/Editor/NodeEditorAction.cs +++ b/Scripts/Editor/NodeEditorAction.cs @@ -5,10 +5,8 @@ using UnityEditor; using UnityEngine; using XNodeEditor.Internal; -namespace XNodeEditor -{ - public partial class NodeEditorWindow - { +namespace XNodeEditor { + public partial class NodeEditorWindow { public enum NodeActivity { Idle, HoldNode, DragNode, HoldGrid, DragGrid } public static NodeActivity currentActivity = NodeActivity.Idle; public static bool isPanning { get; private set; } @@ -45,17 +43,14 @@ namespace XNodeEditor private Vector2 lastMousePosition; private float dragThreshold = 1f; - public void Controls() - { + public void Controls() { wantsMouseMove = true; Event e = Event.current; - switch (e.type) - { + switch (e.type) { case EventType.DragUpdated: case EventType.DragPerform: DragAndDrop.visualMode = DragAndDropVisualMode.Generic; - if (e.type == EventType.DragPerform) - { + if (e.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); graphEditor.OnDropObjects(DragAndDrop.objectReferences); } @@ -71,68 +66,52 @@ namespace XNodeEditor if (NodeEditorPreferences.GetSettings().zoomToMouse) panOffset += (1 - oldZoom / zoom) * (WindowToGridPosition(e.mousePosition) + panOffset); break; case EventType.MouseDrag: - if (e.button == 0) - { - if (IsDraggingPort) - { + if (e.button == 0) { + if (IsDraggingPort) { // Set target even if we can't connect, so as to prevent auto-conn menu from opening erroneously - if (IsHoveringPort && hoveredPort.IsInput && !draggedOutput.IsConnectedTo(hoveredPort)) - { + if (IsHoveringPort && hoveredPort.IsInput && !draggedOutput.IsConnectedTo(hoveredPort)) { draggedOutputTarget = hoveredPort; - } - else - { + } else { draggedOutputTarget = null; } Repaint(); - } - else if (currentActivity == NodeActivity.HoldNode) - { + } else if (currentActivity == NodeActivity.HoldNode) { RecalculateDragOffsets(e); currentActivity = NodeActivity.DragNode; Repaint(); } - if (currentActivity == NodeActivity.DragNode) - { + 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) - { + 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; Undo.RecordObject(node, "Moved Node"); Vector2 initial = node.position; node.position = mousePos + dragOffset[i]; - if (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; } // 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) - { + if (offset.sqrMagnitude > 0) { + foreach (XNode.NodePort output in node.Outputs) { Rect rect; - if (portConnectionPoints.TryGetValue(output, out rect)) - { + if (portConnectionPoints.TryGetValue(output, out rect)) { rect.position += offset; portConnectionPoints[output] = rect; } } - foreach (XNode.NodePort input in node.Inputs) - { + foreach (XNode.NodePort input in node.Inputs) { Rect rect; - if (portConnectionPoints.TryGetValue(input, out rect)) - { + if (portConnectionPoints.TryGetValue(input, out rect)) { rect.position += offset; portConnectionPoints[input] = rect; } @@ -141,28 +120,22 @@ namespace XNodeEditor } } // Move selected reroutes with offset - for (int i = 0; i < selectedReroutes.Count; i++) - { + for (int i = 0; i < selectedReroutes.Count; i++) { Vector2 pos = mousePos + dragOffset[Selection.objects.Length + i]; - if (gridSnap) - { + 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) - { + } else if (currentActivity == NodeActivity.HoldGrid) { currentActivity = NodeActivity.DragGrid; preBoxSelection = Selection.objects; preBoxSelectionReroute = selectedReroutes.ToArray(); dragBoxStart = WindowToGridPosition(e.mousePosition); Repaint(); - } - else if (currentActivity == NodeActivity.DragGrid) - { + } 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); } @@ -170,12 +143,9 @@ namespace XNodeEditor selectionBox = new Rect(boxStartPos, boxSize); Repaint(); } - } - else if (e.button == 1 || e.button == 2) - { + } else if (e.button == 1 || e.button == 2) { //check drag threshold for larger screens - if (e.delta.magnitude > dragThreshold) - { + if (e.delta.magnitude > dragThreshold) { panOffset += e.delta * zoom; isPanning = true; } @@ -183,23 +153,17 @@ namespace XNodeEditor break; case EventType.MouseDown: Repaint(); - if (e.button == 0) - { + if (e.button == 0) { draggedOutputReroutes.Clear(); - if (IsHoveringPort) - { - if (hoveredPort.IsOutput) - { + if (IsHoveringPort) { + if (hoveredPort.IsOutput) { draggedOutput = hoveredPort; autoConnectOutput = hoveredPort; - } - else - { + } else { hoveredPort.VerifyConnections(); autoConnectOutput = null; - if (hoveredPort.IsConnected) - { + if (hoveredPort.IsConnected) { XNode.Node node = hoveredPort.node; XNode.NodePort output = hoveredPort.Connection; int outputConnectionIndex = output.GetConnectionIndex(hoveredPort); @@ -210,33 +174,25 @@ namespace XNodeEditor if (NodeEditor.onUpdateNode != null) NodeEditor.onUpdateNode(node); } } - } - else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) - { + } else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) { // If mousedown on node header, select or deselect - if (!Selection.Contains(hoveredNode)) - { + 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); + } 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) - { + } else if (IsHoveringReroute) { // If reroute isn't selected - if (!selectedReroutes.Contains(hoveredReroute)) - { + if (!selectedReroutes.Contains(hoveredReroute)) { // Add it if (e.control || e.shift) selectedReroutes.Add(hoveredReroute); // Select it - else - { + else { selectedReroutes = new List() { hoveredReroute }; Selection.activeObject = null; } @@ -248,11 +204,9 @@ namespace XNodeEditor currentActivity = NodeActivity.HoldNode; } // If mousedown on grid background, deselect all - else if (!IsHoveringNode) - { + else if (!IsHoveringNode) { currentActivity = NodeActivity.HoldGrid; - if (!e.control && !e.shift) - { + if (!e.control && !e.shift) { selectedReroutes.Clear(); Selection.activeObject = null; } @@ -260,29 +214,24 @@ namespace XNodeEditor } break; case EventType.MouseUp: - if (e.button == 0) - { + if (e.button == 0) { //Port drag release - if (IsDraggingPort) - { + if (IsDraggingPort) { // If connection is valid, save it - if (draggedOutputTarget != null && draggedOutput.CanConnectTo(draggedOutputTarget)) - { + if (draggedOutputTarget != null && draggedOutput.CanConnectTo(draggedOutputTarget)) { 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) - { + if (connectionIndex != -1) { draggedOutput.GetReroutePoints(connectionIndex).AddRange(draggedOutputReroutes); if (NodeEditor.onUpdateNode != null) NodeEditor.onUpdateNode(node); EditorUtility.SetDirty(graph); } } // Open context menu for auto-connection if there is no target node - else if (draggedOutputTarget == null && NodeEditorPreferences.GetSettings().dragToCreate && autoConnectOutput != null) - { + else if (draggedOutputTarget == null && NodeEditorPreferences.GetSettings().dragToCreate && autoConnectOutput != null) { GenericMenu menu = new GenericMenu(); graphEditor.AddContextMenuItems(menu, draggedOutput.ValueType); menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); @@ -292,18 +241,13 @@ namespace XNodeEditor draggedOutputTarget = null; EditorUtility.SetDirty(graph); if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); - } - else if (currentActivity == NodeActivity.DragNode) - { + } else if (currentActivity == NodeActivity.DragNode) { IEnumerable 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) - { + } else if (!IsHoveringNode) { // If click outside node, release field focus - if (!isPanning) - { + if (!isPanning) { EditorGUI.FocusTextInControl(null); EditorGUIUtility.editingTextField = false; } @@ -311,61 +255,44 @@ namespace XNodeEditor } // If click node header, select it. - if (currentActivity == NodeActivity.HoldNode && !(e.control || e.shift)) - { + if (currentActivity == NodeActivity.HoldNode && !(e.control || e.shift)) { selectedReroutes.Clear(); SelectNode(hoveredNode, false); // Double click to center node - if (isDoubleClick) - { + 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)) - { + if (IsHoveringReroute && !(e.control || e.shift)) { selectedReroutes = new List() { hoveredReroute }; Selection.activeObject = null; } Repaint(); currentActivity = NodeActivity.Idle; - } - else if (e.button == 1 || e.button == 2) - { - if (!isPanning) - { - if (IsDraggingPort) - { + } 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) - { + } 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) - { + } else if (IsHoveringReroute) { ShowRerouteContextMenu(hoveredReroute); - } - else if (IsHoveringPort) - { + } else if (IsHoveringPort) { ShowPortContextMenu(hoveredPort); - } - else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) - { + } 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) - { + } else if (!IsHoveringNode) { autoConnectOutput = null; GenericMenu menu = new GenericMenu(); graphEditor.AddContextMenuItems(menu); @@ -380,27 +307,18 @@ namespace XNodeEditor case EventType.KeyDown: if (EditorGUIUtility.editingTextField) break; else if (e.keyCode == KeyCode.F) Home(); - if (NodeEditorUtilities.IsMac()) - { + if (NodeEditorUtilities.IsMac()) { if (e.keyCode == KeyCode.Return) RenameSelectedNode(); - } - else - { + } 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) - { + 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) - { + } else { + foreach (XNode.Node node in graph.nodes) { SelectNode(node, true); } } @@ -409,28 +327,19 @@ namespace XNodeEditor break; case EventType.ValidateCommand: case EventType.ExecuteCommand: - if (e.commandName == "SoftDelete") - { + if (e.commandName == "SoftDelete") { if (e.type == EventType.ExecuteCommand) RemoveSelectedNodes(); e.Use(); - } - else if (NodeEditorUtilities.IsMac() && e.commandName == "Delete") - { + } else if (NodeEditorUtilities.IsMac() && e.commandName == "Delete") { if (e.type == EventType.ExecuteCommand) RemoveSelectedNodes(); e.Use(); - } - else if (e.commandName == "Duplicate") - { + } else if (e.commandName == "Duplicate") { if (e.type == EventType.ExecuteCommand) DuplicateSelectedNodes(); e.Use(); - } - else if (e.commandName == "Copy") - { + } else if (e.commandName == "Copy") { if (e.type == EventType.ExecuteCommand) CopySelectedNodes(); e.Use(); - } - else if (e.commandName == "Paste") - { + } else if (e.commandName == "Paste") { if (e.type == EventType.ExecuteCommand) PasteNodes(WindowToGridPosition(lastMousePosition)); e.Use(); } @@ -438,8 +347,7 @@ namespace XNodeEditor break; case EventType.Ignore: // If release mouse outside window - if (e.rawType == EventType.MouseUp && currentActivity == NodeActivity.DragGrid) - { + if (e.rawType == EventType.MouseUp && currentActivity == NodeActivity.DragGrid) { Repaint(); currentActivity = NodeActivity.Idle; } @@ -447,57 +355,45 @@ namespace XNodeEditor } } - private void RecalculateDragOffsets(Event current) - { + private void RecalculateDragOffsets(Event current) { dragOffset = new Vector2[Selection.objects.Length + selectedReroutes.Count]; // Selected nodes - for (int i = 0; i < Selection.objects.Length; i++) - { - if (Selection.objects[i] is XNode.Node) - { + 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; dragOffset[i] = node.position - WindowToGridPosition(current.mousePosition); } } // Selected reroutes - for (int i = 0; i < selectedReroutes.Count; i++) - { + for (int i = 0; i < selectedReroutes.Count; i++) { dragOffset[Selection.objects.Length + i] = selectedReroutes[i].GetPoint() - WindowToGridPosition(current.mousePosition); } } /// Puts all selected nodes in focus. If no nodes are present, resets view and zoom to to origin - public void Home() - { + public void Home() { var nodes = Selection.objects.Where(o => o is XNode.Node).Cast().ToList(); - if (nodes.Count > 0) - { + if (nodes.Count > 0) { Vector2 minPos = nodes.Select(x => x.position).Aggregate((x, y) => new Vector2(Mathf.Min(x.x, y.x), Mathf.Min(x.y, y.y))); Vector2 maxPos = nodes.Select(x => x.position + (nodeSizes.ContainsKey(x) ? nodeSizes[x] : Vector2.zero)).Aggregate((x, y) => new Vector2(Mathf.Max(x.x, y.x), Mathf.Max(x.y, y.y))); panOffset = -(minPos + (maxPos - minPos) / 2f); - } - else - { + } else { zoom = 2; panOffset = Vector2.zero; } } /// Remove nodes in the graph in Selection.objects - public void RemoveSelectedNodes() - { + public void RemoveSelectedNodes() { // We need to delete reroutes starting at the highest point index to avoid shifting indices selectedReroutes = selectedReroutes.OrderByDescending(x => x.pointIndex).ToList(); - for (int i = 0; i < selectedReroutes.Count; i++) - { + for (int i = 0; i < selectedReroutes.Count; i++) { selectedReroutes[i].RemovePoint(); } selectedReroutes.Clear(); - foreach (UnityEngine.Object item in Selection.objects) - { - if (item is XNode.Node) - { + foreach (UnityEngine.Object item in Selection.objects) { + if (item is XNode.Node) { XNode.Node node = item as XNode.Node; graphEditor.RemoveNode(node); } @@ -505,37 +401,29 @@ namespace XNodeEditor } /// Initiate a rename on the currently selected node - public void RenameSelectedNode() - { - if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) - { + public void RenameSelectedNode() { + if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) { XNode.Node node = Selection.activeObject as XNode.Node; Vector2 size; - if (nodeSizes.TryGetValue(node, out size)) - { + if (nodeSizes.TryGetValue(node, out size)) { RenamePopup.Show(Selection.activeObject, size.x); - } - else - { + } else { RenamePopup.Show(Selection.activeObject); } } } /// Draw this node on top of other nodes by placing it last in the graph.nodes list - public void MoveNodeToTop(XNode.Node node) - { + public void MoveNodeToTop(XNode.Node node) { int index; - while ((index = graph.nodes.IndexOf(node)) != graph.nodes.Count - 1) - { + while ((index = graph.nodes.IndexOf(node)) != graph.nodes.Count - 1) { graph.nodes[index] = graph.nodes[index + 1]; graph.nodes[index + 1] = node; } } /// Duplicate selected nodes and select the duplicates - public void DuplicateSelectedNodes() - { + public void DuplicateSelectedNodes() { // Get selected nodes which are part of this graph XNode.Node[] selectedNodes = Selection.objects.Select(x => x as XNode.Node).Where(x => x != null && x.graph == graph).ToArray(); if (selectedNodes == null || selectedNodes.Length == 0) return; @@ -544,18 +432,15 @@ namespace XNodeEditor InsertDuplicateNodes(selectedNodes, topLeftNode + new Vector2(30, 30)); } - public void CopySelectedNodes() - { + public void CopySelectedNodes() { copyBuffer = Selection.objects.Select(x => x as XNode.Node).Where(x => x != null && x.graph == graph).ToArray(); } - public void PasteNodes(Vector2 pos) - { + public void PasteNodes(Vector2 pos) { InsertDuplicateNodes(copyBuffer, pos); } - private void InsertDuplicateNodes(XNode.Node[] nodes, Vector2 topLeft) - { + private void InsertDuplicateNodes(XNode.Node[] nodes, Vector2 topLeft) { if (nodes == null || nodes.Length == 0) return; // Get top-left node @@ -564,16 +449,14 @@ namespace XNodeEditor UnityEngine.Object[] newNodes = new UnityEngine.Object[nodes.Length]; Dictionary substitutes = new Dictionary(); - for (int i = 0; i < nodes.Length; i++) - { + for (int i = 0; i < nodes.Length; i++) { XNode.Node srcNode = nodes[i]; if (srcNode == null) continue; // Check if user is allowed to add more of given node type XNode.Node.DisallowMultipleNodesAttribute disallowAttrib; Type nodeType = srcNode.GetType(); - if (NodeEditorUtilities.GetAttrib(nodeType, out disallowAttrib)) - { + if (NodeEditorUtilities.GetAttrib(nodeType, out disallowAttrib)) { int typeCount = graph.nodes.Count(x => x.GetType() == nodeType); if (typeCount >= disallowAttrib.max) continue; } @@ -585,20 +468,16 @@ namespace XNodeEditor } // Walk through the selected nodes again, recreate connections, using the new nodes - for (int i = 0; i < nodes.Length; i++) - { + for (int i = 0; i < nodes.Length; i++) { XNode.Node srcNode = nodes[i]; if (srcNode == null) continue; - foreach (XNode.NodePort port in srcNode.Ports) - { - for (int c = 0; c < port.ConnectionCount; c++) - { + foreach (XNode.NodePort port in srcNode.Ports) { + for (int c = 0; c < port.ConnectionCount; c++) { XNode.NodePort inputPort = port.direction == XNode.NodePort.IO.Input ? port : port.GetConnection(c); XNode.NodePort outputPort = port.direction == XNode.NodePort.IO.Output ? port : port.GetConnection(c); XNode.Node newNodeIn, newNodeOut; - if (substitutes.TryGetValue(inputPort.node, out newNodeIn) && substitutes.TryGetValue(outputPort.node, out newNodeOut)) - { + if (substitutes.TryGetValue(inputPort.node, out newNodeIn) && substitutes.TryGetValue(outputPort.node, out newNodeOut)) { newNodeIn.UpdatePorts(); newNodeOut.UpdatePorts(); inputPort = newNodeIn.GetInputPort(inputPort.fieldName); @@ -614,10 +493,8 @@ namespace XNodeEditor } /// Draw a connection as we are dragging it - public void DrawDraggedConnection() - { - if (IsDraggingPort) - { + public void DrawDraggedConnection() { + if (IsDraggingPort) { Gradient gradient = graphEditor.GetNoodleGradient(draggedOutput, null); float thickness = graphEditor.GetNoodleThickness(draggedOutput, null); NoodlePath path = graphEditor.GetNoodlePath(draggedOutput, null); @@ -627,8 +504,7 @@ namespace XNodeEditor if (!_portConnectionPoints.TryGetValue(draggedOutput, out fromRect)) return; List gridPoints = new List(); gridPoints.Add(fromRect.center); - for (int i = 0; i < draggedOutputReroutes.Count; i++) - { + for (int i = 0; i < draggedOutputReroutes.Count; i++) { gridPoints.Add(draggedOutputReroutes[i]); } if (draggedOutputTarget != null) gridPoints.Add(portConnectionPoints[draggedOutputTarget].center); @@ -643,8 +519,7 @@ namespace XNodeEditor frcol.a = 0.6f; // Loop through reroute points again and draw the points - for (int i = 0; i < draggedOutputReroutes.Count; i++) - { + for (int i = 0; i < draggedOutputReroutes.Count; i++) { // Draw reroute point at position Rect rect = new Rect(draggedOutputReroutes[i], new Vector2(16, 16)); rect.position = new Vector2(rect.position.x - 8, rect.position.y - 8); @@ -655,8 +530,7 @@ namespace XNodeEditor } } - bool IsHoveringTitle(XNode.Node node) - { + bool IsHoveringTitle(XNode.Node node) { Vector2 mousePos = Event.current.mousePosition; //Get node position Vector2 nodePos = GridToWindowPosition(node.position); @@ -669,8 +543,7 @@ namespace XNodeEditor } /// Attempt to connect dragged output to target node - public void AutoConnect(XNode.Node node) - { + public void AutoConnect(XNode.Node node) { if (autoConnectOutput == null) return; // Find input port of same type diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index 78c9614..ca726d5 100755 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -119,8 +119,7 @@ namespace XNodeEditor { } contextMenu.AddItem(new GUIContent("Clear Connections"), false, () => hoveredPort.ClearConnections()); //Get compatible nodes with this port - if (NodeEditorPreferences.GetSettings().createFilter) - { + if (NodeEditorPreferences.GetSettings().createFilter) { contextMenu.AddSeparator(""); if (hoveredPort.direction == XNode.NodePort.IO.Input) @@ -573,8 +572,7 @@ namespace XNodeEditor { string tooltip = null; if (hoveredPort != null) { tooltip = graphEditor.GetPortTooltip(hoveredPort); - } - else if (hoveredNode != null && IsHoveringNode && IsHoveringTitle(hoveredNode)) { + } else if (hoveredNode != null && IsHoveringNode && IsHoveringTitle(hoveredNode)) { tooltip = NodeEditor.GetEditor(hoveredNode, this).GetHeaderTooltip(); } if (string.IsNullOrEmpty(tooltip)) return; diff --git a/Scripts/Editor/NodeEditorGUILayout.cs b/Scripts/Editor/NodeEditorGUILayout.cs index 9a6cc1b..8c93cb2 100644 --- a/Scripts/Editor/NodeEditorGUILayout.cs +++ b/Scripts/Editor/NodeEditorGUILayout.cs @@ -7,24 +7,20 @@ using UnityEditor; using UnityEditorInternal; using UnityEngine; -namespace XNodeEditor -{ +namespace XNodeEditor { /// xNode-specific version of - public static class NodeEditorGUILayout - { + public static class NodeEditorGUILayout { private static readonly Dictionary> reorderableListCache = new Dictionary>(); private static int reorderableListIndex = -1; /// Make a field for a serialized property. Automatically displays relevant node port. - public static void PropertyField(SerializedProperty property, bool includeChildren = true, params GUILayoutOption[] options) - { + public static void PropertyField(SerializedProperty property, bool includeChildren = true, params GUILayoutOption[] options) { PropertyField(property, (GUIContent)null, includeChildren, options); } /// Make a field for a serialized property. Automatically displays relevant node port. - public static void PropertyField(SerializedProperty property, GUIContent label, bool includeChildren = true, params GUILayoutOption[] options) - { + public static void PropertyField(SerializedProperty property, GUIContent label, bool includeChildren = true, params GUILayoutOption[] options) { if (property == null) throw new NullReferenceException(); XNode.Node node = property.serializedObject.targetObject as XNode.Node; XNode.NodePort port = node.GetPort(property.name); @@ -32,33 +28,28 @@ namespace XNodeEditor } /// Make a field for a serialized property. Manual node port override. - public static void PropertyField(SerializedProperty property, XNode.NodePort port, bool includeChildren = true, params GUILayoutOption[] options) - { + public static void PropertyField(SerializedProperty property, XNode.NodePort port, bool includeChildren = true, params GUILayoutOption[] options) { PropertyField(property, null, port, includeChildren, options); } /// Make a field for a serialized property. Manual node port override. - public static void PropertyField(SerializedProperty property, GUIContent label, XNode.NodePort port, bool includeChildren = true, params GUILayoutOption[] options) - { + public static void PropertyField(SerializedProperty property, GUIContent label, XNode.NodePort port, bool includeChildren = true, params GUILayoutOption[] options) { if (property == null) throw new NullReferenceException(); // If property is not a port, display a regular property field if (port == null) EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); - else - { + else { Rect rect = new Rect(); List propertyAttributes = NodeEditorUtilities.GetCachedPropertyAttribs(port.node.GetType(), property.name); // If property is an input, display a regular property field and put a port handle on the left side - if (port.direction == XNode.NodePort.IO.Input) - { + if (port.direction == XNode.NodePort.IO.Input) { // Get data from [Input] attribute XNode.Node.ShowBackingValue showBacking = XNode.Node.ShowBackingValue.Unconnected; XNode.Node.InputAttribute inputAttribute; bool dynamicPortList = false; - if (NodeEditorUtilities.GetCachedAttrib(port.node.GetType(), property.name, out inputAttribute)) - { + if (NodeEditorUtilities.GetCachedAttrib(port.node.GetType(), property.name, out inputAttribute)) { dynamicPortList = inputAttribute.dynamicPortList; showBacking = inputAttribute.backingValue; } @@ -69,40 +60,30 @@ namespace XNodeEditor float spacePadding = 0; string tooltip = null; - foreach (var attr in propertyAttributes) - { - if (attr is SpaceAttribute) - { + foreach (var attr in propertyAttributes) { + if (attr is SpaceAttribute) { if (usePropertyAttributes) GUILayout.Space((attr as SpaceAttribute).height); else spacePadding += (attr as SpaceAttribute).height; - } - else if (attr is HeaderAttribute) - { - if (usePropertyAttributes) - { + } else if (attr is HeaderAttribute) { + if (usePropertyAttributes) { //GUI Values are from https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/ScriptAttributeGUI/Implementations/DecoratorDrawers.cs Rect position = GUILayoutUtility.GetRect(0, (EditorGUIUtility.singleLineHeight * 1.5f) - EditorGUIUtility.standardVerticalSpacing); //Layout adds standardVerticalSpacing after rect so we subtract it. position.yMin += EditorGUIUtility.singleLineHeight * 0.5f; position = EditorGUI.IndentedRect(position); GUI.Label(position, (attr as HeaderAttribute).header, EditorStyles.boldLabel); - } - else spacePadding += EditorGUIUtility.singleLineHeight * 1.5f; - } - else if (attr is TooltipAttribute) - { + } else spacePadding += EditorGUIUtility.singleLineHeight * 1.5f; + } else if (attr is TooltipAttribute) { tooltip = (attr as TooltipAttribute).tooltip; } } - if (dynamicPortList) - { + if (dynamicPortList) { Type type = GetType(property); XNode.Node.ConnectionType connectionType = inputAttribute != null ? inputAttribute.connectionType : XNode.Node.ConnectionType.Multiple; DynamicPortList(property.name, type, property.serializedObject, port.direction, connectionType); return; } - switch (showBacking) - { + switch (showBacking) { case XNode.Node.ShowBackingValue.Unconnected: // Display a label if port is connected if (port.IsConnected) EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName, tooltip)); @@ -123,15 +104,12 @@ namespace XNodeEditor float paddingLeft = NodeEditorWindow.current.graphEditor.GetPortStyle(port).padding.left; rect.position = rect.position - new Vector2(16 + paddingLeft, -spacePadding); // If property is an output, display a text label and put a port handle on the right side - } - else if (port.direction == XNode.NodePort.IO.Output) - { + } else if (port.direction == XNode.NodePort.IO.Output) { // Get data from [Output] attribute XNode.Node.ShowBackingValue showBacking = XNode.Node.ShowBackingValue.Unconnected; XNode.Node.OutputAttribute outputAttribute; bool dynamicPortList = false; - if (NodeEditorUtilities.GetCachedAttrib(port.node.GetType(), property.name, out outputAttribute)) - { + if (NodeEditorUtilities.GetCachedAttrib(port.node.GetType(), property.name, out outputAttribute)) { dynamicPortList = outputAttribute.dynamicPortList; showBacking = outputAttribute.backingValue; } @@ -142,40 +120,30 @@ namespace XNodeEditor float spacePadding = 0; string tooltip = null; - foreach (var attr in propertyAttributes) - { - if (attr is SpaceAttribute) - { + foreach (var attr in propertyAttributes) { + if (attr is SpaceAttribute) { if (usePropertyAttributes) GUILayout.Space((attr as SpaceAttribute).height); else spacePadding += (attr as SpaceAttribute).height; - } - else if (attr is HeaderAttribute) - { - if (usePropertyAttributes) - { + } else if (attr is HeaderAttribute) { + if (usePropertyAttributes) { //GUI Values are from https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/ScriptAttributeGUI/Implementations/DecoratorDrawers.cs Rect position = GUILayoutUtility.GetRect(0, (EditorGUIUtility.singleLineHeight * 1.5f) - EditorGUIUtility.standardVerticalSpacing); //Layout adds standardVerticalSpacing after rect so we subtract it. position.yMin += EditorGUIUtility.singleLineHeight * 0.5f; position = EditorGUI.IndentedRect(position); GUI.Label(position, (attr as HeaderAttribute).header, EditorStyles.boldLabel); - } - else spacePadding += EditorGUIUtility.singleLineHeight * 1.5f; - } - else if (attr is TooltipAttribute) - { + } else spacePadding += EditorGUIUtility.singleLineHeight * 1.5f; + } else if (attr is TooltipAttribute) { tooltip = (attr as TooltipAttribute).tooltip; } } - if (dynamicPortList) - { + if (dynamicPortList) { Type type = GetType(property); XNode.Node.ConnectionType connectionType = outputAttribute != null ? outputAttribute.connectionType : XNode.Node.ConnectionType.Multiple; DynamicPortList(property.name, type, property.serializedObject, port.direction, connectionType); return; } - switch (showBacking) - { + switch (showBacking) { case XNode.Node.ShowBackingValue.Unconnected: // Display a label if port is connected if (port.IsConnected) EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName, tooltip), NodeEditorResources.OutputPort, GUILayout.MinWidth(30)); @@ -210,30 +178,26 @@ namespace XNodeEditor } } - private static System.Type GetType(SerializedProperty property) - { + private static System.Type GetType(SerializedProperty property) { System.Type parentType = property.serializedObject.targetObject.GetType(); System.Reflection.FieldInfo fi = parentType.GetFieldInfo(property.name); return fi.FieldType; } /// Make a simple port field. - public static void PortField(XNode.NodePort port, params GUILayoutOption[] options) - { + public static void PortField(XNode.NodePort port, params GUILayoutOption[] options) { PortField(null, port, options); } /// Make a simple port field. - public static void PortField(GUIContent label, XNode.NodePort port, params GUILayoutOption[] options) - { + public static void PortField(GUIContent label, XNode.NodePort port, params GUILayoutOption[] options) { if (port == null) return; if (options == null) options = new GUILayoutOption[] { GUILayout.MinWidth(30) }; Vector2 position = Vector3.zero; GUIContent content = label != null ? label : new GUIContent(ObjectNames.NicifyVariableName(port.fieldName)); // If property is an input, display a regular property field and put a port handle on the left side - if (port.direction == XNode.NodePort.IO.Input) - { + if (port.direction == XNode.NodePort.IO.Input) { // Display a label EditorGUILayout.LabelField(content, options); @@ -242,8 +206,7 @@ namespace XNodeEditor position = rect.position - new Vector2(16 + paddingLeft, 0); } // If property is an output, display a text label and put a port handle on the right side - else if (port.direction == XNode.NodePort.IO.Output) - { + else if (port.direction == XNode.NodePort.IO.Output) { // Display a label EditorGUILayout.LabelField(content, NodeEditorResources.OutputPort, options); @@ -255,8 +218,7 @@ namespace XNodeEditor } /// Make a simple port field. - public static void PortField(Vector2 position, XNode.NodePort port) - { + public static void PortField(Vector2 position, XNode.NodePort port) { if (port == null) return; Rect rect = new Rect(position, new Vector2(16, 16)); @@ -273,21 +235,17 @@ namespace XNodeEditor } /// Add a port field to previous layout element. - public static void AddPortField(XNode.NodePort port) - { + public static void AddPortField(XNode.NodePort port) { if (port == null) return; Rect rect = new Rect(); // If property is an input, display a regular property field and put a port handle on the left side - if (port.direction == XNode.NodePort.IO.Input) - { + if (port.direction == XNode.NodePort.IO.Input) { rect = GUILayoutUtility.GetLastRect(); float paddingLeft = NodeEditorWindow.current.graphEditor.GetPortStyle(port).padding.left; rect.position = rect.position - new Vector2(16 + paddingLeft, 0); // If property is an output, display a text label and put a port handle on the right side - } - else if (port.direction == XNode.NodePort.IO.Output) - { + } else if (port.direction == XNode.NodePort.IO.Output) { rect = GUILayoutUtility.GetLastRect(); rect.width += NodeEditorWindow.current.graphEditor.GetPortStyle(port).padding.right; rect.position = rect.position + new Vector2(rect.width, 0); @@ -307,8 +265,7 @@ namespace XNodeEditor } /// Draws an input and an output port on the same line - public static void PortPair(XNode.NodePort input, XNode.NodePort output) - { + public static void PortPair(XNode.NodePort input, XNode.NodePort output) { GUILayout.BeginHorizontal(); NodeEditorGUILayout.PortField(input, GUILayout.MinWidth(0)); NodeEditorGUILayout.PortField(output, GUILayout.MinWidth(0)); @@ -323,8 +280,7 @@ namespace XNodeEditor /// /// texture for border of the dot port /// texture for the dot port - public static void DrawPortHandle(Rect rect, Color backgroundColor, Color typeColor, Texture2D border, Texture2D dot) - { + public static void DrawPortHandle(Rect rect, Color backgroundColor, Color typeColor, Texture2D border, Texture2D dot) { Color col = GUI.color; GUI.color = backgroundColor; GUI.DrawTexture(rect, border); @@ -336,26 +292,22 @@ namespace XNodeEditor #region Obsolete [Obsolete("Use IsDynamicPortListPort instead")] - public static bool IsInstancePortListPort(XNode.NodePort port) - { + public static bool IsInstancePortListPort(XNode.NodePort port) { return IsDynamicPortListPort(port); } [Obsolete("Use DynamicPortList instead")] - public static void InstancePortList(string fieldName, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, XNode.Node.TypeConstraint typeConstraint = XNode.Node.TypeConstraint.None, Action onCreation = null) - { + public static void InstancePortList(string fieldName, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, XNode.Node.TypeConstraint typeConstraint = XNode.Node.TypeConstraint.None, Action onCreation = null) { DynamicPortList(fieldName, type, serializedObject, io, connectionType, typeConstraint, onCreation); } #endregion /// Is this port part of a DynamicPortList? - public static bool IsDynamicPortListPort(XNode.NodePort port) - { + public static bool IsDynamicPortListPort(XNode.NodePort port) { string[] parts = port.fieldName.Split(' '); if (parts.Length != 2) return false; Dictionary cache; - if (reorderableListCache.TryGetValue(port.node, out cache)) - { + if (reorderableListCache.TryGetValue(port.node, out cache)) { ReorderableList list; if (cache.TryGetValue(parts[0], out list)) return true; } @@ -368,18 +320,14 @@ namespace XNodeEditor /// The serializedObject of the node /// Connection type of added dynamic ports /// Called on the list on creation. Use this if you want to customize the created ReorderableList - public static void DynamicPortList(string fieldName, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, XNode.Node.TypeConstraint typeConstraint = XNode.Node.TypeConstraint.None, Action onCreation = null) - { + public static void DynamicPortList(string fieldName, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, XNode.Node.TypeConstraint typeConstraint = XNode.Node.TypeConstraint.None, Action onCreation = null) { XNode.Node node = serializedObject.targetObject as XNode.Node; - var indexedPorts = node.DynamicPorts.Select(x => - { + var indexedPorts = node.DynamicPorts.Select(x => { string[] split = x.fieldName.Split(' '); - if (split != null && split.Length == 2 && split[0] == fieldName) - { + if (split != null && split.Length == 2 && split[0] == fieldName) { int i = -1; - if (int.TryParse(split[1], out i)) - { + if (int.TryParse(split[1], out i)) { return new { index = i, port = x }; } } @@ -391,13 +339,11 @@ namespace XNodeEditor ReorderableList list = null; Dictionary rlc; - if (reorderableListCache.TryGetValue(serializedObject.targetObject, out rlc)) - { + if (reorderableListCache.TryGetValue(serializedObject.targetObject, out rlc)) { if (!rlc.TryGetValue(fieldName, out list)) list = null; } // If a ReorderableList isn't cached for this array, do so. - if (list == null) - { + if (list == null) { SerializedProperty arrayData = serializedObject.FindProperty(fieldName); list = CreateReorderableList(fieldName, dynamicPorts, arrayData, type, serializedObject, io, connectionType, typeConstraint, onCreation); if (reorderableListCache.TryGetValue(serializedObject.targetObject, out rlc)) rlc.Add(fieldName, list); @@ -408,67 +354,53 @@ namespace XNodeEditor } - private static ReorderableList CreateReorderableList(string fieldName, List dynamicPorts, SerializedProperty arrayData, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType, XNode.Node.TypeConstraint typeConstraint, Action onCreation) - { + private static ReorderableList CreateReorderableList(string fieldName, List dynamicPorts, SerializedProperty arrayData, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType, XNode.Node.TypeConstraint typeConstraint, Action onCreation) { bool hasArrayData = arrayData != null && arrayData.isArray; XNode.Node node = serializedObject.targetObject as XNode.Node; ReorderableList list = new ReorderableList(dynamicPorts, null, true, true, true, true); string label = arrayData != null ? arrayData.displayName : ObjectNames.NicifyVariableName(fieldName); list.drawElementCallback = - (Rect rect, int index, bool isActive, bool isFocused) => - { + (Rect rect, int index, bool isActive, bool isFocused) => { XNode.NodePort port = node.GetPort(fieldName + " " + index); - if (hasArrayData && arrayData.propertyType != SerializedPropertyType.String) - { - if (arrayData.arraySize <= index) - { + if (hasArrayData && arrayData.propertyType != SerializedPropertyType.String) { + if (arrayData.arraySize <= index) { EditorGUI.LabelField(rect, "Array[" + index + "] data out of range"); return; } SerializedProperty itemData = arrayData.GetArrayElementAtIndex(index); EditorGUI.PropertyField(rect, itemData, true); - } - else EditorGUI.LabelField(rect, port != null ? port.fieldName : ""); - if (port != null) - { + } else EditorGUI.LabelField(rect, port != null ? port.fieldName : ""); + if (port != null) { Vector2 pos = rect.position + (port.IsOutput ? new Vector2(rect.width + 6, 0) : new Vector2(-36, 0)); NodeEditorGUILayout.PortField(pos, port); } }; list.elementHeightCallback = - (int index) => - { - if (hasArrayData) - { + (int index) => { + if (hasArrayData) { if (arrayData.arraySize <= index) return EditorGUIUtility.singleLineHeight; SerializedProperty itemData = arrayData.GetArrayElementAtIndex(index); return EditorGUI.GetPropertyHeight(itemData); - } - else return EditorGUIUtility.singleLineHeight; + } else return EditorGUIUtility.singleLineHeight; }; list.drawHeaderCallback = - (Rect rect) => - { + (Rect rect) => { EditorGUI.LabelField(rect, label); }; list.onSelectCallback = - (ReorderableList rl) => - { + (ReorderableList rl) => { reorderableListIndex = rl.index; }; list.onReorderCallback = - (ReorderableList rl) => - { + (ReorderableList rl) => { bool hasRect = false; bool hasNewRect = false; Rect rect = Rect.zero; Rect newRect = Rect.zero; // Move up - if (rl.index > reorderableListIndex) - { - for (int i = reorderableListIndex; i < rl.index; ++i) - { + if (rl.index > reorderableListIndex) { + for (int i = reorderableListIndex; i < rl.index; ++i) { XNode.NodePort port = node.GetPort(fieldName + " " + i); XNode.NodePort nextPort = node.GetPort(fieldName + " " + (i + 1)); port.SwapConnections(nextPort); @@ -481,10 +413,8 @@ namespace XNodeEditor } } // Move down - else - { - for (int i = reorderableListIndex; i > rl.index; --i) - { + else { + for (int i = reorderableListIndex; i > rl.index; --i) { XNode.NodePort port = node.GetPort(fieldName + " " + i); XNode.NodePort nextPort = node.GetPort(fieldName + " " + (i - 1)); port.SwapConnections(nextPort); @@ -501,8 +431,7 @@ namespace XNodeEditor serializedObject.Update(); // Move array data if there is any - if (hasArrayData) - { + if (hasArrayData) { arrayData.MoveArrayElement(reorderableListIndex, rl.index); } @@ -513,8 +442,7 @@ namespace XNodeEditor EditorApplication.delayCall += NodeEditorWindow.current.Repaint; }; list.onAddCallback = - (ReorderableList rl) => - { + (ReorderableList rl) => { // Add dynamic port postfixed with an index number string newName = fieldName + " 0"; int i = 0; @@ -524,24 +452,19 @@ namespace XNodeEditor else node.AddDynamicInput(type, connectionType, typeConstraint, newName); serializedObject.Update(); EditorUtility.SetDirty(node); - if (hasArrayData) - { + if (hasArrayData) { arrayData.InsertArrayElementAtIndex(arrayData.arraySize); } serializedObject.ApplyModifiedProperties(); }; list.onRemoveCallback = - (ReorderableList rl) => - { + (ReorderableList rl) => { - var indexedPorts = node.DynamicPorts.Select(x => - { + var indexedPorts = node.DynamicPorts.Select(x => { string[] split = x.fieldName.Split(' '); - if (split != null && split.Length == 2 && split[0] == fieldName) - { + if (split != null && split.Length == 2 && split[0] == fieldName) { int i = -1; - if (int.TryParse(split[1], out i)) - { + if (int.TryParse(split[1], out i)) { return new { index = i, port = x }; } } @@ -551,24 +474,17 @@ namespace XNodeEditor int index = rl.index; - if (dynamicPorts[index] == null) - { + if (dynamicPorts[index] == null) { Debug.LogWarning("No port found at index " + index + " - Skipped"); - } - else if (dynamicPorts.Count <= index) - { + } else if (dynamicPorts.Count <= index) { Debug.LogWarning("DynamicPorts[" + index + "] out of range. Length was " + dynamicPorts.Count + " - Skipped"); - } - else - { + } else { // Clear the removed ports connections dynamicPorts[index].ClearConnections(); // Move following connections one step up to replace the missing connection - for (int k = index + 1; k < dynamicPorts.Count(); k++) - { - for (int j = 0; j < dynamicPorts[k].ConnectionCount; j++) - { + for (int k = index + 1; k < dynamicPorts.Count(); k++) { + for (int j = 0; j < dynamicPorts[k].ConnectionCount; j++) { XNode.NodePort other = dynamicPorts[k].GetConnection(j); dynamicPorts[k].Disconnect(other); dynamicPorts[k - 1].Connect(other); @@ -580,20 +496,16 @@ namespace XNodeEditor EditorUtility.SetDirty(node); } - if (hasArrayData && arrayData.propertyType != SerializedPropertyType.String) - { - if (arrayData.arraySize <= index) - { + if (hasArrayData && arrayData.propertyType != SerializedPropertyType.String) { + if (arrayData.arraySize <= index) { Debug.LogWarning("Attempted to remove array index " + index + " where only " + arrayData.arraySize + " exist - Skipped"); Debug.Log(rl.list[0]); return; } arrayData.DeleteArrayElementAtIndex(index); // Error handling. If the following happens too often, file a bug report at https://github.com/Siccity/xNode/issues - if (dynamicPorts.Count <= arrayData.arraySize) - { - while (dynamicPorts.Count <= arrayData.arraySize) - { + if (dynamicPorts.Count <= arrayData.arraySize) { + while (dynamicPorts.Count <= arrayData.arraySize) { arrayData.DeleteArrayElementAtIndex(arrayData.arraySize - 1); } UnityEngine.Debug.LogWarning("Array size exceeded dynamic ports size. Excess items removed."); @@ -603,11 +515,9 @@ namespace XNodeEditor } }; - if (hasArrayData) - { + if (hasArrayData) { int dynamicPortCount = dynamicPorts.Count; - while (dynamicPortCount < arrayData.arraySize) - { + while (dynamicPortCount < arrayData.arraySize) { // Add dynamic port postfixed with an index number string newName = arrayData.name + " 0"; int i = 0; @@ -617,8 +527,7 @@ namespace XNodeEditor EditorUtility.SetDirty(node); dynamicPortCount++; } - while (arrayData.arraySize < dynamicPortCount) - { + while (arrayData.arraySize < dynamicPortCount) { arrayData.InsertArrayElementAtIndex(arrayData.arraySize); } serializedObject.ApplyModifiedProperties(); diff --git a/Scripts/Editor/NodeEditorPreferences.cs b/Scripts/Editor/NodeEditorPreferences.cs index 715ac6a..5113904 100644 --- a/Scripts/Editor/NodeEditorPreferences.cs +++ b/Scripts/Editor/NodeEditorPreferences.cs @@ -104,7 +104,7 @@ namespace XNodeEditor { public static SettingsProvider CreateXNodeSettingsProvider() { SettingsProvider provider = new SettingsProvider("Preferences/Node Editor", SettingsScope.User) { guiHandler = (searchContext) => { XNodeEditor.NodeEditorPreferences.PreferencesGUI(); }, - keywords = new HashSet(new [] { "xNode", "node", "editor", "graph", "connections", "noodles", "ports" }) + keywords = new HashSet(new [] { "xNode", "node", "editor", "graph", "connections", "noodles", "ports" }) }; return provider; } @@ -166,9 +166,8 @@ namespace XNodeEditor { settings.noodleThickness = EditorGUILayout.FloatField(new GUIContent("Noodle thickness", "Noodle Thickness of the node connections"), settings.noodleThickness); settings.noodleStroke = (NoodleStroke) EditorGUILayout.EnumPopup("Noodle stroke", (Enum) settings.noodleStroke); settings.portTooltips = EditorGUILayout.Toggle("Port Tooltips", settings.portTooltips); - settings.dragToCreate = EditorGUILayout.Toggle(new GUIContent("Drag to Create", "Drag a port connection anywhere on the grid to create and connect a node"), settings.dragToCreate); + settings.dragToCreate = EditorGUILayout.Toggle(new GUIContent("Drag to Create", "Drag a port connection anywhere on the grid to create and connect a node"), settings.dragToCreate); settings.createFilter = EditorGUILayout.Toggle(new GUIContent("Create Filter", "Only show nodes that are compatible with the selected port"), settings.createFilter); - //END if (GUI.changed) { diff --git a/Scripts/Editor/NodeEditorUtilities.cs b/Scripts/Editor/NodeEditorUtilities.cs index 900e2e2..753973b 100644 --- a/Scripts/Editor/NodeEditorUtilities.cs +++ b/Scripts/Editor/NodeEditorUtilities.cs @@ -134,21 +134,17 @@ namespace XNodeEditor { /// Type to find compatiblities /// /// True if NodeType has some port with value type compatible - public static bool HasCompatiblePortType(Type nodeType, Type compatibleType, XNode.NodePort.IO direction = XNode.NodePort.IO.Input) - { + public static bool HasCompatiblePortType(Type nodeType, Type compatibleType, XNode.NodePort.IO direction = XNode.NodePort.IO.Input) { Type findType = typeof(XNode.Node.InputAttribute); if (direction == XNode.NodePort.IO.Output) findType = typeof(XNode.Node.OutputAttribute); //Get All fields from node type and we go filter only field with portAttribute. //This way is possible to know the values of the all ports and if have some with compatible value tue - foreach (FieldInfo f in XNode.NodeDataCache.GetNodeFields(nodeType)) - { + foreach (FieldInfo f in XNode.NodeDataCache.GetNodeFields(nodeType)) { var portAttribute = f.GetCustomAttributes(findType, false).FirstOrDefault(); - if (portAttribute != null) - { - if (IsCastableTo(f.FieldType, compatibleType)) - { + if (portAttribute != null) { + if (IsCastableTo(f.FieldType, compatibleType)) { return true; } } @@ -163,8 +159,7 @@ namespace XNodeEditor { /// List with all nodes type to filter /// Compatible Type to Filter /// Return Only Node Types with ports compatible, or an empty list - public static List GetCompatibleNodesTypes(Type[] nodeTypes, Type compatibleType, XNode.NodePort.IO direction = XNode.NodePort.IO.Input) - { + public static List GetCompatibleNodesTypes(Type[] nodeTypes, Type compatibleType, XNode.NodePort.IO direction = XNode.NodePort.IO.Input) { //Result List List filteredTypes = new List(); @@ -173,10 +168,8 @@ namespace XNodeEditor { if (compatibleType == null) { return filteredTypes; } //Find compatiblity - foreach (Type findType in nodeTypes) - { - if (HasCompatiblePortType(findType, compatibleType, direction)) - { + foreach (Type findType in nodeTypes) { + if (HasCompatiblePortType(findType, compatibleType, direction)) { filteredTypes.Add(findType); } } diff --git a/Scripts/Editor/NodeGraphEditor.cs b/Scripts/Editor/NodeGraphEditor.cs index 580e3a8..9b80df0 100644 --- a/Scripts/Editor/NodeGraphEditor.cs +++ b/Scripts/Editor/NodeGraphEditor.cs @@ -4,12 +4,10 @@ using System.Linq; using UnityEditor; using UnityEngine; -namespace XNodeEditor -{ +namespace XNodeEditor { /// Base class to derive custom Node Graph editors from. Use this to override how graphs are drawn in the editor. [CustomNodeGraphEditor(typeof(XNode.NodeGraph))] - public class NodeGraphEditor : XNodeEditor.Internal.NodeEditorBase - { + public class NodeGraphEditor : XNodeEditor.Internal.NodeEditorBase { [Obsolete("Use window.position instead")] public Rect position { get { return window.position; } set { window.position = value; } } /// Are we currently renaming a node? @@ -26,25 +24,21 @@ namespace XNodeEditor /// Called when NodeEditorWindow loses focus public virtual void OnWindowFocusLost() { } - public virtual Texture2D GetGridTexture() - { + public virtual Texture2D GetGridTexture() { return NodeEditorPreferences.GetSettings().gridTexture; } - public virtual Texture2D GetSecondaryGridTexture() - { + public virtual Texture2D GetSecondaryGridTexture() { return NodeEditorPreferences.GetSettings().crossTexture; } /// Return default settings for this graph type. This is the settings the user will load if no previous settings have been saved. - public virtual NodeEditorPreferences.Settings GetDefaultPreferences() - { + public virtual NodeEditorPreferences.Settings GetDefaultPreferences() { return new NodeEditorPreferences.Settings(); } /// Returns context node menu path. Null or empty strings for hidden nodes. - public virtual string GetNodeMenuName(Type type) - { + public virtual string GetNodeMenuName(Type type) { //Check if type has the CreateNodeMenuAttribute XNode.Node.CreateNodeMenuAttribute attrib; if (NodeEditorUtilities.GetAttrib(type, out attrib)) // Return custom path @@ -54,8 +48,7 @@ namespace XNodeEditor } /// The order by which the menu items are displayed. - public virtual int GetNodeMenuOrder(Type type) - { + public virtual int GetNodeMenuOrder(Type type) { //Check if type has the CreateNodeMenuAttribute XNode.Node.CreateNodeMenuAttribute attrib; if (NodeEditorUtilities.GetAttrib(type, out attrib)) // Return custom path @@ -65,25 +58,22 @@ namespace XNodeEditor } /// - /// Add items for the context menu when right-clicking this node. + /// Add items for the context menu when right-clicking this node. /// Override to add custom menu items. /// /// /// Use it to filter only nodes with ports value type, compatible with this type /// Direction of the compatiblity - public virtual void AddContextMenuItems(GenericMenu menu, Type compatibleType = null, XNode.NodePort.IO direction = XNode.NodePort.IO.Input) - { + public virtual void AddContextMenuItems(GenericMenu menu, Type compatibleType = null, XNode.NodePort.IO direction = XNode.NodePort.IO.Input) { Vector2 pos = NodeEditorWindow.current.WindowToGridPosition(Event.current.mousePosition); Type[] nodeTypes = NodeEditorReflection.nodeTypes.OrderBy(type => GetNodeMenuOrder(type)).ToArray(); - if (compatibleType != null && NodeEditorPreferences.GetSettings().createFilter) - { + if (compatibleType != null && NodeEditorPreferences.GetSettings().createFilter) { nodeTypes = NodeEditorUtilities.GetCompatibleNodesTypes(NodeEditorReflection.nodeTypes, compatibleType, direction).ToArray(); } - for (int i = 0; i < nodeTypes.Length; i++) - { + for (int i = 0; i < nodeTypes.Length; i++) { Type type = nodeTypes[i]; @@ -94,16 +84,14 @@ namespace XNodeEditor // Check if user is allowed to add more of given node type XNode.Node.DisallowMultipleNodesAttribute disallowAttrib; bool disallowed = false; - if (NodeEditorUtilities.GetAttrib(type, out disallowAttrib)) - { + if (NodeEditorUtilities.GetAttrib(type, out disallowAttrib)) { int typeCount = target.nodes.Count(x => x.GetType() == type); if (typeCount >= disallowAttrib.max) disallowed = true; } // Add node entry to context menu if (disallowed) menu.AddItem(new GUIContent(path), false, null); - else menu.AddItem(new GUIContent(path), false, () => - { + else menu.AddItem(new GUIContent(path), false, () => { XNode.Node node = CreateNode(type, pos); NodeEditorWindow.current.AutoConnect(node); }); @@ -115,17 +103,14 @@ namespace XNodeEditor menu.AddCustomContextMenuItems(target); } - /// Returned gradient is used to color noodles /// The output this noodle comes from. Never null. /// The output this noodle comes from. Can be null if we are dragging the noodle. - public virtual Gradient GetNoodleGradient(XNode.NodePort output, XNode.NodePort input) - { + public virtual Gradient GetNoodleGradient(XNode.NodePort output, XNode.NodePort input) { Gradient grad = new Gradient(); // If dragging the noodle, draw solid, slightly transparent - if (input == null) - { + if (input == null) { Color a = GetTypeColor(output.ValueType); grad.SetKeys( new GradientColorKey[] { new GradientColorKey(a, 0f) }, @@ -133,13 +118,11 @@ namespace XNodeEditor ); } // If normal, draw gradient fading from one input color to the other - else - { + else { Color a = GetTypeColor(output.ValueType); Color b = GetTypeColor(input.ValueType); // If any port is hovered, tint white - if (window.hoveredPort == output || window.hoveredPort == input) - { + if (window.hoveredPort == output || window.hoveredPort == input) { a = Color.Lerp(a, Color.white, 0.8f); b = Color.Lerp(b, Color.white, 0.8f); } @@ -154,24 +137,20 @@ namespace XNodeEditor /// Returned float is used for noodle thickness /// The output this noodle comes from. Never null. /// The output this noodle comes from. Can be null if we are dragging the noodle. - public virtual float GetNoodleThickness(XNode.NodePort output, XNode.NodePort input) - { + public virtual float GetNoodleThickness(XNode.NodePort output, XNode.NodePort input) { return NodeEditorPreferences.GetSettings().noodleThickness; } - public virtual NoodlePath GetNoodlePath(XNode.NodePort output, XNode.NodePort input) - { + public virtual NoodlePath GetNoodlePath(XNode.NodePort output, XNode.NodePort input) { return NodeEditorPreferences.GetSettings().noodlePath; } - public virtual NoodleStroke GetNoodleStroke(XNode.NodePort output, XNode.NodePort input) - { + public virtual NoodleStroke GetNoodleStroke(XNode.NodePort output, XNode.NodePort input) { return NodeEditorPreferences.GetSettings().noodleStroke; } /// Returned color is used to color ports - public virtual Color GetPortColor(XNode.NodePort port) - { + public virtual Color GetPortColor(XNode.NodePort port) { return GetTypeColor(port.ValueType); } @@ -185,8 +164,7 @@ namespace XNodeEditor /// /// the owner of the style /// - public virtual GUIStyle GetPortStyle(XNode.NodePort port) - { + public virtual GUIStyle GetPortStyle(XNode.NodePort port) { if (port.direction == XNode.NodePort.IO.Input) return NodeEditorResources.styles.inputPort; @@ -195,25 +173,21 @@ namespace XNodeEditor /// The returned color is used to color the background of the door. /// Usually used for outer edge effect - public virtual Color GetPortBackgroundColor(XNode.NodePort port) - { + public virtual Color GetPortBackgroundColor(XNode.NodePort port) { return Color.gray; } /// Returns generated color for a type. This color is editable in preferences - public virtual Color GetTypeColor(Type type) - { + public virtual Color GetTypeColor(Type type) { return NodeEditorPreferences.GetTypeColor(type); } /// Override to display custom tooltips - public virtual string GetPortTooltip(XNode.NodePort port) - { + public virtual string GetPortTooltip(XNode.NodePort port) { Type portType = port.ValueType; string tooltip = ""; tooltip = portType.PrettyName(); - if (port.IsOutput) - { + if (port.IsOutput) { object obj = port.node.GetValue(port); tooltip += " = " + (obj != null ? obj.ToString() : "null"); } @@ -221,14 +195,12 @@ namespace XNodeEditor } /// Deal with objects dropped into the graph through DragAndDrop - public virtual void OnDropObjects(UnityEngine.Object[] objects) - { + public virtual void OnDropObjects(UnityEngine.Object[] objects) { if (GetType() != typeof(NodeGraphEditor)) Debug.Log("No OnDropObjects override defined for " + GetType()); } /// Create a node and save it in the graph asset - public virtual XNode.Node CreateNode(Type type, Vector2 position) - { + public virtual XNode.Node CreateNode(Type type, Vector2 position) { Undo.RecordObject(target, "Create Node"); XNode.Node node = target.AddNode(type); Undo.RegisterCreatedObjectUndo(node, "Create Node"); @@ -241,8 +213,7 @@ namespace XNodeEditor } /// Creates a copy of the original node in the graph - public virtual XNode.Node CopyNode(XNode.Node original) - { + public virtual XNode.Node CopyNode(XNode.Node original) { Undo.RecordObject(target, "Duplicate Node"); XNode.Node node = target.CopyNode(original); Undo.RegisterCreatedObjectUndo(node, "Duplicate Node"); @@ -253,16 +224,13 @@ namespace XNodeEditor } /// Return false for nodes that can't be removed - public virtual bool CanRemove(XNode.Node node) - { + public virtual bool CanRemove(XNode.Node node) { // Check graph attributes to see if this node is required Type graphType = target.GetType(); XNode.NodeGraph.RequireNodeAttribute[] attribs = Array.ConvertAll( graphType.GetCustomAttributes(typeof(XNode.NodeGraph.RequireNodeAttribute), true), x => x as XNode.NodeGraph.RequireNodeAttribute); - if (attribs.Any(x => x.Requires(node.GetType()))) - { - if (target.nodes.Count(x => x.GetType() == node.GetType()) <= 1) - { + if (attribs.Any(x => x.Requires(node.GetType()))) { + if (target.nodes.Count(x => x.GetType() == node.GetType()) <= 1) { return false; } } @@ -270,8 +238,7 @@ namespace XNodeEditor } /// Safely remove a node and all its connections. - public virtual void RemoveNode(XNode.Node node) - { + public virtual void RemoveNode(XNode.Node node) { if (!CanRemove(node)) return; // Remove the node @@ -287,21 +254,18 @@ namespace XNodeEditor [AttributeUsage(AttributeTargets.Class)] public class CustomNodeGraphEditorAttribute : Attribute, - XNodeEditor.Internal.NodeEditorBase.INodeEditorAttrib - { + XNodeEditor.Internal.NodeEditorBase.INodeEditorAttrib { private Type inspectedType; public string editorPrefsKey; /// Tells a NodeGraphEditor which Graph type it is an editor for /// Type that this editor can edit /// Define unique key for unique layout settings instance - public CustomNodeGraphEditorAttribute(Type inspectedType, string editorPrefsKey = "xNode.Settings") - { + public CustomNodeGraphEditorAttribute(Type inspectedType, string editorPrefsKey = "xNode.Settings") { this.inspectedType = inspectedType; this.editorPrefsKey = editorPrefsKey; } - public Type GetInspectedType() - { + public Type GetInspectedType() { return inspectedType; } }