diff --git a/Scripts/Editor/NodeEditor.cs b/Scripts/Editor/NodeEditor.cs index 91d92d0..7652658 100644 --- a/Scripts/Editor/NodeEditor.cs +++ b/Scripts/Editor/NodeEditor.cs @@ -12,7 +12,7 @@ namespace XNodeEditor { /// Fires every whenever a node was modified through the editor public static Action onUpdateNode; - public static Dictionary portPositions; + public readonly static Dictionary portPositions = new Dictionary(); public virtual void OnHeaderGUI() { GUILayout.Label(target.name, NodeEditorResources.styles.nodeHeader, GUILayout.Height(30)); @@ -25,7 +25,6 @@ namespace XNodeEditor { // serializedObject.ApplyModifiedProperties(); goes at the end. serializedObject.Update(); string[] excludes = { "m_Script", "graph", "position", "ports" }; - portPositions = new Dictionary(); // Iterate through serialized properties and draw them like the Inspector (But with ports) SerializedProperty iterator = serializedObject.GetIterator(); diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index c773571..c9c460f 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -301,7 +301,7 @@ namespace XNodeEditor { NodeEditor nodeEditor = NodeEditor.GetEditor(node, this); - NodeEditor.portPositions = new Dictionary(); + NodeEditor.portPositions.Clear(); //Get node position Vector2 nodePos = GridToWindowPositionNoClipped(node.position); @@ -351,8 +351,7 @@ namespace XNodeEditor { Vector2 portHandlePos = kvp.Value; portHandlePos += node.position; Rect rect = new Rect(portHandlePos.x - 8, portHandlePos.y - 8, 16, 16); - if (portConnectionPoints.ContainsKey(kvp.Key)) portConnectionPoints[kvp.Key] = rect; - else portConnectionPoints.Add(kvp.Key, rect); + portConnectionPoints[kvp.Key] = rect; } } diff --git a/Scripts/Editor/NodeEditorGUILayout.cs b/Scripts/Editor/NodeEditorGUILayout.cs index 1826107..cd4d320 100644 --- a/Scripts/Editor/NodeEditorGUILayout.cs +++ b/Scripts/Editor/NodeEditorGUILayout.cs @@ -147,8 +147,7 @@ namespace XNodeEditor { // Register the handle position Vector2 portPos = rect.center; - if (NodeEditor.portPositions.ContainsKey(port)) NodeEditor.portPositions[port] = portPos; - else NodeEditor.portPositions.Add(port, portPos); + NodeEditor.portPositions[port] = portPos; } } @@ -204,8 +203,7 @@ namespace XNodeEditor { // Register the handle position Vector2 portPos = rect.center; - if (NodeEditor.portPositions.ContainsKey(port)) NodeEditor.portPositions[port] = portPos; - else NodeEditor.portPositions.Add(port, portPos); + NodeEditor.portPositions[port] = portPos; } /// Add a port field to previous layout element. @@ -233,8 +231,7 @@ namespace XNodeEditor { // Register the handle position Vector2 portPos = rect.center; - if (NodeEditor.portPositions.ContainsKey(port)) NodeEditor.portPositions[port] = portPos; - else NodeEditor.portPositions.Add(port, portPos); + NodeEditor.portPositions[port] = portPos; } /// Draws an input and an output port on the same line @@ -326,12 +323,13 @@ namespace XNodeEditor { XNode.NodePort port = node.GetPort(fieldName + " " + index); if (hasArrayData) { if (arrayData.arraySize <= index) { - EditorGUI.LabelField(rect, "Invalid element " + index); + string portInfo = port != null ? port.fieldName : ""; + 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.fieldName); + } 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); @@ -430,7 +428,12 @@ namespace XNodeEditor { int index = rl.index; - if (dynamicPorts.Count > index) { + if (dynamicPorts[index] == null) { + Debug.LogWarning("No port found at index " + index + " - Skipped"); + } else if (dynamicPorts.Count <= index) { + Debug.LogWarning("DynamicPorts[" + index + "] out of range. Length was " + dynamicPorts.Count + " - Skipped"); + } else { + // Clear the removed ports connections dynamicPorts[index].ClearConnections(); // Move following connections one step up to replace the missing connection @@ -445,11 +448,14 @@ namespace XNodeEditor { node.RemoveDynamicPort(dynamicPorts[dynamicPorts.Count() - 1].fieldName); serializedObject.Update(); EditorUtility.SetDirty(node); - } else { - Debug.LogWarning("DynamicPorts[" + index + "] out of range. Length was " + dynamicPorts.Count + ". Skipping."); } if (hasArrayData) { + 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) { diff --git a/Scripts/Editor/NodeEditorPreferences.cs b/Scripts/Editor/NodeEditorPreferences.cs index bd2cb55..2f84a4a 100644 --- a/Scripts/Editor/NodeEditorPreferences.cs +++ b/Scripts/Editor/NodeEditorPreferences.cs @@ -23,7 +23,12 @@ namespace XNodeEditor { [SerializeField] private Color32 _gridBgColor = new Color(0.18f, 0.18f, 0.18f); public Color32 gridBgColor { get { return _gridBgColor; } set { _gridBgColor = value; _gridTexture = null; } } - public float zoomOutLimit = 5f; + [Obsolete("Use maxZoom instead")] + public float zoomOutLimit { get { return maxZoom; } set { maxZoom = value; } } + + [UnityEngine.Serialization.FormerlySerializedAs("zoomOutLimit")] + public float maxZoom = 5f; + public float minZoom = 1f; public Color32 highlightColor = new Color32(255, 255, 255, 255); public bool gridSnap = true; public bool autoSave = true; @@ -114,7 +119,11 @@ namespace XNodeEditor { EditorGUILayout.LabelField("Grid", EditorStyles.boldLabel); settings.gridSnap = EditorGUILayout.Toggle(new GUIContent("Snap", "Hold CTRL in editor to invert"), settings.gridSnap); settings.zoomToMouse = EditorGUILayout.Toggle(new GUIContent("Zoom to Mouse", "Zooms towards mouse position"), settings.zoomToMouse); - settings.zoomOutLimit = EditorGUILayout.FloatField(new GUIContent("Zoom out Limit", "Upper limit to zoom"), settings.zoomOutLimit); + EditorGUILayout.LabelField("Zoom"); + EditorGUI.indentLevel++; + settings.maxZoom = EditorGUILayout.FloatField(new GUIContent("Max", "Upper limit to zoom"), settings.maxZoom); + settings.minZoom = EditorGUILayout.FloatField(new GUIContent("Min", "Lower limit to zoom"), settings.minZoom); + EditorGUI.indentLevel--; settings.gridLineColor = EditorGUILayout.ColorField("Color", settings.gridLineColor); settings.gridBgColor = EditorGUILayout.ColorField(" ", settings.gridBgColor); if (GUI.changed) { @@ -149,11 +158,13 @@ namespace XNodeEditor { //Label EditorGUILayout.LabelField("Types", EditorStyles.boldLabel); + //Clone keys so we can enumerate the dictionary and make changes. + var typeColorKeys = new List(typeColors.Keys); + //Display type colors. Save them if they are edited by the user - foreach (var typeColor in typeColors) { - Type type = typeColor.Key; + foreach (var type in typeColorKeys) { string typeColorKey = NodeEditorUtilities.PrettyName(type); - Color col = typeColor.Value; + Color col = typeColors[type]; EditorGUI.BeginChangeCheck(); EditorGUILayout.BeginHorizontal(); col = EditorGUILayout.ColorField(typeColorKey, col); @@ -162,7 +173,7 @@ namespace XNodeEditor { typeColors[type] = col; if (settings.typeColors.ContainsKey(typeColorKey)) settings.typeColors[typeColorKey] = col; else settings.typeColors.Add(typeColorKey, col); - SavePrefs(typeColorKey, settings); + SavePrefs(key, settings); NodeEditorWindow.RepaintAll(); } } diff --git a/Scripts/Editor/NodeEditorWindow.cs b/Scripts/Editor/NodeEditorWindow.cs index a575c8d..fc04439 100644 --- a/Scripts/Editor/NodeEditorWindow.cs +++ b/Scripts/Editor/NodeEditorWindow.cs @@ -61,7 +61,7 @@ namespace XNodeEditor { public XNode.NodeGraph graph; public Vector2 panOffset { get { return _panOffset; } set { _panOffset = value; Repaint(); } } private Vector2 _panOffset; - public float zoom { get { return _zoom; } set { _zoom = Mathf.Clamp(value, 1f, NodeEditorPreferences.GetSettings().zoomOutLimit); Repaint(); } } + public float zoom { get { return _zoom; } set { _zoom = Mathf.Clamp(value, NodeEditorPreferences.GetSettings().minZoom, NodeEditorPreferences.GetSettings().maxZoom); Repaint(); } } private float _zoom = 1; void OnFocus() { diff --git a/Scripts/Editor/NodeGraphEditor.cs b/Scripts/Editor/NodeGraphEditor.cs index 8a9d2f0..c509d28 100644 --- a/Scripts/Editor/NodeGraphEditor.cs +++ b/Scripts/Editor/NodeGraphEditor.cs @@ -72,7 +72,12 @@ namespace XNodeEditor { public virtual void CreateNode(Type type, Vector2 position) { XNode.Node node = target.AddNode(type); node.position = position; - if (string.IsNullOrEmpty(node.name)) node.name = UnityEditor.ObjectNames.NicifyVariableName(type.Name); + if (string.IsNullOrEmpty(node.name)) { + // Automatically remove redundant 'Node' postfix + string typeName = type.Name; + if (typeName.EndsWith("Node")) typeName = typeName.Substring(0, typeName.LastIndexOf("Node")); + node.name = UnityEditor.ObjectNames.NicifyVariableName(typeName); + } AssetDatabase.AddObjectToAsset(node, target); if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); NodeEditorWindow.RepaintAll(); @@ -88,9 +93,9 @@ namespace XNodeEditor { } /// Safely remove a node and all its connections. - public void RemoveNode(XNode.Node node) { - UnityEngine.Object.DestroyImmediate(node, true); + public virtual void RemoveNode(XNode.Node node) { target.RemoveNode(node); + UnityEngine.Object.DestroyImmediate(node, true); if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); } diff --git a/Scripts/Editor/RenamePopup.cs b/Scripts/Editor/RenamePopup.cs index a49a948..9a1ed7b 100644 --- a/Scripts/Editor/RenamePopup.cs +++ b/Scripts/Editor/RenamePopup.cs @@ -57,10 +57,10 @@ namespace XNodeEditor { else { if (GUILayout.Button("Apply") || (e.isKey && e.keyCode == KeyCode.Return)) { target.name = input; - AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); + AssetDatabase.RenameAsset(AssetDatabase.GetAssetPath(target), input); Close(); } } } } -} \ No newline at end of file +}