From aef80738967ee1707600594bdd24803c6ab5eb71 Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Wed, 24 Jul 2019 00:28:43 +0200 Subject: [PATCH] Made NodeEditorReflection static, merged NodeEditorWindow and NodeGraphEditor into NodeGraphWindow --- Scripts/Editor/Drawers/NodeEnumDrawer.cs | 2 +- Scripts/Editor/NodeEditor.cs | 19 +- Scripts/Editor/NodeEditorAction.cs | 10 +- Scripts/Editor/NodeEditorBase.cs | 14 +- Scripts/Editor/NodeEditorGUI.cs | 16 +- Scripts/Editor/NodeEditorGUILayout.cs | 30 +- Scripts/Editor/NodeEditorPreferences.cs | 18 +- Scripts/Editor/NodeEditorReflection.cs | 21 +- Scripts/Editor/NodeEditorUtilities.cs | 2 +- Scripts/Editor/NodeGraphEditor.cs | 133 ----- Scripts/Editor/NodeGraphEditor.cs.meta | 12 - ...NodeEditorWindow.cs => NodeGraphWindow.cs} | 514 +++++++++++------- ...Window.cs.meta => NodeGraphWindow.cs.meta} | 0 Scripts/Editor/RenamePopup.cs | 4 +- 14 files changed, 382 insertions(+), 413 deletions(-) delete mode 100644 Scripts/Editor/NodeGraphEditor.cs delete mode 100644 Scripts/Editor/NodeGraphEditor.cs.meta rename Scripts/Editor/{NodeEditorWindow.cs => NodeGraphWindow.cs} (51%) rename Scripts/Editor/{NodeEditorWindow.cs.meta => NodeGraphWindow.cs.meta} (100%) diff --git a/Scripts/Editor/Drawers/NodeEnumDrawer.cs b/Scripts/Editor/Drawers/NodeEnumDrawer.cs index 7478f94..15844e9 100644 --- a/Scripts/Editor/Drawers/NodeEnumDrawer.cs +++ b/Scripts/Editor/Drawers/NodeEnumDrawer.cs @@ -29,7 +29,7 @@ namespace XNodeEditor { if (EditorGUI.DropdownButton(position, new GUIContent(enumName), FocusType.Passive)) { // Position is all wrong if we show the dropdown during the node draw phase. // Instead, add it to onLateGUI to display it later. - NodeEditorWindow.current.onLateGUI += () => ShowContextMenuAtMouse(property); + NodeGraphWindow.current.onLateGUI += () => ShowContextMenuAtMouse(property); } #else // Display dropdown diff --git a/Scripts/Editor/NodeEditor.cs b/Scripts/Editor/NodeEditor.cs index 015ed0a..25d2d1c 100644 --- a/Scripts/Editor/NodeEditor.cs +++ b/Scripts/Editor/NodeEditor.cs @@ -49,7 +49,7 @@ namespace XNodeEditor { public virtual int GetWidth() { Type type = target.GetType(); int width; - if (NodeEditorWindow.nodeWidth.TryGetValue(type, out width)) return width; + if (NodeEditorReflection.nodeWidth.TryGetValue(type, out width)) return width; else return 208; } @@ -58,7 +58,7 @@ namespace XNodeEditor { // Try get color from [NodeTint] attribute Type type = target.GetType(); Color color; - if (NodeEditorWindow.nodeTint.TryGetValue(type, out color)) return color; + if (NodeEditorReflection.nodeTint.TryGetValue(type, out color)) return color; // Return default color (grey) else return DEFAULTCOLOR; } @@ -72,19 +72,19 @@ namespace XNodeEditor { // Actions if only one node is selected if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) { XNode.Node node = Selection.activeObject as XNode.Node; - menu.AddItem(new GUIContent("Move To Top"), false, () => NodeEditorWindow.current.MoveNodeToTop(node)); - menu.AddItem(new GUIContent("Rename"), false, NodeEditorWindow.current.RenameSelectedNode); + menu.AddItem(new GUIContent("Move To Top"), false, () => NodeGraphWindow.current.MoveNodeToTop(node)); + menu.AddItem(new GUIContent("Rename"), false, NodeGraphWindow.current.RenameSelectedNode); } // Add actions to any number of selected nodes - menu.AddItem(new GUIContent("Copy"), false, NodeEditorWindow.current.CopySelectedNodes); - menu.AddItem(new GUIContent("Duplicate"), false, NodeEditorWindow.current.DuplicateSelectedNodes); - menu.AddItem(new GUIContent("Remove"), false, NodeEditorWindow.current.RemoveSelectedNodes); + menu.AddItem(new GUIContent("Copy"), false, NodeGraphWindow.current.CopySelectedNodes); + menu.AddItem(new GUIContent("Duplicate"), false, NodeGraphWindow.current.DuplicateSelectedNodes); + menu.AddItem(new GUIContent("Remove"), false, NodeGraphWindow.current.RemoveSelectedNodes); // Custom sctions if only one node is selected if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) { XNode.Node node = Selection.activeObject as XNode.Node; - NodeEditorWindow.AddCustomContextMenuItems(menu, node); + NodeEditorReflection.AddCustomContextMenuItems(menu, node); } } @@ -96,8 +96,7 @@ namespace XNodeEditor { } [AttributeUsage(AttributeTargets.Class)] - public class CustomNodeEditorAttribute : Attribute, - XNodeEditor.Internal.NodeEditorBase.INodeEditorAttrib { + public class CustomNodeEditorAttribute : Attribute, XNodeEditor.Internal.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 5319639..f6896ec 100644 --- a/Scripts/Editor/NodeEditorAction.cs +++ b/Scripts/Editor/NodeEditorAction.cs @@ -5,7 +5,7 @@ using UnityEditor; using UnityEngine; namespace XNodeEditor { - public partial class NodeEditorWindow { + public partial class NodeGraphWindow { public enum NodeActivity { Idle, HoldNode, DragNode, HoldGrid, DragGrid } public static NodeActivity currentActivity = NodeActivity.Idle; public static bool isPanning { get; private set; } @@ -57,7 +57,7 @@ namespace XNodeEditor { DragAndDrop.visualMode = DragAndDropVisualMode.Generic; if (e.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); - graphEditor.OnDropObjects(DragAndDrop.objectReferences); + OnDropObjects(DragAndDrop.objectReferences); } break; case EventType.MouseMove: @@ -287,7 +287,7 @@ namespace XNodeEditor { e.Use(); // Fixes copy/paste context menu appearing in Unity 5.6.6f2 - doesn't occur in 2018.3.2f1 Probably needs to be used in other places. } else if (!IsHoveringNode) { GenericMenu menu = new GenericMenu(); - graphEditor.AddContextMenuItems(menu); + AddContextMenuItems(menu); menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); } } @@ -376,7 +376,7 @@ namespace XNodeEditor { foreach (UnityEngine.Object item in Selection.objects) { if (item is XNode.Node) { XNode.Node node = item as XNode.Node; - graphEditor.RemoveNode(node); + RemoveNode(node); } } } @@ -432,7 +432,7 @@ namespace XNodeEditor { for (int i = 0; i < nodes.Length; i++) { XNode.Node srcNode = nodes[i]; if (srcNode == null) continue; - XNode.Node newNode = graphEditor.CopyNode(srcNode); + XNode.Node newNode = CopyNode(srcNode); substitutes.Add(srcNode, newNode); newNode.position = srcNode.position + offset; newNodes[i] = newNode; diff --git a/Scripts/Editor/NodeEditorBase.cs b/Scripts/Editor/NodeEditorBase.cs index ab463e6..53a8d1d 100644 --- a/Scripts/Editor/NodeEditorBase.cs +++ b/Scripts/Editor/NodeEditorBase.cs @@ -10,15 +10,15 @@ namespace XNodeEditor.Internal { /// Editor Type. Should be the type of the deriving script itself (eg. NodeEditor) /// Attribute Type. The attribute used to connect with the runtime type (eg. CustomNodeEditorAttribute) /// Runtime Type. The ScriptableObject this can be an editor for (eg. Node) - public abstract class NodeEditorBase where A : Attribute, NodeEditorBase.INodeEditorAttrib where T : NodeEditorBase where K : ScriptableObject { + public abstract class NodeEditorBase where A : Attribute, INodeEditorAttrib where T : NodeEditorBase where K : ScriptableObject { /// Custom editors defined with [CustomNodeEditor] private static Dictionary editorTypes; private static Dictionary editors = new Dictionary(); - public NodeEditorWindow window; + public NodeGraphWindow window; public K target; public SerializedObject serializedObject; - public static T GetEditor(K target, NodeEditorWindow window) { + public static T GetEditor(K target, NodeGraphWindow window) { if (target == null) return null; T editor; if (!editors.TryGetValue(target, out editor)) { @@ -50,7 +50,7 @@ namespace XNodeEditor.Internal { editorTypes = new Dictionary(); //Get all classes deriving from NodeEditor via reflection - Type[] nodeEditors = XNodeEditor.NodeEditorWindow.GetDerivedTypes(typeof(T)); + Type[] nodeEditors = XNodeEditor.NodeEditorReflection.GetDerivedTypes(typeof(T)); for (int i = 0; i < nodeEditors.Length; i++) { if (nodeEditors[i].IsAbstract) continue; var attribs = nodeEditors[i].GetCustomAttributes(typeof(A), false); @@ -62,9 +62,9 @@ namespace XNodeEditor.Internal { /// Called on creation, after references have been set public virtual void OnCreate() { } + } - public interface INodeEditorAttrib { - Type GetInspectedType(); - } + public interface INodeEditorAttrib { + Type GetInspectedType(); } } \ No newline at end of file diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index 6304754..a330b85 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -6,8 +6,7 @@ using UnityEngine; namespace XNodeEditor { /// Contains GUI methods - public partial class NodeEditorWindow { - public NodeGraphEditor graphEditor; + public partial class NodeGraphWindow { private List selectionCache; private List culledNodes; /// 19 if docked, 22 if not @@ -23,7 +22,6 @@ namespace XNodeEditor { Event e = Event.current; Matrix4x4 m = GUI.matrix; if (graph == null) return; - ValidateGraphEditor(); Controls(); DrawGrid(position, zoom, panOffset); @@ -71,7 +69,7 @@ namespace XNodeEditor { GUI.EndGroup(); Rect rect = new Rect(new Vector2(leftPadding, topPadding), new Vector2(Screen.width, Screen.height)); GUI.BeginGroup(rect); - graphEditor.OnGUI(); + OnOverlayGUI(); GUI.EndGroup(); GUI.BeginGroup(new Rect(0.0f, topPadding - (topPadding * zoom), Screen.width, Screen.height)); } @@ -94,8 +92,8 @@ namespace XNodeEditor { rect.position = Vector2.zero; Vector2 center = rect.size / 2f; - Texture2D gridTex = graphEditor.GetGridTexture(); - Texture2D crossTex = graphEditor.GetSecondaryGridTexture(); + Texture2D gridTex = GetGridTexture(); + Texture2D crossTex = GetSecondaryGridTexture(); // Offset from origin in tile units float xOffset = -(center.x * zoom + panOffset.x) / gridTex.width; @@ -230,7 +228,7 @@ namespace XNodeEditor { Rect fromRect; if (!_portConnectionPoints.TryGetValue(output, out fromRect)) continue; - Color connectionColor = graphEditor.GetPortColor(output); + Color connectionColor = GetPortColor(output); for (int k = 0; k < output.ConnectionCount; k++) { XNode.NodePort input = output.GetConnection(k); @@ -430,8 +428,8 @@ namespace XNodeEditor { } private void DrawTooltip() { - if (hoveredPort != null && NodeEditorPreferences.GetSettings().portTooltips && graphEditor != null) { - string tooltip = graphEditor.GetPortTooltip(hoveredPort); + if (hoveredPort != null && NodeEditorPreferences.GetSettings().portTooltips) { + string tooltip = GetPortTooltip(hoveredPort); if (string.IsNullOrEmpty(tooltip)) return; GUIContent content = new GUIContent(tooltip); Vector2 size = NodeEditorResources.styles.tooltip.CalcSize(content); diff --git a/Scripts/Editor/NodeEditorGUILayout.cs b/Scripts/Editor/NodeEditorGUILayout.cs index 7372508..bfb8336 100644 --- a/Scripts/Editor/NodeEditorGUILayout.cs +++ b/Scripts/Editor/NodeEditorGUILayout.cs @@ -141,8 +141,8 @@ namespace XNodeEditor { Color backgroundColor = new Color32(90, 97, 105, 255); Color tint; - if (NodeEditorWindow.nodeTint.TryGetValue(port.node.GetType(), out tint)) backgroundColor *= tint; - Color col = NodeEditorWindow.current.graphEditor.GetPortColor(port); + if (NodeEditorReflection.nodeTint.TryGetValue(port.node.GetType(), out tint)) backgroundColor *= tint; + Color col = NodeGraphWindow.current.GetPortColor(port); DrawPortHandle(rect, backgroundColor, col); // Register the handle position @@ -153,7 +153,7 @@ namespace XNodeEditor { private static System.Type GetType(SerializedProperty property) { System.Type parentType = property.serializedObject.targetObject.GetType(); - System.Reflection.FieldInfo fi = NodeEditorWindow.GetFieldInfo(parentType, property.name); + System.Reflection.FieldInfo fi = NodeEditorReflection.GetFieldInfo(parentType, property.name); return fi.FieldType; } @@ -197,8 +197,8 @@ namespace XNodeEditor { Color backgroundColor = new Color32(90, 97, 105, 255); Color tint; - if (NodeEditorWindow.nodeTint.TryGetValue(port.node.GetType(), out tint)) backgroundColor *= tint; - Color col = NodeEditorWindow.current.graphEditor.GetPortColor(port); + if (NodeEditorReflection.nodeTint.TryGetValue(port.node.GetType(), out tint)) backgroundColor *= tint; + Color col = NodeGraphWindow.current.GetPortColor(port); DrawPortHandle(rect, backgroundColor, col); // Register the handle position @@ -225,8 +225,8 @@ namespace XNodeEditor { Color backgroundColor = new Color32(90, 97, 105, 255); Color tint; - if (NodeEditorWindow.nodeTint.TryGetValue(port.node.GetType(), out tint)) backgroundColor *= tint; - Color col = NodeEditorWindow.current.graphEditor.GetPortColor(port); + if (NodeEditorReflection.nodeTint.TryGetValue(port.node.GetType(), out tint)) backgroundColor *= tint; + Color col = NodeGraphWindow.current.GetPortColor(port); DrawPortHandle(rect, backgroundColor, col); // Register the handle position @@ -362,9 +362,9 @@ namespace XNodeEditor { port.SwapConnections(nextPort); // Swap cached positions to mitigate twitching - Rect rect = NodeEditorWindow.current.portConnectionPoints[port]; - NodeEditorWindow.current.portConnectionPoints[port] = NodeEditorWindow.current.portConnectionPoints[nextPort]; - NodeEditorWindow.current.portConnectionPoints[nextPort] = rect; + Rect rect = NodeGraphWindow.current.portConnectionPoints[port]; + NodeGraphWindow.current.portConnectionPoints[port] = NodeGraphWindow.current.portConnectionPoints[nextPort]; + NodeGraphWindow.current.portConnectionPoints[nextPort] = rect; } } // Move down @@ -375,9 +375,9 @@ namespace XNodeEditor { port.SwapConnections(nextPort); // Swap cached positions to mitigate twitching - Rect rect = NodeEditorWindow.current.portConnectionPoints[port]; - NodeEditorWindow.current.portConnectionPoints[port] = NodeEditorWindow.current.portConnectionPoints[nextPort]; - NodeEditorWindow.current.portConnectionPoints[nextPort] = rect; + Rect rect = NodeGraphWindow.current.portConnectionPoints[port]; + NodeGraphWindow.current.portConnectionPoints[port] = NodeGraphWindow.current.portConnectionPoints[nextPort]; + NodeGraphWindow.current.portConnectionPoints[nextPort] = rect; } } // Apply changes @@ -392,8 +392,8 @@ namespace XNodeEditor { // Apply changes serializedObject.ApplyModifiedProperties(); serializedObject.Update(); - NodeEditorWindow.current.Repaint(); - EditorApplication.delayCall += NodeEditorWindow.current.Repaint; + NodeGraphWindow.current.Repaint(); + EditorApplication.delayCall += NodeGraphWindow.current.Repaint; }; list.onAddCallback = (ReorderableList rl) => { diff --git a/Scripts/Editor/NodeEditorPreferences.cs b/Scripts/Editor/NodeEditorPreferences.cs index c28c064..5e7459b 100644 --- a/Scripts/Editor/NodeEditorPreferences.cs +++ b/Scripts/Editor/NodeEditorPreferences.cs @@ -8,7 +8,7 @@ namespace XNodeEditor { public enum NoodleType { Curve, Line, Angled } /// The last editor we checked. This should be the one we modify - private static XNodeEditor.NodeGraphEditor lastEditor; + private static XNodeEditor.NodeGraphWindow lastEditor; /// The last key we checked. This should be the one we modify private static string lastKey = "xNode.Settings"; @@ -76,11 +76,11 @@ 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 (lastEditor != XNodeEditor.NodeGraphWindow.current) { + object[] attribs = XNodeEditor.NodeGraphWindow.current.GetType().GetCustomAttributes(typeof(XNodeEditor.NodeGraphWindow.CustomNodeGraphWindowAttribute), true); if (attribs.Length == 1) { - XNodeEditor.NodeGraphEditor.CustomNodeGraphEditorAttribute attrib = attribs[0] as XNodeEditor.NodeGraphEditor.CustomNodeGraphEditorAttribute; - lastEditor = XNodeEditor.NodeEditorWindow.current.graphEditor; + XNodeEditor.NodeGraphWindow.CustomNodeGraphWindowAttribute attrib = attribs[0] as XNodeEditor.NodeGraphWindow.CustomNodeGraphWindowAttribute; + lastEditor = XNodeEditor.NodeGraphWindow.current; lastKey = attrib.editorPrefsKey; } else return null; } @@ -130,7 +130,7 @@ namespace XNodeEditor { if (GUI.changed) { SavePrefs(key, settings); - NodeEditorWindow.RepaintAll(); + NodeGraphWindow.RepaintAll(); } EditorGUILayout.Space(); } @@ -151,7 +151,7 @@ namespace XNodeEditor { settings.portTooltips = EditorGUILayout.Toggle("Port Tooltips", settings.portTooltips); if (GUI.changed) { SavePrefs(key, settings); - NodeEditorWindow.RepaintAll(); + NodeGraphWindow.RepaintAll(); } EditorGUILayout.Space(); } @@ -176,7 +176,7 @@ namespace XNodeEditor { if (settings.typeColors.ContainsKey(typeColorKey)) settings.typeColors[typeColorKey] = col; else settings.typeColors.Add(typeColorKey, col); SavePrefs(key, settings); - NodeEditorWindow.RepaintAll(); + NodeGraphWindow.RepaintAll(); } } } @@ -197,7 +197,7 @@ namespace XNodeEditor { if (settings.ContainsKey(lastKey)) settings.Remove(lastKey); typeColors = new Dictionary(); VerifyLoaded(); - NodeEditorWindow.RepaintAll(); + NodeGraphWindow.RepaintAll(); } /// Save preferences in EditorPrefs diff --git a/Scripts/Editor/NodeEditorReflection.cs b/Scripts/Editor/NodeEditorReflection.cs index 76ec656..1bf3f2f 100644 --- a/Scripts/Editor/NodeEditorReflection.cs +++ b/Scripts/Editor/NodeEditorReflection.cs @@ -8,7 +8,7 @@ using UnityEngine; namespace XNodeEditor { /// Contains reflection-related info - public partial class NodeEditorWindow { + public static class NodeEditorReflection { /// Custom node tint colors defined with [NodeColor(r, g, b)] public static Dictionary nodeTint { get { return _nodeTint != null ? _nodeTint : _nodeTint = GetNodeTint(); } } @@ -22,23 +22,18 @@ namespace XNodeEditor { [NonSerialized] private static Type[] _nodeTypes = null; - private Func isDocked { - get { - if (_isDocked == null) { - BindingFlags fullBinding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; - MethodInfo isDockedMethod = typeof(NodeEditorWindow).GetProperty("docked", fullBinding).GetGetMethod(true); - _isDocked = (Func) Delegate.CreateDelegate(typeof(Func), this, isDockedMethod); - } - return _isDocked; - } - } - private Func _isDocked; - public static Type[] GetNodeTypes() { //Get all classes deriving from Node via reflection return GetDerivedTypes(typeof(XNode.Node)); } + /// Return a delegate used to determine whether window is docked or not. It is faster to cache this delegate than run the reflection required each time. + public static Func GetIsDockedDelegate(this EditorWindow window) { + BindingFlags fullBinding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; + MethodInfo isDockedMethod = typeof(NodeGraphWindow).GetProperty("docked", fullBinding).GetGetMethod(true); + return (Func) Delegate.CreateDelegate(typeof(Func), window, isDockedMethod); + } + public static Dictionary GetNodeTint() { Dictionary tints = new Dictionary(); for (int i = 0; i < nodeTypes.Length; i++) { diff --git a/Scripts/Editor/NodeEditorUtilities.cs b/Scripts/Editor/NodeEditorUtilities.cs index 77e71bb..0da92d7 100644 --- a/Scripts/Editor/NodeEditorUtilities.cs +++ b/Scripts/Editor/NodeEditorUtilities.cs @@ -36,7 +36,7 @@ namespace XNodeEditor { public static bool GetAttrib(Type classType, string fieldName, out T attribOut) where T : Attribute { // If we can't find field in the first run, it's probably a private field in a base class. - FieldInfo field = NodeEditorWindow.GetFieldInfo(classType, fieldName); + FieldInfo field = NodeEditorReflection.GetFieldInfo(classType, fieldName); // This shouldn't happen. Ever. if (field == null) { Debug.LogWarning("Field " + fieldName + " couldnt be found"); diff --git a/Scripts/Editor/NodeGraphEditor.cs b/Scripts/Editor/NodeGraphEditor.cs deleted file mode 100644 index ff2ca5c..0000000 --- a/Scripts/Editor/NodeGraphEditor.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor; -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 : XNodeEditor.Internal.NodeEditorBase { - [Obsolete("Use window.position instead")] - public Rect position { get { return window.position; } set { window.position = value; } } - /// Are we currently renaming a node? - protected bool isRenaming; - - public virtual void OnGUI() { } - - /// Called when opened by NodeEditorWindow - public virtual void OnOpen() { } - - public virtual Texture2D GetGridTexture() { - return NodeEditorPreferences.GetSettings().gridTexture; - } - - public virtual Texture2D GetSecondaryGridTexture() { - 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 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 - return attrib.menuName; - else // Return generated path - return ObjectNames.NicifyVariableName(type.ToString().Replace('.', '/')); - } - - /// Add items for the context menu when right-clicking this node. Override to add custom menu items. - public virtual void AddContextMenuItems(GenericMenu menu) { - Vector2 pos = NodeEditorWindow.current.WindowToGridPosition(Event.current.mousePosition); - for (int i = 0; i < NodeEditorWindow.nodeTypes.Length; i++) { - Type type = NodeEditorWindow.nodeTypes[i]; - - //Get node context menu path - string path = GetNodeMenuName(type); - if (string.IsNullOrEmpty(path)) continue; - - menu.AddItem(new GUIContent(path), false, () => { - CreateNode(type, pos); - }); - } - menu.AddSeparator(""); - if (NodeEditorWindow.copyBuffer != null && NodeEditorWindow.copyBuffer.Length > 0) menu.AddItem(new GUIContent("Paste"), false, () => NodeEditorWindow.current.PasteNodes(pos)); - else menu.AddDisabledItem(new GUIContent("Paste")); - menu.AddItem(new GUIContent("Preferences"), false, () => NodeEditorWindow.OpenPreferences()); - NodeEditorWindow.AddCustomContextMenuItems(menu, target); - } - - public virtual Color GetPortColor(XNode.NodePort port) { - return GetTypeColor(port.ValueType); - } - - public virtual Color GetTypeColor(Type type) { - return NodeEditorPreferences.GetTypeColor(type); - } - - public virtual string GetPortTooltip(XNode.NodePort port) { - Type portType = port.ValueType; - string tooltip = ""; - tooltip = portType.PrettyName(); - if (port.IsOutput) { - object obj = port.node.GetValue(port); - tooltip += " = " + (obj != null ? obj.ToString() : "null"); - } - return tooltip; - } - - /// Deal with objects dropped into the graph through DragAndDrop - public virtual void OnDropObjects(UnityEngine.Object[] objects) { - Debug.Log("No OnDropItems override defined for " + GetType()); - } - - /// Create a node and save it in the graph asset - public virtual void CreateNode(Type type, Vector2 position) { - XNode.Node node = target.AddNode(type); - node.position = position; - if (node.name == null || node.name.Trim() == "") node.name = NodeEditorUtilities.NodeDefaultName(type); - AssetDatabase.AddObjectToAsset(node, target); - if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); - NodeEditorWindow.RepaintAll(); - } - - /// Creates a copy of the original node in the graph - public XNode.Node CopyNode(XNode.Node original) { - XNode.Node node = target.CopyNode(original); - node.name = original.name; - AssetDatabase.AddObjectToAsset(node, target); - if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); - return node; - } - - /// Safely remove a node and all its connections. - public virtual void RemoveNode(XNode.Node node) { - target.RemoveNode(node); - UnityEngine.Object.DestroyImmediate(node, true); - if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); - } - - [AttributeUsage(AttributeTargets.Class)] - public class CustomNodeGraphEditorAttribute : Attribute, - XNodeEditor.Internal.NodeEditorBase.INodeEditorAttrib { - private Type inspectedType; - public string editorPrefsKey; - /// Tells a NodeGraphEditor which Graph type it is an editor for - /// Type that this editor can edit - /// 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() { - return inspectedType; - } - } - } -} \ No newline at end of file diff --git a/Scripts/Editor/NodeGraphEditor.cs.meta b/Scripts/Editor/NodeGraphEditor.cs.meta deleted file mode 100644 index bc1c153..0000000 --- a/Scripts/Editor/NodeGraphEditor.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: ddcbb5432255d3247a0718b15a9c193c -timeCreated: 1505462176 -licenseType: Free -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Scripts/Editor/NodeEditorWindow.cs b/Scripts/Editor/NodeGraphWindow.cs similarity index 51% rename from Scripts/Editor/NodeEditorWindow.cs rename to Scripts/Editor/NodeGraphWindow.cs index fc04439..cfe2633 100644 --- a/Scripts/Editor/NodeEditorWindow.cs +++ b/Scripts/Editor/NodeGraphWindow.cs @@ -1,196 +1,318 @@ -using System.Collections.Generic; -using UnityEditor; -using UnityEditor.Callbacks; -using UnityEngine; - -namespace XNodeEditor { - [InitializeOnLoad] - public partial class NodeEditorWindow : EditorWindow { - public static NodeEditorWindow current; - - /// Stores node positions for all nodePorts. - public Dictionary portConnectionPoints { get { return _portConnectionPoints; } } - private Dictionary _portConnectionPoints = new Dictionary(); - [SerializeField] private NodePortReference[] _references = new NodePortReference[0]; - [SerializeField] private Rect[] _rects = new Rect[0]; - - [System.Serializable] private class NodePortReference { - [SerializeField] private XNode.Node _node; - [SerializeField] private string _name; - - public NodePortReference(XNode.NodePort nodePort) { - _node = nodePort.node; - _name = nodePort.fieldName; - } - - public XNode.NodePort GetNodePort() { - if (_node == null) { - return null; - } - return _node.GetPort(_name); - } - } - - private void OnDisable() { - // Cache portConnectionPoints before serialization starts - int count = portConnectionPoints.Count; - _references = new NodePortReference[count]; - _rects = new Rect[count]; - int index = 0; - foreach (var portConnectionPoint in portConnectionPoints) { - _references[index] = new NodePortReference(portConnectionPoint.Key); - _rects[index] = portConnectionPoint.Value; - index++; - } - } - - private void OnEnable() { - // Reload portConnectionPoints if there are any - int length = _references.Length; - if (length == _rects.Length) { - for (int i = 0; i < length; i++) { - XNode.NodePort nodePort = _references[i].GetNodePort(); - if (nodePort != null) - _portConnectionPoints.Add(nodePort, _rects[i]); - } - } - } - - 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; - public float zoom { get { return _zoom; } set { _zoom = Mathf.Clamp(value, NodeEditorPreferences.GetSettings().minZoom, NodeEditorPreferences.GetSettings().maxZoom); Repaint(); } } - private float _zoom = 1; - - void OnFocus() { - current = this; - ValidateGraphEditor(); - if (graphEditor != null && NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); - } - - [InitializeOnLoadMethod] - private static void OnLoad() { - Selection.selectionChanged -= OnSelectionChanged; - Selection.selectionChanged += OnSelectionChanged; - } - - /// Handle Selection Change events - private static void OnSelectionChanged() { - XNode.NodeGraph nodeGraph = Selection.activeObject as XNode.NodeGraph; - if (nodeGraph && !AssetDatabase.Contains(nodeGraph)) { - Open(nodeGraph); - } - } - - /// Make sure the graph editor is assigned and to the right object - private void ValidateGraphEditor() { - NodeGraphEditor graphEditor = NodeGraphEditor.GetEditor(graph, this); - if (this.graphEditor != graphEditor) { - this.graphEditor = graphEditor; - graphEditor.OnOpen(); - } - } - - /// Create editor window - public static NodeEditorWindow Init() { - NodeEditorWindow w = CreateInstance(); - w.titleContent = new GUIContent("xNode"); - w.wantsMouseMove = true; - w.Show(); - return w; - } - - public void Save() { - if (AssetDatabase.Contains(graph)) { - EditorUtility.SetDirty(graph); - if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); - } else SaveAs(); - } - - public void SaveAs() { - string path = EditorUtility.SaveFilePanelInProject("Save NodeGraph", "NewNodeGraph", "asset", ""); - if (string.IsNullOrEmpty(path)) return; - else { - XNode.NodeGraph existingGraph = AssetDatabase.LoadAssetAtPath(path); - if (existingGraph != null) AssetDatabase.DeleteAsset(path); - AssetDatabase.CreateAsset(graph, path); - EditorUtility.SetDirty(graph); - if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); - } - } - - private void DraggableWindow(int windowID) { - GUI.DragWindow(); - } - - public Vector2 WindowToGridPosition(Vector2 windowPosition) { - return (windowPosition - (position.size * 0.5f) - (panOffset / zoom)) * zoom; - } - - public Vector2 GridToWindowPosition(Vector2 gridPosition) { - return (position.size * 0.5f) + (panOffset / zoom) + (gridPosition / zoom); - } - - public Rect GridToWindowRectNoClipped(Rect gridRect) { - gridRect.position = GridToWindowPositionNoClipped(gridRect.position); - return gridRect; - } - - public Rect GridToWindowRect(Rect gridRect) { - gridRect.position = GridToWindowPosition(gridRect.position); - gridRect.size /= zoom; - return gridRect; - } - - public Vector2 GridToWindowPositionNoClipped(Vector2 gridPosition) { - Vector2 center = position.size * 0.5f; - // UI Sharpness complete fix - Round final offset not panOffset - float xOffset = Mathf.Round(center.x * zoom + (panOffset.x + gridPosition.x)); - float yOffset = Mathf.Round(center.y * zoom + (panOffset.y + gridPosition.y)); - return new Vector2(xOffset, yOffset); - } - - public void SelectNode(XNode.Node node, bool add) { - if (add) { - List selection = new List(Selection.objects); - selection.Add(node); - Selection.objects = selection.ToArray(); - } else Selection.objects = new Object[] { node }; - } - - public void DeselectNode(XNode.Node node) { - List selection = new List(Selection.objects); - selection.Remove(node); - Selection.objects = selection.ToArray(); - } - - [OnOpenAsset(0)] - public static bool OnOpen(int instanceID, int line) { - XNode.NodeGraph nodeGraph = EditorUtility.InstanceIDToObject(instanceID) as XNode.NodeGraph; - if (nodeGraph != null) { - Open(nodeGraph); - return true; - } - return false; - } - - /// Open the provided graph in the NodeEditor - public static void Open(XNode.NodeGraph graph) { - if (!graph) return; - - NodeEditorWindow w = GetWindow(typeof(NodeEditorWindow), false, "xNode", true) as NodeEditorWindow; - w.wantsMouseMove = true; - w.graph = graph; - } - - /// Repaint all open NodeEditorWindows. - public static void RepaintAll() { - NodeEditorWindow[] windows = Resources.FindObjectsOfTypeAll(); - for (int i = 0; i < windows.Length; i++) { - windows[i].Repaint(); - } - } - } -} +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace XNodeEditor { + [InitializeOnLoad, CustomNodeGraphWindow(typeof(XNode.NodeGraph))] + public partial class NodeGraphWindow : EditorWindow { + + /// Stores node positions for all nodePorts. + public Dictionary portConnectionPoints { get { return _portConnectionPoints; } } + private Dictionary _portConnectionPoints = new Dictionary(); + [SerializeField] private NodePortReference[] _references = new NodePortReference[0]; + [SerializeField] private Rect[] _rects = new Rect[0]; + + private Func isDocked { + get { + if (_isDocked == null) _isDocked = this.GetIsDockedDelegate(); + return _isDocked; + } + } + private Func _isDocked; + + [System.Serializable] private class NodePortReference { + [SerializeField] private XNode.Node _node; + [SerializeField] private string _name; + + public NodePortReference(XNode.NodePort nodePort) { + _node = nodePort.node; + _name = nodePort.fieldName; + } + + public XNode.NodePort GetNodePort() { + if (_node == null) { + return null; + } + return _node.GetPort(_name); + } + } + + public static NodeGraphWindow current; + + public XNode.NodeGraph target; + + /// Are we currently renaming a node? + protected bool isRenaming; + + /// Called when opened by NodeEditorWindow + public virtual void OnOpen() { } + + public virtual void OnOverlayGUI() { } + + public virtual Texture2D GetGridTexture() { + return NodeEditorPreferences.GetSettings().gridTexture; + } + + public virtual Texture2D GetSecondaryGridTexture() { + 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 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 + return attrib.menuName; + else // Return generated path + return ObjectNames.NicifyVariableName(type.ToString().Replace('.', '/')); + } + + /// Add items for the context menu when right-clicking this node. Override to add custom menu items. + public virtual void AddContextMenuItems(GenericMenu menu) { + Vector2 pos = WindowToGridPosition(Event.current.mousePosition); + for (int i = 0; i < NodeEditorReflection.nodeTypes.Length; i++) { + Type type = NodeEditorReflection.nodeTypes[i]; + + //Get node context menu path + string path = GetNodeMenuName(type); + if (string.IsNullOrEmpty(path)) continue; + + menu.AddItem(new GUIContent(path), false, () => { + CreateNode(type, pos); + }); + } + menu.AddSeparator(""); + if (NodeGraphWindow.copyBuffer != null && NodeGraphWindow.copyBuffer.Length > 0) menu.AddItem(new GUIContent("Paste"), false, () => PasteNodes(pos)); + else menu.AddDisabledItem(new GUIContent("Paste")); + menu.AddItem(new GUIContent("Preferences"), false, () => NodeEditorReflection.OpenPreferences()); + NodeEditorReflection.AddCustomContextMenuItems(menu, target); + } + + public virtual Color GetPortColor(XNode.NodePort port) { + return GetTypeColor(port.ValueType); + } + + public virtual Color GetTypeColor(Type type) { + return NodeEditorPreferences.GetTypeColor(type); + } + + public virtual string GetPortTooltip(XNode.NodePort port) { + Type portType = port.ValueType; + string tooltip = ""; + tooltip = portType.PrettyName(); + if (port.IsOutput) { + object obj = port.node.GetValue(port); + tooltip += " = " + (obj != null ? obj.ToString() : "null"); + } + return tooltip; + } + + /// Deal with objects dropped into the graph through DragAndDrop + public virtual void OnDropObjects(UnityEngine.Object[] objects) { + Debug.Log("No OnDropItems override defined for " + GetType()); + } + + /// Create a node and save it in the graph asset + public virtual void CreateNode(Type type, Vector2 position) { + XNode.Node node = target.AddNode(type); + node.position = position; + if (node.name == null || node.name.Trim() == "") node.name = NodeEditorUtilities.NodeDefaultName(type); + AssetDatabase.AddObjectToAsset(node, target); + if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); + NodeGraphWindow.RepaintAll(); + } + + /// Creates a copy of the original node in the graph + public XNode.Node CopyNode(XNode.Node original) { + XNode.Node node = target.CopyNode(original); + node.name = original.name; + AssetDatabase.AddObjectToAsset(node, target); + if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); + return node; + } + + /// Safely remove a node and all its connections. + public virtual void RemoveNode(XNode.Node node) { + target.RemoveNode(node); + UnityEngine.Object.DestroyImmediate(node, true); + if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); + } + + [AttributeUsage(AttributeTargets.Class)] + public class CustomNodeGraphWindowAttribute : Attribute, XNodeEditor.Internal.INodeEditorAttrib { + private Type inspectedType; + public string editorPrefsKey; + /// Tells a NodeGraphEditor which Graph type it is an editor for + /// Type that this editor can edit + /// Define unique key for unique layout settings instance + public CustomNodeGraphWindowAttribute(Type inspectedType, string editorPrefsKey = "xNode.Settings") { + this.inspectedType = inspectedType; + this.editorPrefsKey = editorPrefsKey; + } + + public Type GetInspectedType() { + return inspectedType; + } + } + + private void OnDisable() { + // Cache portConnectionPoints before serialization starts + int count = portConnectionPoints.Count; + _references = new NodePortReference[count]; + _rects = new Rect[count]; + int index = 0; + foreach (var portConnectionPoint in portConnectionPoints) { + _references[index] = new NodePortReference(portConnectionPoint.Key); + _rects[index] = portConnectionPoint.Value; + index++; + } + } + + private void OnEnable() { + // Reload portConnectionPoints if there are any + int length = _references.Length; + if (length == _rects.Length) { + for (int i = 0; i < length; i++) { + XNode.NodePort nodePort = _references[i].GetNodePort(); + if (nodePort != null) + _portConnectionPoints.Add(nodePort, _rects[i]); + } + } + } + + 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; + public float zoom { get { return _zoom; } set { _zoom = Mathf.Clamp(value, NodeEditorPreferences.GetSettings().minZoom, NodeEditorPreferences.GetSettings().maxZoom); Repaint(); } } + private float _zoom = 1; + + void OnFocus() { + current = this; + if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); + } + + [InitializeOnLoadMethod] + private static void OnLoad() { + Selection.selectionChanged -= OnSelectionChanged; + Selection.selectionChanged += OnSelectionChanged; + } + + /// Handle Selection Change events + private static void OnSelectionChanged() { + XNode.NodeGraph nodeGraph = Selection.activeObject as XNode.NodeGraph; + if (nodeGraph && !AssetDatabase.Contains(nodeGraph)) { + Open(nodeGraph); + } + } + + /// Create editor window + public static NodeGraphWindow Init() { + NodeGraphWindow w = CreateInstance(); + w.titleContent = new GUIContent("xNode"); + w.wantsMouseMove = true; + w.Show(); + return w; + } + + public void Save() { + if (AssetDatabase.Contains(graph)) { + EditorUtility.SetDirty(graph); + if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); + } else SaveAs(); + } + + public void SaveAs() { + string path = EditorUtility.SaveFilePanelInProject("Save NodeGraph", "NewNodeGraph", "asset", ""); + if (string.IsNullOrEmpty(path)) return; + else { + XNode.NodeGraph existingGraph = AssetDatabase.LoadAssetAtPath(path); + if (existingGraph != null) AssetDatabase.DeleteAsset(path); + AssetDatabase.CreateAsset(graph, path); + EditorUtility.SetDirty(graph); + if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); + } + } + + private void DraggableWindow(int windowID) { + GUI.DragWindow(); + } + + public Vector2 WindowToGridPosition(Vector2 windowPosition) { + return (windowPosition - (position.size * 0.5f) - (panOffset / zoom)) * zoom; + } + + public Vector2 GridToWindowPosition(Vector2 gridPosition) { + return (position.size * 0.5f) + (panOffset / zoom) + (gridPosition / zoom); + } + + public Rect GridToWindowRectNoClipped(Rect gridRect) { + gridRect.position = GridToWindowPositionNoClipped(gridRect.position); + return gridRect; + } + + public Rect GridToWindowRect(Rect gridRect) { + gridRect.position = GridToWindowPosition(gridRect.position); + gridRect.size /= zoom; + return gridRect; + } + + public Vector2 GridToWindowPositionNoClipped(Vector2 gridPosition) { + Vector2 center = position.size * 0.5f; + // UI Sharpness complete fix - Round final offset not panOffset + float xOffset = Mathf.Round(center.x * zoom + (panOffset.x + gridPosition.x)); + float yOffset = Mathf.Round(center.y * zoom + (panOffset.y + gridPosition.y)); + return new Vector2(xOffset, yOffset); + } + + public void SelectNode(XNode.Node node, bool add) { + if (add) { + List selection = new List(Selection.objects); + selection.Add(node); + Selection.objects = selection.ToArray(); + } else Selection.objects = new Object[] { node }; + } + + public void DeselectNode(XNode.Node node) { + List selection = new List(Selection.objects); + selection.Remove(node); + Selection.objects = selection.ToArray(); + } + + [OnOpenAsset(0)] + public static bool OnOpen(int instanceID, int line) { + XNode.NodeGraph nodeGraph = EditorUtility.InstanceIDToObject(instanceID) as XNode.NodeGraph; + if (nodeGraph != null) { + Open(nodeGraph); + return true; + } + return false; + } + + /// Open the provided graph in the NodeEditor + public static void Open(XNode.NodeGraph graph) { + if (!graph) return; + + NodeGraphWindow w = GetWindow(typeof(NodeGraphWindow), false, "xNode", true) as NodeGraphWindow; + w.wantsMouseMove = true; + w.graph = graph; + } + + /// Repaint all open NodeEditorWindows. + public static void RepaintAll() { + NodeGraphWindow[] windows = Resources.FindObjectsOfTypeAll(); + for (int i = 0; i < windows.Length; i++) { + windows[i].Repaint(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Editor/NodeEditorWindow.cs.meta b/Scripts/Editor/NodeGraphWindow.cs.meta similarity index 100% rename from Scripts/Editor/NodeEditorWindow.cs.meta rename to Scripts/Editor/NodeGraphWindow.cs.meta diff --git a/Scripts/Editor/RenamePopup.cs b/Scripts/Editor/RenamePopup.cs index 4903525..2f05dbf 100644 --- a/Scripts/Editor/RenamePopup.cs +++ b/Scripts/Editor/RenamePopup.cs @@ -51,7 +51,7 @@ namespace XNodeEditor { target.name = NodeEditorUtilities.NodeDefaultName(target.GetType()); AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); Close(); - NodeEditorWindow.TriggerOnValidate(target); + NodeEditorReflection.TriggerOnValidate(target); } } // Rename asset to input text @@ -60,7 +60,7 @@ namespace XNodeEditor { target.name = input; AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); Close(); - NodeEditorWindow.TriggerOnValidate(target); + NodeEditorReflection.TriggerOnValidate(target); } } }