From 69ee12169ddb9db88cba52e5f88c9476628844eb Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Sat, 14 Apr 2018 22:49:16 +0200 Subject: [PATCH 01/25] Destroy nodes on graph destruction #30 --- Scripts/NodeGraph.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Scripts/NodeGraph.cs b/Scripts/NodeGraph.cs index 32310d2..e9fe75f 100644 --- a/Scripts/NodeGraph.cs +++ b/Scripts/NodeGraph.cs @@ -38,10 +38,16 @@ namespace XNode { public void RemoveNode(Node node) { node.ClearConnections(); nodes.Remove(node); + if (Application.isPlaying) Destroy(node); } /// Remove all nodes and connections from the graph public void Clear() { + if (Application.isPlaying) { + for (int i = 0; i < nodes.Count; i++) { + Destroy(nodes[i]); + } + } nodes.Clear(); } @@ -67,5 +73,10 @@ namespace XNode { return graph; } + + private void OnDestroy() { + // Remove all nodes prior to graph destruction + Clear(); + } } } \ No newline at end of file From 75795c59b061bb55fe3b5eb2f2f19be4d82573bb Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Wed, 18 Apr 2018 12:57:12 +0200 Subject: [PATCH 02/25] Added F2 to rename hotkey (return on mac) --- Scripts/Editor/NodeEditorAction.cs | 13 +++++++++++++ Scripts/Editor/NodeEditorGUI.cs | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs index 651824a..1258983 100644 --- a/Scripts/Editor/NodeEditorAction.cs +++ b/Scripts/Editor/NodeEditorAction.cs @@ -255,6 +255,11 @@ namespace XNodeEditor { 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(); @@ -318,6 +323,14 @@ namespace XNodeEditor { } } + /// Initiate a rename on the currently selected node + public void RenameSelectedNode() { + if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) { + XNode.Node node = Selection.activeObject as XNode.Node; + NodeEditor.GetEditor(node).InitiateRename(); + } + } + /// Draw this node on top of other nodes by placing it last in the graph.nodes list public void MoveNodeToTop(XNode.Node node) { int index; diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index 34cd210..51baf55 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -112,7 +112,7 @@ namespace XNodeEditor { if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) { XNode.Node node = Selection.activeObject as XNode.Node; contextMenu.AddItem(new GUIContent("Move To Top"), false, () => MoveNodeToTop(node)); - contextMenu.AddItem(new GUIContent("Rename"), false, NodeEditor.GetEditor(node).InitiateRename); + contextMenu.AddItem(new GUIContent("Rename"), false, RenameSelectedNode); } contextMenu.AddItem(new GUIContent("Duplicate"), false, DublicateSelectedNodes); From 97ec4bbf42000f8a5517c8f92486c5b7f5404bd8 Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Sat, 12 May 2018 14:40:23 +0200 Subject: [PATCH 03/25] Improved warning message --- Scripts/NodePort.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/NodePort.cs b/Scripts/NodePort.cs index 65ad4be..0ada72d 100644 --- a/Scripts/NodePort.cs +++ b/Scripts/NodePort.cs @@ -190,7 +190,7 @@ namespace XNode { public void Connect(NodePort port) { if (connections == null) connections = new List(); if (port == null) { Debug.LogWarning("Cannot connect to null port"); return; } - if (port == this) { Debug.LogWarning("Attempting to connect port to self."); return; } + if (port == this) { Debug.LogWarning("Cannot connect port to self."); return; } if (IsConnectedTo(port)) { Debug.LogWarning("Port already connected. "); return; } if (direction == port.direction) { Debug.LogWarning("Cannot connect two " + (direction == IO.Input ? "input" : "output") + " connections"); return; } if (port.connectionType == Node.ConnectionType.Override && port.ConnectionCount != 0) { port.ClearConnections(); } From 61ca00ce317eb3156cdc264d4ed9c7cb89c176a6 Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Sun, 13 May 2018 12:18:16 +0200 Subject: [PATCH 04/25] Renamed GetNodePath to GetNodeMenuName (consistency) Empty menuNames now skips, just like null does --- Scripts/Editor/NodeEditorGUI.cs | 4 ++-- Scripts/Editor/NodeGraphEditor.cs | 6 ++++++ Scripts/Node.cs | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index 51baf55..a1e8fd3 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -135,8 +135,8 @@ namespace XNodeEditor { Type type = nodeTypes[i]; //Get node context menu path - string path = graphEditor.GetNodePath(type); - if (path == null) continue; + string path = graphEditor.GetNodeMenuName(type); + if (string.IsNullOrEmpty(path)) continue; contextMenu.AddItem(new GUIContent(path), false, () => { CreateNode(type, pos); diff --git a/Scripts/Editor/NodeGraphEditor.cs b/Scripts/Editor/NodeGraphEditor.cs index 8d81a07..3f0141a 100644 --- a/Scripts/Editor/NodeGraphEditor.cs +++ b/Scripts/Editor/NodeGraphEditor.cs @@ -29,7 +29,13 @@ namespace XNodeEditor { } /// Returns context menu path. Returns null if node is not available. + [Obsolete("Use GetNodeMenuName instead")] public virtual string GetNodePath(Type type) { + return GetNodeMenuName(type); + } + + /// Returns context node menu path. Null or empty strings for hidden nodes. + 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 diff --git a/Scripts/Node.cs b/Scripts/Node.cs index be3d5a7..ad2889f 100644 --- a/Scripts/Node.cs +++ b/Scripts/Node.cs @@ -240,7 +240,7 @@ namespace XNode { public class CreateNodeMenuAttribute : Attribute { public string menuName; /// Manually supply node class with a context menu path - /// Path to this node in the context menu + /// Path to this node in the context menu. Null or empty hides it. public CreateNodeMenuAttribute(string menuName) { this.menuName = menuName; } From 7a1726b3428f3846a2d972e2028a204b45622ce3 Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Sun, 13 May 2018 13:29:12 +0200 Subject: [PATCH 05/25] Fixed commenting --- Scripts/Node.cs | 4 ++-- Scripts/NodeGraph.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Scripts/Node.cs b/Scripts/Node.cs index ad2889f..7e9a4ac 100644 --- a/Scripts/Node.cs +++ b/Scripts/Node.cs @@ -181,7 +181,7 @@ namespace XNode { else return fallback; } - /// Returns a value based on requested port output. Should be overridden before used. + /// Returns a value based on requested port output. Should be overridden in all derived nodes with outputs. /// The requested port. public virtual object GetValue(NodePort port) { Debug.LogWarning("No GetValue(NodePort port) override defined for " + GetType()); @@ -194,7 +194,7 @@ namespace XNode { public virtual void OnCreateConnection(NodePort from, NodePort to) { } /// Called after a connection is removed from this port - /// Output Input + /// Output or Input public virtual void OnRemoveConnection(NodePort port) { } /// Disconnect everything from this node diff --git a/Scripts/NodeGraph.cs b/Scripts/NodeGraph.cs index e9fe75f..d6d766c 100644 --- a/Scripts/NodeGraph.cs +++ b/Scripts/NodeGraph.cs @@ -34,7 +34,7 @@ namespace XNode { } /// Safely remove a node and all its connections - /// + /// The node to remove public void RemoveNode(Node node) { node.ClearConnections(); nodes.Remove(node); From 8f658d276230d2a4c3ab25bd71d536be63e44302 Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Mon, 14 May 2018 09:26:31 +0200 Subject: [PATCH 06/25] Fixed error on graph open Error introduced in commit 2582d5aaf3cac7c769ee21cde7de449bee353e6f Caused by trying to get settings in OnFocus, before the graph is ready --- Scripts/Editor/NodeEditorWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/Editor/NodeEditorWindow.cs b/Scripts/Editor/NodeEditorWindow.cs index db16033..a5cbf3f 100644 --- a/Scripts/Editor/NodeEditorWindow.cs +++ b/Scripts/Editor/NodeEditorWindow.cs @@ -22,7 +22,7 @@ namespace XNodeEditor { void OnFocus() { current = this; graphEditor = NodeGraphEditor.GetEditor(graph); - if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); + if (graphEditor != null && NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); } partial void OnEnable(); From f04629a120bcda8a0fcb592b152375a48e878359 Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Tue, 22 May 2018 16:25:21 +0200 Subject: [PATCH 07/25] Added experimental node culling for performance boost --- Scripts/Editor/NodeEditorAction.cs | 2 +- Scripts/Editor/NodeEditorGUI.cs | 42 +++++++++++++++++++++++++----- Scripts/Editor/NodeEditorWindow.cs | 4 +-- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs index 1258983..511f5d3 100644 --- a/Scripts/Editor/NodeEditorAction.cs +++ b/Scripts/Editor/NodeEditorAction.cs @@ -420,7 +420,7 @@ namespace XNodeEditor { //Get node position Vector2 nodePos = GridToWindowPosition(node.position); float width = 200; - if (nodeWidths.ContainsKey(node)) width = nodeWidths[node]; + if (nodeSizes.ContainsKey(node)) width = nodeSizes[node].x; Rect windowRect = new Rect(nodePos, new Vector2(width / zoom, 30 / zoom)); return windowRect.Contains(mousePos); } diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index a1e8fd3..c83f544 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -8,6 +8,7 @@ namespace XNodeEditor { public partial class NodeEditorWindow { public NodeGraphEditor graphEditor; private List selectionCache; + private List culledNodes; private void OnGUI() { Event e = Event.current; @@ -280,10 +281,6 @@ namespace XNodeEditor { if (e.type == EventType.Layout) { selectionCache = new List(Selection.objects); } - if (e.type == EventType.Repaint) { - portConnectionPoints.Clear(); - nodeWidths.Clear(); - } //Active node is hashed before and after node GUI to detect changes int nodeHash = 0; @@ -313,6 +310,8 @@ namespace XNodeEditor { //Save guiColor so we can revert it Color guiColor = GUI.color; + + if (e.type == EventType.Layout) culledNodes = new List(); for (int n = 0; n < graph.nodes.Count; n++) { // Skip null nodes. The user could be in the process of renaming scripts, so removing them at this point is not advisable. if (graph.nodes[n] == null) continue; @@ -320,6 +319,17 @@ namespace XNodeEditor { XNode.Node node = graph.nodes[n]; NodeEditor nodeEditor = NodeEditor.GetEditor(node); + + // Culling + if (e.type == EventType.Layout) { + // Cull unselected nodes outside view + if (!Selection.Contains(node) && ShouldBeCulled(nodeEditor)) { + culledNodes.Add(node); + continue; + } + } else if (culledNodes.Contains(node)) continue; + + Debug.Log("Draw " + n); NodeEditor.portPositions = new Dictionary(); //Get node position @@ -358,18 +368,23 @@ namespace XNodeEditor { if (NodeEditor.onUpdateNode != null) NodeEditor.onUpdateNode(node); } + GUILayout.EndVertical(); + + //Cache data about the node for next frame if (e.type == EventType.Repaint) { - nodeWidths.Add(node, nodeEditor.GetWidth()); + Vector2 size = GUILayoutUtility.GetLastRect().size; + if (nodeSizes.ContainsKey(node)) nodeSizes[node] = size; + else nodeSizes.Add(node, size); foreach (var kvp in NodeEditor.portPositions) { Vector2 portHandlePos = kvp.Value; portHandlePos += node.position; Rect rect = new Rect(portHandlePos.x - 8, portHandlePos.y - 8, 16, 16); - portConnectionPoints.Add(kvp.Key, rect); + if (portConnectionPoints.ContainsKey(kvp.Key)) portConnectionPoints[kvp.Key] = rect; + else portConnectionPoints.Add(kvp.Key, rect); } } - GUILayout.EndVertical(); if (selected) GUILayout.EndVertical(); if (e.type != EventType.Layout) { @@ -414,6 +429,19 @@ namespace XNodeEditor { } } + /// Returns true if outside window area + private bool ShouldBeCulled(XNodeEditor.NodeEditor nodeEditor) { + Vector2 nodePos = GridToWindowPositionNoClipped(nodeEditor.target.position); + if (nodePos.x / _zoom > position.width) return true; // Right + else if (nodePos.y / _zoom > position.height) return true; // Bottom + else if (nodeSizes.ContainsKey(nodeEditor.target)) { + Vector2 size = nodeSizes[nodeEditor.target]; + if (nodePos.x + size.x < 0) return true; // Left + else if (nodePos.y + size.y < 0) return true; // Top + } + return false; + } + private void DrawTooltip() { if (hoveredPort != null) { Type type = hoveredPort.ValueType; diff --git a/Scripts/Editor/NodeEditorWindow.cs b/Scripts/Editor/NodeEditorWindow.cs index a5cbf3f..7fdc49d 100644 --- a/Scripts/Editor/NodeEditorWindow.cs +++ b/Scripts/Editor/NodeEditorWindow.cs @@ -11,8 +11,8 @@ namespace XNodeEditor { /// Stores node positions for all nodePorts. public Dictionary portConnectionPoints { get { return _portConnectionPoints; } } private Dictionary _portConnectionPoints = new Dictionary(); - public Dictionary nodeWidths { get { return _nodeWidths; } } - private Dictionary _nodeWidths = new Dictionary(); + public Dictionary nodeSizes { get { return _nodeSizes; } } + private Dictionary _nodeSizes = new Dictionary(); public XNode.NodeGraph graph; public Vector2 panOffset { get { return _panOffset; } set { _panOffset = value; Repaint(); } } private Vector2 _panOffset; From 3f405e318a59298666da82ce9b84d10c5961520d Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Wed, 23 May 2018 10:58:36 +0200 Subject: [PATCH 08/25] Remove console spam --- Scripts/Editor/NodeEditorGUI.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index c83f544..ee339b9 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -329,7 +329,6 @@ namespace XNodeEditor { } } else if (culledNodes.Contains(node)) continue; - Debug.Log("Draw " + n); NodeEditor.portPositions = new Dictionary(); //Get node position From e92a001a7c10229d237cbeace01301fe8a64101d Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Tue, 5 Jun 2018 13:34:24 +0200 Subject: [PATCH 09/25] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e0544a7..3c9f670 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ [Downloads](https://github.com/Siccity/xNode/releases) / [Asset Store](http://u3d.as/108S) / [Documentation](https://github.com/Siccity/xNode/wiki) +[Support Me on Ko-fi](https://ko-fi.com/Z8Z5DYWA) + ### xNode Thinking of developing a node-based plugin? Then this is for you. You can download it as an archive and unpack to a new unity project, or connect it as git submodule. From dc9b11c5a3707df528da39a0fa6512f7271fb052 Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Sun, 10 Jun 2018 21:16:18 +0200 Subject: [PATCH 10/25] Added NodeEditorGUILayout.InstancePortList. Use it to draw lists of instance ports easily. --- Scripts/Editor/NodeEditorGUILayout.cs | 70 ++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/Scripts/Editor/NodeEditorGUILayout.cs b/Scripts/Editor/NodeEditorGUILayout.cs index 8a629e8..d7a4871 100644 --- a/Scripts/Editor/NodeEditorGUILayout.cs +++ b/Scripts/Editor/NodeEditorGUILayout.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine; @@ -132,9 +134,75 @@ namespace XNodeEditor { Color col = GUI.color; GUI.color = backgroundColor; GUI.DrawTexture(rect, NodeEditorResources.dotOuter); - GUI.color = typeColor; + GUI.color = typeColor; GUI.DrawTexture(rect, NodeEditorResources.dot); GUI.color = col; } + + /// Draw an editable list of instance ports. Port names are named as "[fieldName] [index]" + /// Supply a list for editable values + /// Value type of added instance ports + /// The serializedObject of the node + /// Connection type of added instance ports + public static void InstancePortList(string fieldName, Type type, SerializedObject serializedObject, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple) { + XNode.Node node = serializedObject.targetObject as XNode.Node; + SerializedProperty arrayData = serializedObject.FindProperty(fieldName); + bool hasArrayData = arrayData != null && arrayData.isArray; + int arraySize = hasArrayData ? arrayData.arraySize : 0; + + List instancePorts = node.InstancePorts.Where(x => x.fieldName.StartsWith(fieldName)).OrderBy(x => x.fieldName).ToList(); + + for (int i = 0; i < instancePorts.Count(); i++) { + GUILayout.BeginHorizontal(); + if (GUILayout.Button("-", GUILayout.Width(30))) { + // Clear the removed ports connections + instancePorts[i].ClearConnections(); + // Move following connections one step up to replace the missing connection + for (int k = i + 1; k < instancePorts.Count(); k++) { + for (int j = 0; j < instancePorts[k].ConnectionCount; j++) { + XNode.NodePort other = instancePorts[k].GetConnection(j); + instancePorts[k].Disconnect(other); + instancePorts[k - 1].Connect(other); + } + } + // Remove the last instance port, to avoid messing up the indexing + node.RemoveInstancePort(instancePorts[instancePorts.Count() - 1].fieldName); + serializedObject.Update(); + EditorUtility.SetDirty(node); + if (hasArrayData) { + arrayData.DeleteArrayElementAtIndex(i); + arraySize--; + } + i--; + } else { + if (hasArrayData) { + if (i < arraySize) { + SerializedProperty itemData = arrayData.GetArrayElementAtIndex(i); + if (itemData != null) EditorGUILayout.PropertyField(itemData, new GUIContent(ObjectNames.NicifyVariableName(fieldName) + " " + i)); + else EditorGUILayout.LabelField("[Missing array data]"); + } else EditorGUILayout.LabelField("[Out of bounds]"); + + } else { + EditorGUILayout.LabelField(instancePorts[i].fieldName); + } + NodeEditorGUILayout.PortField(new GUIContent(), node.GetPort(instancePorts[i].fieldName), GUILayout.Width(-4)); + } + GUILayout.EndHorizontal(); + } + GUILayout.BeginHorizontal(); + EditorGUILayout.Space(); + if (GUILayout.Button("+", GUILayout.Width(30))) { + + string newName = fieldName + " 0"; + int i = 0; + while (node.HasPort(newName)) newName = fieldName + " " + (++i); + + instancePorts.Add(node.AddInstanceOutput(type, connectionType, newName)); + serializedObject.Update(); + EditorUtility.SetDirty(node); + if (hasArrayData) arrayData.InsertArrayElementAtIndex(arraySize); + } + GUILayout.EndHorizontal(); + } } } \ No newline at end of file From 704730e59d2eb10bb55e36987a2214c57b9672fc Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Sun, 10 Jun 2018 21:17:17 +0200 Subject: [PATCH 11/25] Minor corrections Instance ports now show value for tooltip Edited comment --- Scripts/Editor/NodeEditorGUI.cs | 2 +- Scripts/Node.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index ee339b9..70f7d54 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -446,7 +446,7 @@ namespace XNodeEditor { Type type = hoveredPort.ValueType; GUIContent content = new GUIContent(); content.text = type.PrettyName(); - if (hoveredPort.IsStatic && hoveredPort.IsOutput) { + if (hoveredPort.IsOutput) { object obj = hoveredPort.node.GetValue(hoveredPort); content.text += " = " + (obj != null ? obj.ToString() : "null"); } diff --git a/Scripts/Node.cs b/Scripts/Node.cs index 7e9a4ac..111ee18 100644 --- a/Scripts/Node.cs +++ b/Scripts/Node.cs @@ -57,7 +57,7 @@ namespace XNode { [SerializeField] public NodeGraph graph; /// Position on the [SerializeField] public Vector2 position; - /// Input s. It is recommended not to modify these at hand. Instead, see + /// It is recommended not to modify these at hand. Instead, see and [SerializeField] private NodePortDictionary ports = new NodePortDictionary(); protected void OnEnable() { From 9c6fb740642a4ec86e07787df2ab13f73981ad36 Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Thu, 14 Jun 2018 22:56:14 +0200 Subject: [PATCH 12/25] Fixed automatic caching and drawing noodles when intentionally hiding ports --- Scripts/Editor/NodeEditorGUI.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index 70f7d54..7230121 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEditor; using UnityEngine; @@ -329,6 +330,10 @@ namespace XNodeEditor { } } else if (culledNodes.Contains(node)) continue; + if (e.type == EventType.Repaint) { + _portConnectionPoints = _portConnectionPoints.Where(x => x.Key.node != node).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + } + NodeEditor.portPositions = new Dictionary(); //Get node position From c015b6ec4bcb51b3928d28f3b8749069415079c2 Mon Sep 17 00:00:00 2001 From: Simon Rodriguez Date: Sun, 17 Jun 2018 14:16:13 +0200 Subject: [PATCH 13/25] Added attribute NodeWidth. Changes the width used when rendering the node in the editor. --- Scripts/Editor/NodeEditor.cs | 4 +++- Scripts/Editor/NodeEditorReflection.cs | 15 +++++++++++++++ Scripts/Node.cs | 10 ++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Scripts/Editor/NodeEditor.cs b/Scripts/Editor/NodeEditor.cs index 8a64663..d76a624 100644 --- a/Scripts/Editor/NodeEditor.cs +++ b/Scripts/Editor/NodeEditor.cs @@ -58,7 +58,9 @@ namespace XNodeEditor { } public virtual int GetWidth() { - return 208; + Type type = target.GetType(); + if (NodeEditorWindow.nodeWidth.ContainsKey(type)) return NodeEditorWindow.nodeWidth[type]; + else return 208; } public virtual Color GetTint() { diff --git a/Scripts/Editor/NodeEditorReflection.cs b/Scripts/Editor/NodeEditorReflection.cs index 6cdbc42..7eaec2b 100644 --- a/Scripts/Editor/NodeEditorReflection.cs +++ b/Scripts/Editor/NodeEditorReflection.cs @@ -13,6 +13,10 @@ namespace XNodeEditor { public static Dictionary nodeTint { get { return _nodeTint != null ? _nodeTint : _nodeTint = GetNodeTint(); } } [NonSerialized] private static Dictionary _nodeTint; + /// Custom node widths defined with [NodeWidth(width)] + public static Dictionary nodeWidth { get { return _nodeWidth != null ? _nodeWidth : _nodeWidth = GetNodeWidth(); } } + + [NonSerialized] private static Dictionary _nodeWidth; /// All available node types public static Type[] nodeTypes { get { return _nodeTypes != null ? _nodeTypes : _nodeTypes = GetNodeTypes(); } } @@ -34,6 +38,17 @@ namespace XNodeEditor { return tints; } + public static Dictionary GetNodeWidth() { + Dictionary widths = new Dictionary(); + for (int i = 0; i < nodeTypes.Length; i++) { + var attribs = nodeTypes[i].GetCustomAttributes(typeof(XNode.Node.NodeWidth), true); + if (attribs == null || attribs.Length == 0) continue; + XNode.Node.NodeWidth attrib = attribs[0] as XNode.Node.NodeWidth; + widths.Add(nodeTypes[i], attrib.width); + } + return widths; + } + /// Get all classes deriving from baseType via reflection public static Type[] GetDerivedTypes(Type baseType) { List types = new List(); diff --git a/Scripts/Node.cs b/Scripts/Node.cs index 111ee18..7c52d9b 100644 --- a/Scripts/Node.cs +++ b/Scripts/Node.cs @@ -272,6 +272,16 @@ namespace XNode { } } + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class NodeWidth : Attribute { + public int width; + /// Specify a width for this node type + /// Width + public NodeWidth(int width) { + this.width = width; + } + } + [Serializable] private class NodePortDictionary : Dictionary, ISerializationCallbackReceiver { [SerializeField] private List keys = new List(); [SerializeField] private List values = new List(); From 1731f8161f5d7426e3b3854dc252512fc1027241 Mon Sep 17 00:00:00 2001 From: Simon Rodriguez Date: Mon, 18 Jun 2018 15:28:56 +0200 Subject: [PATCH 14/25] Changed from .ToString() to .Name that omits the namespace from the name. --- Scripts/Editor/NodeEditorAction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs index 511f5d3..28d9e6f 100644 --- a/Scripts/Editor/NodeEditorAction.cs +++ b/Scripts/Editor/NodeEditorAction.cs @@ -301,7 +301,7 @@ namespace XNodeEditor { public void CreateNode(Type type, Vector2 position) { XNode.Node node = graph.AddNode(type); node.position = position; - node.name = UnityEditor.ObjectNames.NicifyVariableName(type.ToString()); + node.name = UnityEditor.ObjectNames.NicifyVariableName(type.Name); AssetDatabase.AddObjectToAsset(node, graph); if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); Repaint(); From 22b645c5d0acb495fe57f5cccccae561cf194511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Baran=20Pirin=C3=A7al?= <37786733+baranpirincal@users.noreply.github.com> Date: Mon, 18 Jun 2018 17:55:24 +0300 Subject: [PATCH 15/25] Added logo to readme Squashed commits: * added logo license * added logo design * Delete license * added logo design * added logo-type * Delete xNode-logotype2.png * Delete xNode-logotype.png * Delete xNode-logo-grayscale.png * Delete xNode-logo-alternative.png * Delete xNode-logo-alternative2.png * Delete xNode-logo-50x50-grayscale.png * Delete xNode-logo.svg * Delete xNode-logo-50x50.png * Delete xNode-logo-30x30_1.png * Delete xNode-logo.png * Update README.md * Update README.md * Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3c9f670..dcaa133 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +![alt text](https://user-images.githubusercontent.com/37786733/41541140-71602302-731a-11e8-9434-79b3a57292b6.png) + [![Discord](https://img.shields.io/discord/361769369404964864.svg)](https://discord.gg/qgPrHv4) [![GitHub issues](https://img.shields.io/github/issues/Siccity/xNode.svg)](https://github.com/Siccity/xNode/issues) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/Siccity/xNode/master/LICENSE.md) From 0331bde4e1c335f115f1ce2c6ab55fd7791dbd14 Mon Sep 17 00:00:00 2001 From: Joram Date: Mon, 18 Jun 2018 19:31:44 +0200 Subject: [PATCH 16/25] Plugin folder get recognized as seperate dll --- Scripts/NodeDataCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/NodeDataCache.cs b/Scripts/NodeDataCache.cs index 23507a6..8d6bbe7 100644 --- a/Scripts/NodeDataCache.cs +++ b/Scripts/NodeDataCache.cs @@ -49,7 +49,7 @@ namespace XNode { List nodeTypes = new List(); System.Reflection.Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies(); Assembly selfAssembly = Assembly.GetAssembly(baseType); - if (selfAssembly.FullName.StartsWith("Assembly-CSharp")) { + if (selfAssembly.FullName.StartsWith("Assembly-CSharp") && !selfAssembly.FullName.Contains("-firstpass")) { // If xNode is not used as a DLL, check only CSharp (fast) nodeTypes.AddRange(selfAssembly.GetTypes().Where(t => !t.IsAbstract && baseType.IsAssignableFrom(t))); } else { From 4bfb6c4b8b7958d3d8786d083c87e0a16739cffe Mon Sep 17 00:00:00 2001 From: Joram Date: Mon, 18 Jun 2018 20:52:58 +0200 Subject: [PATCH 17/25] optimized dll caching --- Scripts/NodeDataCache.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Scripts/NodeDataCache.cs b/Scripts/NodeDataCache.cs index 8d6bbe7..b194230 100644 --- a/Scripts/NodeDataCache.cs +++ b/Scripts/NodeDataCache.cs @@ -53,8 +53,12 @@ namespace XNode { // If xNode is not used as a DLL, check only CSharp (fast) nodeTypes.AddRange(selfAssembly.GetTypes().Where(t => !t.IsAbstract && baseType.IsAssignableFrom(t))); } else { - // Else, check all DDLs (slow) + // Else, check all relevant DDLs (slower) + // ignore all unity related assemblies foreach (Assembly assembly in assemblies) { + if (assembly.FullName.StartsWith("Unity")) continue; + // unity created assemblies always have version 0.0.0 + if (!assembly.FullName.Contains("Version=0.0.0")) continue; nodeTypes.AddRange(assembly.GetTypes().Where(t => !t.IsAbstract && baseType.IsAssignableFrom(t)).ToArray()); } } From efa44d26373c3bc82f8ddba3df4d437956b82f5a Mon Sep 17 00:00:00 2001 From: Simon Rodriguez Date: Wed, 20 Jun 2018 11:15:28 +0200 Subject: [PATCH 18/25] Panning was kept active if you used the middle button(button2) for panning. --- Scripts/Editor/NodeEditorAction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs index 28d9e6f..9d264b4 100644 --- a/Scripts/Editor/NodeEditorAction.cs +++ b/Scripts/Editor/NodeEditorAction.cs @@ -231,7 +231,7 @@ namespace XNodeEditor { Repaint(); currentActivity = NodeActivity.Idle; - } else if (e.button == 1) { + } else if (e.button == 1 || e.button == 2) { if (!isPanning) { if (IsDraggingPort) { draggedOutputReroutes.Add(WindowToGridPosition(e.mousePosition)); From ba3c8bdac0c4fd39a6b12368881621174ec89ba4 Mon Sep 17 00:00:00 2001 From: Simon Rodriguez Date: Wed, 20 Jun 2018 11:21:55 +0200 Subject: [PATCH 19/25] This function releases the focus of text fields and dropdowns. --- Scripts/Editor/NodeEditorAction.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs index 28d9e6f..ef5b871 100644 --- a/Scripts/Editor/NodeEditorAction.cs +++ b/Scripts/Editor/NodeEditorAction.cs @@ -207,12 +207,7 @@ namespace XNodeEditor { } 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; + EditorGUI.FocusTextInControl(null); } if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); } From c202829c9da1a94496d0c864d79c1cf71cbf7e8f Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Thu, 21 Jun 2018 23:21:32 +0200 Subject: [PATCH 20/25] Bugfix and old code removal Fixed NodeEditorGUILayout.PortField being inconsistent with Ports drawn by NodeEditorGUILayout.PropertyField Removed obsolete NodeEditorGraph.GetNodePath --- Scripts/Editor/NodeEditorGUILayout.cs | 23 ++++++++++++++++++----- Scripts/Editor/NodeGraphEditor.cs | 6 ------ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Scripts/Editor/NodeEditorGUILayout.cs b/Scripts/Editor/NodeEditorGUILayout.cs index d7a4871..3332b59 100644 --- a/Scripts/Editor/NodeEditorGUILayout.cs +++ b/Scripts/Editor/NodeEditorGUILayout.cs @@ -112,11 +112,24 @@ namespace XNodeEditor { /// Make a simple port field. public static void PortField(GUIContent label, XNode.NodePort port, params GUILayoutOption[] options) { if (port == null) return; - if (label == null) EditorGUILayout.LabelField(ObjectNames.NicifyVariableName(port.fieldName), options); - else EditorGUILayout.LabelField(label, options); - Rect rect = GUILayoutUtility.GetLastRect(); - if (port.direction == XNode.NodePort.IO.Input) rect.position = rect.position - new Vector2(16, 0); - else if (port.direction == XNode.NodePort.IO.Output) rect.position = rect.position + new Vector2(rect.width, 0); + 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) { + // Display a label + EditorGUILayout.LabelField(label != null ? label : new GUIContent(ObjectNames.NicifyVariableName(port.fieldName)), options); + + rect = GUILayoutUtility.GetLastRect(); + rect.position = rect.position - new Vector2(16, 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) { + // Display a label + EditorGUILayout.LabelField(label != null ? label : new GUIContent(ObjectNames.NicifyVariableName(port.fieldName)), NodeEditorResources.OutputPort, GUILayout.MinWidth(30)); + + rect = GUILayoutUtility.GetLastRect(); + rect.position = rect.position + new Vector2(rect.width, 0); + } + rect.size = new Vector2(16, 16); Color backgroundColor = new Color32(90, 97, 105, 255); diff --git a/Scripts/Editor/NodeGraphEditor.cs b/Scripts/Editor/NodeGraphEditor.cs index 3f0141a..bcb95e1 100644 --- a/Scripts/Editor/NodeGraphEditor.cs +++ b/Scripts/Editor/NodeGraphEditor.cs @@ -28,12 +28,6 @@ namespace XNodeEditor { return new NodeEditorPreferences.Settings(); } - /// Returns context menu path. Returns null if node is not available. - [Obsolete("Use GetNodeMenuName instead")] - public virtual string GetNodePath(Type type) { - return GetNodeMenuName(type); - } - /// Returns context node menu path. Null or empty strings for hidden nodes. public virtual string GetNodeMenuName(Type type) { //Check if type has the CreateNodeMenuAttribute From a0d86c895ea4c3ff76922cae0f8885f5e25eb2ea Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Sat, 23 Jun 2018 16:40:03 +0200 Subject: [PATCH 21/25] Added convenience NodeEditorGUILayout.PortPair --- Scripts/Editor/NodeEditorGUILayout.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Scripts/Editor/NodeEditorGUILayout.cs b/Scripts/Editor/NodeEditorGUILayout.cs index 3332b59..5064a9d 100644 --- a/Scripts/Editor/NodeEditorGUILayout.cs +++ b/Scripts/Editor/NodeEditorGUILayout.cs @@ -143,6 +143,14 @@ namespace XNodeEditor { else NodeEditor.portPositions.Add(port, portPos); } + /// Draws an input and an output port on the same line + public static void PortPair(XNode.NodePort input, XNode.NodePort output) { + GUILayout.BeginHorizontal(); + NodeEditorGUILayout.PortField(input, GUILayout.MinWidth(0)); + NodeEditorGUILayout.PortField(output, GUILayout.MinWidth(0)); + GUILayout.EndHorizontal(); + } + public static void DrawPortHandle(Rect rect, Color backgroundColor, Color typeColor) { Color col = GUI.color; GUI.color = backgroundColor; From a71cf4961dcf09181d73d2ec37436bb9c1f0c206 Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Sun, 24 Jun 2018 17:43:07 +0200 Subject: [PATCH 22/25] Small performance improvement. Nodes are now automatically marked dirty when changed. --- Scripts/Editor/NodeEditorGUI.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index 7230121..cda5b98 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -364,12 +364,11 @@ namespace XNodeEditor { //Draw node contents nodeEditor.OnNodeGUI(); - //Apply - nodeEditor.serializedObject.ApplyModifiedProperties(); - //If user changed a value, notify other scripts through onUpdateNode if (EditorGUI.EndChangeCheck()) { if (NodeEditor.onUpdateNode != null) NodeEditor.onUpdateNode(node); + EditorUtility.SetDirty(node); + nodeEditor.serializedObject.ApplyModifiedProperties(); } GUILayout.EndVertical(); From 12ddf511645f7ec5b49aede049f6d867bcc919fa Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Sun, 24 Jun 2018 23:20:29 +0200 Subject: [PATCH 23/25] Fixed bug that ironically appeared in c202829c9da1a94496d0c864d79c1cf71cbf7e8f Bug would cause ports drawn with InstancePortList to not appear at all --- Scripts/Editor/NodeEditorGUILayout.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Scripts/Editor/NodeEditorGUILayout.cs b/Scripts/Editor/NodeEditorGUILayout.cs index 5064a9d..cfd3c67 100644 --- a/Scripts/Editor/NodeEditorGUILayout.cs +++ b/Scripts/Editor/NodeEditorGUILayout.cs @@ -112,19 +112,21 @@ namespace XNodeEditor { /// Make a simple port field. 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) }; Rect rect = new Rect(); + 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) { // Display a label - EditorGUILayout.LabelField(label != null ? label : new GUIContent(ObjectNames.NicifyVariableName(port.fieldName)), options); + EditorGUILayout.LabelField(content, options); rect = GUILayoutUtility.GetLastRect(); rect.position = rect.position - new Vector2(16, 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) { // Display a label - EditorGUILayout.LabelField(label != null ? label : new GUIContent(ObjectNames.NicifyVariableName(port.fieldName)), NodeEditorResources.OutputPort, GUILayout.MinWidth(30)); + EditorGUILayout.LabelField(content, NodeEditorResources.OutputPort, options); rect = GUILayoutUtility.GetLastRect(); rect.position = rect.position + new Vector2(rect.width, 0); From 6ee12afc84361ce0b27157a47c280d0a1a25cefd Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Sun, 24 Jun 2018 23:38:19 +0200 Subject: [PATCH 24/25] Fixed not marking moved nodes as dirty --- Scripts/Editor/NodeEditorAction.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs index ddf9e1f..2996938 100644 --- a/Scripts/Editor/NodeEditorAction.cs +++ b/Scripts/Editor/NodeEditorAction.cs @@ -203,6 +203,8 @@ namespace XNodeEditor { EditorUtility.SetDirty(graph); if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); } 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) { // If click outside node, release field focus From 5a88ddbda684a9f03e9fd368bcc327a531dadbfa Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Mon, 25 Jun 2018 22:46:07 +0200 Subject: [PATCH 25/25] Removed automatically setting header to white. Controlling header color is now easier --- Scripts/Editor/NodeEditor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Scripts/Editor/NodeEditor.cs b/Scripts/Editor/NodeEditor.cs index d76a624..475a3b6 100644 --- a/Scripts/Editor/NodeEditor.cs +++ b/Scripts/Editor/NodeEditor.cs @@ -23,7 +23,6 @@ namespace XNodeEditor { } public virtual void OnHeaderGUI() { - GUI.color = Color.white; string title = target.name; if (renaming != 0 && Selection.Contains(target)) { int controlID = EditorGUIUtility.GetControlID(FocusType.Keyboard) + 1;