diff --git a/.gitignore b/.gitignore
index 2946d78..46cc792 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,5 +20,6 @@
# Unity3D Generated File On Crash Reports
sysinfo.txt
+/Examples/
README.md.meta
LICENSE.md.meta
diff --git a/README.md b/README.md
index 5517e75..5194a63 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[](https://raw.githubusercontent.com/Siccity/xNode/master/LICENSE.md)
[](https://github.com/Siccity/xNode/wiki)
-[Go to Downloads](https://github.com/Siccity/xNode/releases)
+[Go to Downloads](https://github.com/Siccity/xNode/releases) / [Go to Asset Store](http://u3d.as/108S)
### 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.
diff --git a/Scripts/Editor/NodeEditor.cs b/Scripts/Editor/NodeEditor.cs
index 5ce6cc3..39febe9 100644
--- a/Scripts/Editor/NodeEditor.cs
+++ b/Scripts/Editor/NodeEditor.cs
@@ -8,7 +8,7 @@ namespace XNodeEditor {
/// Base class to derive custom Node editors from. Use this to create your own custom inspectors and editors for your nodes.
[CustomNodeEditor(typeof(XNode.Node))]
- public class NodeEditor : XNodeInternal.NodeEditorBase {
+ public class NodeEditor : XNodeEditor.Internal.NodeEditorBase {
/// Fires every whenever a node was modified through the editor
public static Action onUpdateNode;
@@ -54,7 +54,7 @@ namespace XNodeEditor {
[AttributeUsage(AttributeTargets.Class)]
public class CustomNodeEditorAttribute : Attribute,
- XNodeInternal.NodeEditorBase.INodeEditorAttrib {
+ XNodeEditor.Internal.NodeEditorBase.INodeEditorAttrib {
private Type inspectedType;
/// Tells a NodeEditor which Node type it is an editor for
/// Type that this editor can edit
diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs
index 41bb196..946e43a 100644
--- a/Scripts/Editor/NodeEditorAction.cs
+++ b/Scripts/Editor/NodeEditorAction.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
@@ -46,7 +47,11 @@ namespace XNodeEditor {
if (Selection.objects[i] is XNode.Node) {
XNode.Node node = Selection.objects[i] as XNode.Node;
node.position = WindowToGridPosition(e.mousePosition) + dragOffset[i];
- if (NodeEditorPreferences.GridSnap) {
+ bool gridSnap = NodeEditorPreferences.GetSettings().gridSnap;
+ if (e.control) {
+ gridSnap = !gridSnap;
+ }
+ if (gridSnap) {
node.position.x = (Mathf.Round((node.position.x + 8) / 16) * 16) - 8;
node.position.y = (Mathf.Round((node.position.y + 8) / 16) * 16) - 8;
}
@@ -197,16 +202,42 @@ namespace XNodeEditor {
}
}
- // Dublicate selected nodes and select the dublicates
+ /// Dublicate selected nodes and select the dublicates
public void DublicateSelectedNodes() {
UnityEngine.Object[] newNodes = new UnityEngine.Object[Selection.objects.Length];
+ Dictionary substitutes = new Dictionary();
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;
- if (node.graph != graph) continue; // ignore nodes selected in another graph
- XNode.Node n = graph.CopyNode(node);
- n.position = node.position + new Vector2(30, 30);
- newNodes[i] = n;
+ XNode.Node srcNode = Selection.objects[i] as XNode.Node;
+ if (srcNode.graph != graph) continue; // ignore nodes selected in another graph
+ XNode.Node newNode = graph.CopyNode(srcNode);
+ substitutes.Add(srcNode, newNode);
+ newNode.position = srcNode.position + new Vector2(30, 30);
+ newNodes[i] = newNode;
+ }
+ }
+
+ // Walk through the selected nodes again, recreate connections, using the new nodes
+ for (int i = 0; i < Selection.objects.Length; i++) {
+ if (Selection.objects[i] is XNode.Node) {
+ XNode.Node srcNode = Selection.objects[i] as XNode.Node;
+ if (srcNode.graph != graph) continue; // ignore nodes selected in another graph
+ 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);
+
+ if (substitutes.ContainsKey(inputPort.node) && substitutes.ContainsKey(outputPort.node)) {
+ XNode.Node newNodeIn = substitutes[inputPort.node];
+ XNode.Node newNodeOut = substitutes[outputPort.node];
+ newNodeIn.UpdateStaticPorts();
+ newNodeOut.UpdateStaticPorts();
+ inputPort = newNodeIn.GetInputPort(inputPort.fieldName);
+ outputPort = newNodeOut.GetOutputPort(outputPort.fieldName);
+ }
+ if (!inputPort.IsConnectedTo(outputPort)) inputPort.Connect(outputPort);
+ }
+ }
}
}
Selection.objects = newNodes;
diff --git a/Scripts/Editor/NodeEditorBase.cs b/Scripts/Editor/NodeEditorBase.cs
index 67d4833..0868ce0 100644
--- a/Scripts/Editor/NodeEditorBase.cs
+++ b/Scripts/Editor/NodeEditorBase.cs
@@ -5,11 +5,12 @@ using System.Reflection;
using UnityEngine;
using UnityEditor;
-namespace XNodeInternal {
+namespace XNodeEditor.Internal {
/// Handles caching of custom editor classes and their target types. Accessible with GetEditor(Type type)
public class NodeEditorBase where A : Attribute, NodeEditorBase.INodeEditorAttrib where T : NodeEditorBase where K : ScriptableObject {
/// Custom editors defined with [CustomNodeEditor]
private static Dictionary editors;
+ private static Dictionary serializeds;
public K target;
public SerializedObject serializedObject;
@@ -18,10 +19,17 @@ namespace XNodeInternal {
Type type = target.GetType();
T editor = GetEditor(type);
editor.target = target;
- editor.serializedObject = new SerializedObject(target);
+ editor.serializedObject = GetSerialized(target);
return editor;
}
+ private static SerializedObject GetSerialized(K target) {
+ if (target == null) return null;
+ if (serializeds == null) serializeds = new Dictionary();
+ if (!serializeds.ContainsKey(target)) serializeds.Add(target, new SerializedObject(target));
+ return serializeds[target];
+ }
+
private static T GetEditor(Type type) {
if (type == null) return null;
if (editors == null) CacheCustomEditors();
diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs
index e3f8c4c..2843151 100644
--- a/Scripts/Editor/NodeEditorGUI.cs
+++ b/Scripts/Editor/NodeEditorGUI.cs
@@ -6,14 +6,14 @@ using UnityEngine;
namespace XNodeEditor {
/// Contains GUI methods
public partial class NodeEditorWindow {
- private NodeGraphEditor currentGraphEditor;
+ public NodeGraphEditor graphEditor;
private List selectionCache;
private void OnGUI() {
Event e = Event.current;
Matrix4x4 m = GUI.matrix;
if (graph == null) return;
- currentGraphEditor = NodeGraphEditor.GetEditor(graph);
+ graphEditor = NodeGraphEditor.GetEditor(graph);
Controls();
@@ -52,8 +52,8 @@ namespace XNodeEditor {
rect.position = Vector2.zero;
Vector2 center = rect.size / 2f;
- Texture2D gridTex = currentGraphEditor.GetGridTexture();
- Texture2D crossTex = currentGraphEditor.GetSecondaryGridTexture();
+ Texture2D gridTex = graphEditor.GetGridTexture();
+ Texture2D crossTex = graphEditor.GetSecondaryGridTexture();
// Offset from origin in tile units
float xOffset = -(center.x * zoom + panOffset.x) / gridTex.width;
@@ -122,7 +122,7 @@ namespace XNodeEditor {
Type type = nodeTypes[i];
//Get node context menu path
- string path = currentGraphEditor.GetNodePath(type);
+ string path = graphEditor.GetNodePath(type);
if (path == null) continue;
contextMenu.AddItem(new GUIContent(path), false, () => {
@@ -151,15 +151,50 @@ namespace XNodeEditor {
startPoint = GridToWindowPosition(startPoint);
endPoint = GridToWindowPosition(endPoint);
- Vector2 startTangent = startPoint;
- if (startPoint.x < endPoint.x) startTangent.x = Mathf.LerpUnclamped(startPoint.x, endPoint.x, 0.7f);
- else startTangent.x = Mathf.LerpUnclamped(startPoint.x, endPoint.x, -0.7f);
+ switch (NodeEditorPreferences.GetSettings().noodleType) {
+ case NodeEditorPreferences.NoodleType.Curve:
+ Vector2 startTangent = startPoint;
+ if (startPoint.x < endPoint.x) startTangent.x = Mathf.LerpUnclamped(startPoint.x, endPoint.x, 0.7f);
+ else startTangent.x = Mathf.LerpUnclamped(startPoint.x, endPoint.x, -0.7f);
- Vector2 endTangent = endPoint;
- if (startPoint.x > endPoint.x) endTangent.x = Mathf.LerpUnclamped(endPoint.x, startPoint.x, -0.7f);
- else endTangent.x = Mathf.LerpUnclamped(endPoint.x, startPoint.x, 0.7f);
-
- Handles.DrawBezier(startPoint, endPoint, startTangent, endTangent, col, null, 4);
+ Vector2 endTangent = endPoint;
+ if (startPoint.x > endPoint.x) endTangent.x = Mathf.LerpUnclamped(endPoint.x, startPoint.x, -0.7f);
+ else endTangent.x = Mathf.LerpUnclamped(endPoint.x, startPoint.x, 0.7f);
+ Handles.DrawBezier(startPoint, endPoint, startTangent, endTangent, col, null, 4);
+ break;
+ case NodeEditorPreferences.NoodleType.Line:
+ Handles.color = col;
+ Handles.DrawAAPolyLine(5, startPoint, endPoint);
+ break;
+ case NodeEditorPreferences.NoodleType.Angled:
+ Handles.color = col;
+ if (startPoint.x <= endPoint.x - (50 / zoom)) {
+ float midpoint = (startPoint.x + endPoint.x) * 0.5f;
+ Vector2 start_1 = startPoint;
+ Vector2 end_1 = endPoint;
+ start_1.x = midpoint;
+ end_1.x = midpoint;
+ Handles.DrawAAPolyLine(5, startPoint, start_1);
+ Handles.DrawAAPolyLine(5, start_1, end_1);
+ Handles.DrawAAPolyLine(5, end_1, endPoint);
+ } else {
+ float midpoint = (startPoint.y + endPoint.y) * 0.5f;
+ Vector2 start_1 = startPoint;
+ Vector2 end_1 = endPoint;
+ start_1.x += 25 / zoom;
+ end_1.x -= 25 / zoom;
+ Vector2 start_2 = start_1;
+ Vector2 end_2 = end_1;
+ start_2.y = midpoint;
+ end_2.y = midpoint;
+ Handles.DrawAAPolyLine(5, startPoint, start_1);
+ Handles.DrawAAPolyLine(5, start_1, start_2);
+ Handles.DrawAAPolyLine(5, start_2, end_2);
+ Handles.DrawAAPolyLine(5, end_2, end_1);
+ Handles.DrawAAPolyLine(5, end_1, endPoint);
+ }
+ break;
+ }
}
/// Draws all connections
@@ -179,7 +214,7 @@ namespace XNodeEditor {
if (!input.IsConnectedTo(output)) input.Connect(output);
if (!_portConnectionPoints.ContainsKey(input)) continue;
Vector2 to = _portConnectionPoints[input].center;
- Color connectionColor = currentGraphEditor.GetTypeColor(output.ValueType);
+ Color connectionColor = graphEditor.GetTypeColor(output.ValueType);
DrawConnection(from, to, connectionColor);
}
}
@@ -213,7 +248,7 @@ namespace XNodeEditor {
hoveredPort = null;
}
- List preSelection = new List(preBoxSelection);
+ List preSelection = preBoxSelection != null ? new List(preBoxSelection) : new List();
//Save guiColor so we can revert it
Color guiColor = GUI.color;
@@ -240,7 +275,7 @@ namespace XNodeEditor {
style.padding = new RectOffset();
GUI.color = nodeEditor.GetTint();
GUILayout.BeginVertical(new GUIStyle(style));
- GUI.color = NodeEditorPreferences.HighlightColor;
+ GUI.color = NodeEditorPreferences.GetSettings().highlightColor;
GUILayout.BeginVertical(new GUIStyle(highlightStyle));
} else {
GUIStyle style = NodeEditorResources.styles.nodeBody;
diff --git a/Scripts/Editor/NodeEditorGUILayout.cs b/Scripts/Editor/NodeEditorGUILayout.cs
index 1751d78..0a377f9 100644
--- a/Scripts/Editor/NodeEditorGUILayout.cs
+++ b/Scripts/Editor/NodeEditorGUILayout.cs
@@ -92,7 +92,7 @@ namespace XNodeEditor {
Color backgroundColor = new Color32(90, 97, 105, 255);
if (NodeEditorWindow.nodeTint.ContainsKey(port.node.GetType())) backgroundColor *= NodeEditorWindow.nodeTint[port.node.GetType()];
- Color col = NodeGraphEditor.GetEditor(port.node.graph).GetTypeColor(port.ValueType);
+ Color col = NodeEditorWindow.current.graphEditor.GetTypeColor(port.ValueType);
DrawPortHandle(rect, backgroundColor, col);
// Register the handle position
@@ -119,7 +119,7 @@ namespace XNodeEditor {
Color backgroundColor = new Color32(90, 97, 105, 255);
if (NodeEditorWindow.nodeTint.ContainsKey(port.node.GetType())) backgroundColor *= NodeEditorWindow.nodeTint[port.node.GetType()];
- Color col = NodeGraphEditor.GetEditor(port.node.graph).GetTypeColor(port.ValueType);
+ Color col = NodeEditorWindow.current.graphEditor.GetTypeColor(port.ValueType);
DrawPortHandle(rect, backgroundColor, col);
// Register the handle position
diff --git a/Scripts/Editor/NodeEditorPreferences.cs b/Scripts/Editor/NodeEditorPreferences.cs
index 0df1ad2..aa87785 100644
--- a/Scripts/Editor/NodeEditorPreferences.cs
+++ b/Scripts/Editor/NodeEditorPreferences.cs
@@ -5,38 +5,44 @@ using UnityEngine;
namespace XNodeEditor {
public static class NodeEditorPreferences {
+ public enum NoodleType { Curve, Line, Angled }
- public static Texture2D gridTexture {
- get {
- VerifyLoaded();
- if (_gridTexture == null) _gridTexture = NodeEditorResources.GenerateGridTexture(settings.gridLineColor, settings.gridBgColor);
- return _gridTexture;
- }
- }
- private static Texture2D _gridTexture;
- public static Texture2D crossTexture {
- get {
- VerifyLoaded();
- if (_crossTexture == null) _crossTexture = NodeEditorResources.GenerateCrossTexture(settings.gridLineColor);
- return _crossTexture;
- }
- }
- private static Texture2D _crossTexture;
-
- public static bool GridSnap { get { VerifyLoaded(); return settings.gridSnap; } }
- public static Color HighlightColor { get { VerifyLoaded(); return settings.highlightColor; } }
+ /// The last editor we checked. This should be the one we modify
+ private static XNodeEditor.NodeGraphEditor lastEditor;
+ /// The last key we checked. This should be the one we modify
+ private static string lastKey = "xNode.Settings";
private static Dictionary typeColors = new Dictionary();
- private static Settings settings;
+ private static Dictionary settings = new Dictionary();
[System.Serializable]
- private class Settings : ISerializationCallbackReceiver {
- public Color32 gridLineColor = new Color(0.45f, 0.45f, 0.45f);
- public Color32 gridBgColor = new Color(0.18f, 0.18f, 0.18f);
- public Color32 highlightColor = new Color32(255, 223, 255, 255);
+ public class Settings : ISerializationCallbackReceiver {
+ [SerializeField] private Color32 _gridLineColor = new Color(0.45f, 0.45f, 0.45f);
+ public Color32 gridLineColor { get { return _gridLineColor; } set { _gridLineColor = value; _gridTexture = null; _crossTexture = null; } }
+
+ [SerializeField] private Color32 _gridBgColor = new Color(0.18f, 0.18f, 0.18f);
+ public Color32 gridBgColor { get { return _gridBgColor; } set { _gridBgColor = value; _gridTexture = null; } }
+
+ public Color32 highlightColor = new Color32(255, 255, 255, 255);
public bool gridSnap = true;
- public string typeColorsData = "";
- public Dictionary typeColors = new Dictionary();
+ [SerializeField] private string typeColorsData = "";
+ [NonSerialized] public Dictionary typeColors = new Dictionary();
+ public NoodleType noodleType = NoodleType.Curve;
+
+ private Texture2D _gridTexture;
+ public Texture2D gridTexture {
+ get {
+ if (_gridTexture == null) _gridTexture = NodeEditorResources.GenerateGridTexture(gridLineColor, gridBgColor);
+ return _gridTexture;
+ }
+ }
+ private Texture2D _crossTexture;
+ public Texture2D crossTexture {
+ get {
+ if (_crossTexture == null) _crossTexture = NodeEditorResources.GenerateCrossTexture(gridLineColor);
+ return _crossTexture;
+ }
+ }
public void OnAfterDeserialize() {
// Deserialize typeColorsData
@@ -59,19 +65,34 @@ namespace XNodeEditor {
}
}
+ /// Get settings of current active editor
+ public static Settings GetSettings() {
+ if (lastEditor != XNodeEditor.NodeEditorWindow.current.graphEditor) {
+ object[] attribs = XNodeEditor.NodeEditorWindow.current.graphEditor.GetType().GetCustomAttributes(typeof(XNodeEditor.NodeGraphEditor.CustomNodeGraphEditorAttribute), true);
+ if (attribs.Length == 1) {
+ XNodeEditor.NodeGraphEditor.CustomNodeGraphEditorAttribute attrib = attribs[0] as XNodeEditor.NodeGraphEditor.CustomNodeGraphEditorAttribute;
+ lastEditor = XNodeEditor.NodeEditorWindow.current.graphEditor;
+ lastKey = attrib.editorPrefsKey;
+ VerifyLoaded();
+ } else return null;
+ }
+ return settings[lastKey];
+ }
+
[PreferenceItem("Node Editor")]
private static void PreferencesGUI() {
VerifyLoaded();
+ Settings settings = NodeEditorPreferences.settings[lastKey];
- NodeSettingsGUI();
- GridSettingsGUI();
- TypeColorsGUI();
+ NodeSettingsGUI(lastKey, settings);
+ GridSettingsGUI(lastKey, settings);
+ TypeColorsGUI(lastKey, settings);
if (GUILayout.Button(new GUIContent("Set Default", "Reset all values to default"), GUILayout.Width(120))) {
ResetPrefs();
}
}
- private static void GridSettingsGUI() {
+ private static void GridSettingsGUI(string key, Settings settings) {
//Label
EditorGUILayout.LabelField("Grid", EditorStyles.boldLabel);
settings.gridSnap = EditorGUILayout.Toggle("Snap", settings.gridSnap);
@@ -79,75 +100,74 @@ namespace XNodeEditor {
settings.gridLineColor = EditorGUILayout.ColorField("Color", settings.gridLineColor);
settings.gridBgColor = EditorGUILayout.ColorField(" ", settings.gridBgColor);
if (GUI.changed) {
- SavePrefs();
- _gridTexture = NodeEditorResources.GenerateGridTexture(settings.gridLineColor, settings.gridBgColor);
- _crossTexture = NodeEditorResources.GenerateCrossTexture(settings.gridLineColor);
+ SavePrefs(key, settings);
+
NodeEditorWindow.RepaintAll();
}
EditorGUILayout.Space();
}
- private static void NodeSettingsGUI() {
+ private static void NodeSettingsGUI(string key, Settings settings) {
//Label
EditorGUILayout.LabelField("Node", EditorStyles.boldLabel);
settings.highlightColor = EditorGUILayout.ColorField("Selection", settings.highlightColor);
+ settings.noodleType = (NoodleType) EditorGUILayout.EnumPopup("Noodle type", (Enum) settings.noodleType);
if (GUI.changed) {
- SavePrefs();
+ SavePrefs(key, settings);
NodeEditorWindow.RepaintAll();
}
EditorGUILayout.Space();
}
- private static void TypeColorsGUI() {
+ private static void TypeColorsGUI(string key, Settings settings) {
//Label
EditorGUILayout.LabelField("Types", EditorStyles.boldLabel);
//Display type colors. Save them if they are edited by the user
- List keys = new List(typeColors.Keys);
- foreach (string key in keys) {
- Color col = typeColors[key];
+ List typeColorKeys = new List(typeColors.Keys);
+ foreach (string typeColorKey in typeColorKeys) {
+ Color col = typeColors[typeColorKey];
EditorGUI.BeginChangeCheck();
EditorGUILayout.BeginHorizontal();
- col = EditorGUILayout.ColorField(key, col);
+ col = EditorGUILayout.ColorField(typeColorKey, col);
EditorGUILayout.EndHorizontal();
if (EditorGUI.EndChangeCheck()) {
- typeColors[key] = col;
- if (settings.typeColors.ContainsKey(key)) settings.typeColors[key] = col;
- else settings.typeColors.Add(key, col);
- SavePrefs();
+ typeColors[typeColorKey] = col;
+ if (settings.typeColors.ContainsKey(typeColorKey)) settings.typeColors[typeColorKey] = col;
+ else settings.typeColors.Add(typeColorKey, col);
+ SavePrefs(typeColorKey, settings);
NodeEditorWindow.RepaintAll();
}
}
}
+ /// Load prefs if they exist. Create if they don't
private static Settings LoadPrefs() {
- // Remove obsolete editorprefs
- if (EditorPrefs.HasKey("xnode_typecolors")) EditorPrefs.DeleteKey("xnode_typecolors");
- if (EditorPrefs.HasKey("xnode_gridcolor0")) EditorPrefs.DeleteKey("xnode_gridcolor0");
- if (EditorPrefs.HasKey("xnode_gridcolor1")) EditorPrefs.DeleteKey("xnode_gridcolor1");
- if (EditorPrefs.HasKey("xnode_gridsnap")) EditorPrefs.DeleteKey("xnode_gridcolor1");
-
- if (!EditorPrefs.HasKey("xNode.Settings")) EditorPrefs.SetString("xNode.Settings", JsonUtility.ToJson(new Settings()));
- return JsonUtility.FromJson(EditorPrefs.GetString("xNode.Settings"));
+ // Create settings if it doesn't exist
+ if (!EditorPrefs.HasKey(lastKey)) {
+ if (lastEditor != null) EditorPrefs.SetString(lastKey, JsonUtility.ToJson(lastEditor.GetDefaultPreferences()));
+ else EditorPrefs.SetString(lastKey, JsonUtility.ToJson(new Settings()));
+ }
+ return JsonUtility.FromJson(EditorPrefs.GetString(lastKey));
}
/// Delete all prefs
public static void ResetPrefs() {
- if (EditorPrefs.HasKey("xNode.Settings")) EditorPrefs.DeleteKey("xNode.Settings");
-
- settings = LoadPrefs();
+ if (EditorPrefs.HasKey(lastKey)) EditorPrefs.DeleteKey(lastKey);
+ if (settings.ContainsKey(lastKey)) settings.Remove(lastKey);
typeColors = new Dictionary();
- _gridTexture = NodeEditorResources.GenerateGridTexture(settings.gridLineColor, settings.gridBgColor);
- _crossTexture = NodeEditorResources.GenerateCrossTexture(settings.gridLineColor);
+ VerifyLoaded();
NodeEditorWindow.RepaintAll();
}
- private static void SavePrefs() {
- EditorPrefs.SetString("xNode.Settings", JsonUtility.ToJson(settings));
+ /// Save preferences in EditorPrefs
+ private static void SavePrefs(string key, Settings settings) {
+ EditorPrefs.SetString(key, JsonUtility.ToJson(settings));
}
+ /// Check if we have loaded settings for given key. If not, load them
private static void VerifyLoaded() {
- if (settings == null) settings = LoadPrefs();
+ if (!settings.ContainsKey(lastKey)) settings.Add(lastKey, LoadPrefs());
}
/// Return color based on type
@@ -156,7 +176,7 @@ namespace XNodeEditor {
if (type == null) return Color.gray;
string typeName = type.PrettyName();
if (!typeColors.ContainsKey(typeName)) {
- if (settings.typeColors.ContainsKey(typeName)) typeColors.Add(typeName, settings.typeColors[typeName]);
+ if (settings[lastKey].typeColors.ContainsKey(typeName)) typeColors.Add(typeName, settings[lastKey].typeColors[typeName]);
else {
#if UNITY_5_4_OR_NEWER
UnityEngine.Random.InitState(typeName.GetHashCode());
diff --git a/Scripts/Editor/NodeGraphEditor.cs b/Scripts/Editor/NodeGraphEditor.cs
index 2842e61..3fa9406 100644
--- a/Scripts/Editor/NodeGraphEditor.cs
+++ b/Scripts/Editor/NodeGraphEditor.cs
@@ -7,16 +7,21 @@ using UnityEngine;
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 : XNodeInternal.NodeEditorBase {
+ public class NodeGraphEditor : XNodeEditor.Internal.NodeEditorBase {
/// Custom node editors defined with [CustomNodeGraphEditor]
[NonSerialized] private static Dictionary editors;
public virtual Texture2D GetGridTexture() {
- return NodeEditorPreferences.gridTexture;
+ return NodeEditorPreferences.GetSettings().gridTexture;
}
public virtual Texture2D GetSecondaryGridTexture() {
- return NodeEditorPreferences.crossTexture;
+ 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() {
+ return new NodeEditorPreferences.Settings();
}
/// Returns context menu path. Returns null if node is not available.
@@ -35,13 +40,15 @@ namespace XNodeEditor {
[AttributeUsage(AttributeTargets.Class)]
public class CustomNodeGraphEditorAttribute : Attribute,
- XNodeInternal.NodeEditorBase.INodeEditorAttrib {
+ XNodeEditor.Internal.NodeEditorBase.INodeEditorAttrib {
private Type inspectedType;
- /// Tells a NodeEditor which Node type it is an editor for
+ public string editorPrefsKey;
+ /// Tells a NodeGraphEditor which Graph type it is an editor for
/// Type that this editor can edit
- /// Path to the node
- public CustomNodeGraphEditorAttribute(Type inspectedType) {
+ /// Define unique key for unique layout settings instance
+ public CustomNodeGraphEditorAttribute(Type inspectedType, string editorPrefsKey = "xNode.Settings") {
this.inspectedType = inspectedType;
+ this.editorPrefsKey = editorPrefsKey;
}
public Type GetInspectedType() {
diff --git a/Scripts/Node.cs b/Scripts/Node.cs
index c1883d3..0e0449f 100644
--- a/Scripts/Node.cs
+++ b/Scripts/Node.cs
@@ -61,10 +61,15 @@ namespace XNode {
[SerializeField] private NodePortDictionary ports = new NodePortDictionary();
protected void OnEnable() {
- NodeDataCache.UpdatePorts(this, ports);
+ UpdateStaticPorts();
Init();
}
+ /// Update static ports to reflect class fields. This happens automatically on enable.
+ public void UpdateStaticPorts() {
+ NodeDataCache.UpdatePorts(this, ports);
+ }
+
/// Initialize node. Called on creation.
protected virtual void Init() { name = GetType().Name; }
@@ -124,7 +129,8 @@ namespace XNode {
/// Removes all instance ports from the node
[ContextMenu("Clear instance ports")]
public void ClearInstancePorts() {
- foreach (NodePort port in InstancePorts) {
+ List instancePorts = new List(InstancePorts);
+ foreach (NodePort port in instancePorts) {
RemoveInstancePort(port);
}
}
@@ -196,22 +202,18 @@ namespace XNode {
foreach (NodePort port in Ports) port.ClearConnections();
}
- public override int GetHashCode() {
- return JsonUtility.ToJson(this).GetHashCode();
- }
-
/// Mark a serializable field as an input port. You can access this through
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
public class InputAttribute : Attribute {
public ShowBackingValue backingValue;
public ConnectionType connectionType;
-
+
/// Mark a serializable field as an input port. You can access this through
/// Should we display the backing value for this port as an editor field?
/// Should we allow multiple connections?
public InputAttribute(ShowBackingValue backingValue = ShowBackingValue.Unconnected, ConnectionType connectionType = ConnectionType.Multiple) {
this.backingValue = backingValue;
- this.connectionType = connectionType;
+ this.connectionType = connectionType;
}
}