From 63b51aaa10434569a3a1406c60039be41280d651 Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Tue, 30 Jan 2018 12:27:17 +0100 Subject: [PATCH] Added more preferences control Preferences can now be saved with a custom key, and custom default settings can be specified. Other changes: XNodeInternal renamed to XNodeEditor.Internal NodeEditorWindow.graphEditor exposed as public --- Scripts/Editor/NodeEditor.cs | 4 +- Scripts/Editor/NodeEditorAction.cs | 2 +- Scripts/Editor/NodeEditorBase.cs | 2 +- Scripts/Editor/NodeEditorGUI.cs | 16 +-- Scripts/Editor/NodeEditorGUILayout.cs | 4 +- Scripts/Editor/NodeEditorPreferences.cs | 142 +++++++++++++----------- Scripts/Editor/NodeGraphEditor.cs | 21 ++-- 7 files changed, 107 insertions(+), 84 deletions(-) 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 ecea673..946e43a 100644 --- a/Scripts/Editor/NodeEditorAction.cs +++ b/Scripts/Editor/NodeEditorAction.cs @@ -47,7 +47,7 @@ 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]; - bool gridSnap = NodeEditorPreferences.GridSnap; + bool gridSnap = NodeEditorPreferences.GetSettings().gridSnap; if (e.control) { gridSnap = !gridSnap; } diff --git a/Scripts/Editor/NodeEditorBase.cs b/Scripts/Editor/NodeEditorBase.cs index 471fea0..0868ce0 100644 --- a/Scripts/Editor/NodeEditorBase.cs +++ b/Scripts/Editor/NodeEditorBase.cs @@ -5,7 +5,7 @@ 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] diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index 1e67e2c..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,7 +151,7 @@ namespace XNodeEditor { startPoint = GridToWindowPosition(startPoint); endPoint = GridToWindowPosition(endPoint); - switch (NodeEditorPreferences.noodleType) { + 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); @@ -214,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); } } @@ -275,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 b15b784..aa87785 100644 --- a/Scripts/Editor/NodeEditorPreferences.cs +++ b/Scripts/Editor/NodeEditorPreferences.cs @@ -7,40 +7,43 @@ 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; } } - public static NoodleType noodleType { get { VerifyLoaded(); return settings.noodleType; } } + /// 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 typeColors = new Dictionary(); @@ -62,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); @@ -82,76 +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); + 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 @@ -160,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() {