NodeEditorPreferences.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEditor;
  4. using UnityEngine;
  5. using UnityEngine.Serialization;
  6. namespace XNodeEditor {
  7. public enum NoodlePath { Curvy, Straight, Angled, ShaderLab }
  8. public enum NoodleStroke { Full, Dashed }
  9. public static class NodeEditorPreferences {
  10. /// <summary> The last editor we checked. This should be the one we modify </summary>
  11. private static XNodeEditor.NodeGraphEditor lastEditor;
  12. /// <summary> The last key we checked. This should be the one we modify </summary>
  13. private static string lastKey = "xNode.Settings";
  14. private static Dictionary<Type, Color> typeColors = new Dictionary<Type, Color>();
  15. private static Dictionary<string, Settings> settings = new Dictionary<string, Settings>();
  16. [System.Serializable]
  17. public class Settings : ISerializationCallbackReceiver {
  18. [SerializeField] private Color32 _gridLineColor = new Color(0.45f, 0.45f, 0.45f);
  19. public Color32 gridLineColor { get { return _gridLineColor; } set { _gridLineColor = value; _gridTexture = null; _crossTexture = null; } }
  20. [SerializeField] private Color32 _gridBgColor = new Color(0.18f, 0.18f, 0.18f);
  21. public Color32 gridBgColor { get { return _gridBgColor; } set { _gridBgColor = value; _gridTexture = null; } }
  22. [Obsolete("Use maxZoom instead")]
  23. public float zoomOutLimit { get { return maxZoom; } set { maxZoom = value; } }
  24. [UnityEngine.Serialization.FormerlySerializedAs("zoomOutLimit")]
  25. public float maxZoom = 5f;
  26. public float minZoom = 1f;
  27. public Color32 highlightColor = new Color32(255, 255, 255, 255);
  28. public bool gridSnap = true;
  29. public bool autoSave = true;
  30. public bool dragToCreate = true;
  31. public bool zoomToMouse = true;
  32. public bool portTooltips = true;
  33. [SerializeField] private string typeColorsData = "";
  34. [NonSerialized] public Dictionary<string, Color> typeColors = new Dictionary<string, Color>();
  35. [FormerlySerializedAs("noodleType")] public NoodlePath noodlePath = NoodlePath.Curvy;
  36. public NoodleStroke noodleStroke = NoodleStroke.Full;
  37. private Texture2D _gridTexture;
  38. public Texture2D gridTexture {
  39. get {
  40. if (_gridTexture == null) _gridTexture = NodeEditorResources.GenerateGridTexture(gridLineColor, gridBgColor);
  41. return _gridTexture;
  42. }
  43. }
  44. private Texture2D _crossTexture;
  45. public Texture2D crossTexture {
  46. get {
  47. if (_crossTexture == null) _crossTexture = NodeEditorResources.GenerateCrossTexture(gridLineColor);
  48. return _crossTexture;
  49. }
  50. }
  51. public void OnAfterDeserialize() {
  52. // Deserialize typeColorsData
  53. typeColors = new Dictionary<string, Color>();
  54. string[] data = typeColorsData.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
  55. for (int i = 0; i < data.Length; i += 2) {
  56. Color col;
  57. if (ColorUtility.TryParseHtmlString("#" + data[i + 1], out col)) {
  58. typeColors.Add(data[i], col);
  59. }
  60. }
  61. }
  62. public void OnBeforeSerialize() {
  63. // Serialize typeColors
  64. typeColorsData = "";
  65. foreach (var item in typeColors) {
  66. typeColorsData += item.Key + "," + ColorUtility.ToHtmlStringRGB(item.Value) + ",";
  67. }
  68. }
  69. }
  70. /// <summary> Get settings of current active editor </summary>
  71. public static Settings GetSettings() {
  72. if (XNodeEditor.NodeEditorWindow.current == null) return new Settings();
  73. if (lastEditor != XNodeEditor.NodeEditorWindow.current.graphEditor&&NodeEditorWindow.current.graphEditor!=null) {
  74. object[] attribs = XNodeEditor.NodeEditorWindow.current.graphEditor.GetType().GetCustomAttributes(typeof(XNodeEditor.NodeGraphEditor.CustomNodeGraphEditorAttribute), true);
  75. if (attribs.Length == 1) {
  76. XNodeEditor.NodeGraphEditor.CustomNodeGraphEditorAttribute attrib = attribs[0] as XNodeEditor.NodeGraphEditor.CustomNodeGraphEditorAttribute;
  77. lastEditor = XNodeEditor.NodeEditorWindow.current.graphEditor;
  78. lastKey = attrib.editorPrefsKey;
  79. } else return null;
  80. }
  81. if (!settings.ContainsKey(lastKey)) VerifyLoaded();
  82. return settings[lastKey];
  83. }
  84. #if UNITY_2019_1_OR_NEWER
  85. [SettingsProvider]
  86. public static SettingsProvider CreateXNodeSettingsProvider() {
  87. SettingsProvider provider = new SettingsProvider("Preferences/Node Editor", SettingsScope.User) {
  88. guiHandler = (searchContext) => { XNodeEditor.NodeEditorPreferences.PreferencesGUI(); },
  89. keywords = new HashSet<string>(new [] { "xNode", "node", "editor", "graph", "connections", "noodles", "ports" })
  90. };
  91. return provider;
  92. }
  93. #endif
  94. #if !UNITY_2019_1_OR_NEWER
  95. [PreferenceItem("Node Editor")]
  96. #endif
  97. private static void PreferencesGUI() {
  98. VerifyLoaded();
  99. Settings settings = NodeEditorPreferences.settings[lastKey];
  100. if (GUILayout.Button(new GUIContent("Documentation", "https://github.com/Siccity/xNode/wiki"), GUILayout.Width(100))) Application.OpenURL("https://github.com/Siccity/xNode/wiki");
  101. EditorGUILayout.Space();
  102. NodeSettingsGUI(lastKey, settings);
  103. GridSettingsGUI(lastKey, settings);
  104. SystemSettingsGUI(lastKey, settings);
  105. TypeColorsGUI(lastKey, settings);
  106. if (GUILayout.Button(new GUIContent("Set Default", "Reset all values to default"), GUILayout.Width(120))) {
  107. ResetPrefs();
  108. }
  109. }
  110. private static void GridSettingsGUI(string key, Settings settings) {
  111. //Label
  112. EditorGUILayout.LabelField("Grid", EditorStyles.boldLabel);
  113. settings.gridSnap = EditorGUILayout.Toggle(new GUIContent("Snap", "Hold CTRL in editor to invert"), settings.gridSnap);
  114. settings.zoomToMouse = EditorGUILayout.Toggle(new GUIContent("Zoom to Mouse", "Zooms towards mouse position"), settings.zoomToMouse);
  115. EditorGUILayout.LabelField("Zoom");
  116. EditorGUI.indentLevel++;
  117. settings.maxZoom = EditorGUILayout.FloatField(new GUIContent("Max", "Upper limit to zoom"), settings.maxZoom);
  118. settings.minZoom = EditorGUILayout.FloatField(new GUIContent("Min", "Lower limit to zoom"), settings.minZoom);
  119. EditorGUI.indentLevel--;
  120. settings.gridLineColor = EditorGUILayout.ColorField("Color", settings.gridLineColor);
  121. settings.gridBgColor = EditorGUILayout.ColorField(" ", settings.gridBgColor);
  122. if (GUI.changed) {
  123. SavePrefs(key, settings);
  124. NodeEditorWindow.RepaintAll();
  125. }
  126. EditorGUILayout.Space();
  127. }
  128. private static void SystemSettingsGUI(string key, Settings settings) {
  129. //Label
  130. EditorGUILayout.LabelField("System", EditorStyles.boldLabel);
  131. settings.autoSave = EditorGUILayout.Toggle(new GUIContent("Autosave", "Disable for better editor performance"), settings.autoSave);
  132. if (GUI.changed) SavePrefs(key, settings);
  133. EditorGUILayout.Space();
  134. }
  135. private static void NodeSettingsGUI(string key, Settings settings) {
  136. //Label
  137. EditorGUILayout.LabelField("Node", EditorStyles.boldLabel);
  138. settings.highlightColor = EditorGUILayout.ColorField("Selection", settings.highlightColor);
  139. settings.noodlePath = (NoodlePath) EditorGUILayout.EnumPopup("Noodle path", (Enum) settings.noodlePath);
  140. settings.noodleStroke = (NoodleStroke) EditorGUILayout.EnumPopup("Noodle stroke", (Enum) settings.noodleStroke);
  141. settings.portTooltips = EditorGUILayout.Toggle("Port Tooltips", settings.portTooltips);
  142. settings.dragToCreate = EditorGUILayout.Toggle(new GUIContent("Drag to Create", "Drag a port connection anywhere on the grid to create and connect a node"), settings.dragToCreate);
  143. if (GUI.changed) {
  144. SavePrefs(key, settings);
  145. NodeEditorWindow.RepaintAll();
  146. }
  147. EditorGUILayout.Space();
  148. }
  149. private static void TypeColorsGUI(string key, Settings settings) {
  150. //Label
  151. EditorGUILayout.LabelField("Types", EditorStyles.boldLabel);
  152. //Clone keys so we can enumerate the dictionary and make changes.
  153. var typeColorKeys = new List<Type>(typeColors.Keys);
  154. //Display type colors. Save them if they are edited by the user
  155. foreach (var type in typeColorKeys) {
  156. string typeColorKey = NodeEditorUtilities.PrettyName(type);
  157. Color col = typeColors[type];
  158. EditorGUI.BeginChangeCheck();
  159. EditorGUILayout.BeginHorizontal();
  160. col = EditorGUILayout.ColorField(typeColorKey, col);
  161. EditorGUILayout.EndHorizontal();
  162. if (EditorGUI.EndChangeCheck()) {
  163. typeColors[type] = col;
  164. if (settings.typeColors.ContainsKey(typeColorKey)) settings.typeColors[typeColorKey] = col;
  165. else settings.typeColors.Add(typeColorKey, col);
  166. SavePrefs(key, settings);
  167. NodeEditorWindow.RepaintAll();
  168. }
  169. }
  170. }
  171. /// <summary> Load prefs if they exist. Create if they don't </summary>
  172. private static Settings LoadPrefs() {
  173. // Create settings if it doesn't exist
  174. if (!EditorPrefs.HasKey(lastKey)) {
  175. if (lastEditor != null) EditorPrefs.SetString(lastKey, JsonUtility.ToJson(lastEditor.GetDefaultPreferences()));
  176. else EditorPrefs.SetString(lastKey, JsonUtility.ToJson(new Settings()));
  177. }
  178. return JsonUtility.FromJson<Settings>(EditorPrefs.GetString(lastKey));
  179. }
  180. /// <summary> Delete all prefs </summary>
  181. public static void ResetPrefs() {
  182. if (EditorPrefs.HasKey(lastKey)) EditorPrefs.DeleteKey(lastKey);
  183. if (settings.ContainsKey(lastKey)) settings.Remove(lastKey);
  184. typeColors = new Dictionary<Type, Color>();
  185. VerifyLoaded();
  186. NodeEditorWindow.RepaintAll();
  187. }
  188. /// <summary> Save preferences in EditorPrefs </summary>
  189. private static void SavePrefs(string key, Settings settings) {
  190. EditorPrefs.SetString(key, JsonUtility.ToJson(settings));
  191. }
  192. /// <summary> Check if we have loaded settings for given key. If not, load them </summary>
  193. private static void VerifyLoaded() {
  194. if (!settings.ContainsKey(lastKey)) settings.Add(lastKey, LoadPrefs());
  195. }
  196. /// <summary> Return color based on type </summary>
  197. public static Color GetTypeColor(System.Type type) {
  198. VerifyLoaded();
  199. if (type == null) return Color.gray;
  200. Color col;
  201. if (!typeColors.TryGetValue(type, out col)) {
  202. string typeName = type.PrettyName();
  203. if (settings[lastKey].typeColors.ContainsKey(typeName)) typeColors.Add(type, settings[lastKey].typeColors[typeName]);
  204. else {
  205. #if UNITY_5_4_OR_NEWER
  206. UnityEngine.Random.State oldState = UnityEngine.Random.state;
  207. UnityEngine.Random.InitState(typeName.GetHashCode());
  208. #else
  209. int oldSeed = UnityEngine.Random.seed;
  210. UnityEngine.Random.seed = typeName.GetHashCode();
  211. #endif
  212. col = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value);
  213. typeColors.Add(type, col);
  214. #if UNITY_5_4_OR_NEWER
  215. UnityEngine.Random.state = oldState;
  216. #else
  217. UnityEngine.Random.seed = oldSeed;
  218. #endif
  219. }
  220. }
  221. return col;
  222. }
  223. }
  224. }