diff --git a/Examples/Nodes/Editor/MathNodeEditor.cs b/Examples/Nodes/Editor/MathNodeEditor.cs index 38db27b..d244742 100644 --- a/Examples/Nodes/Editor/MathNodeEditor.cs +++ b/Examples/Nodes/Editor/MathNodeEditor.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using UnityEngine; -[CustomNodeEditor(typeof(MathNode))] +[CustomNodeEditor(typeof(MathNode), "Math")] public class AddNodeEditor : NodeEditor { public override void OnNodeGUI() { diff --git a/Scripts/Editor/NodeEditor.cs b/Scripts/Editor/NodeEditor.cs index 1df9ffb..ca6e1ad 100644 --- a/Scripts/Editor/NodeEditor.cs +++ b/Scripts/Editor/NodeEditor.cs @@ -7,7 +7,6 @@ using System.Linq; using System; /// Base class to derive custom Node editors from. Use this to create your own custom inspectors and editors for your nodes. -[CustomNodeEditor(typeof(Node))] public class NodeEditor { public Node target; @@ -26,7 +25,7 @@ public class NodeEditor { object[] fieldAttribs = fields[i].GetCustomAttributes(false); HeaderAttribute headerAttrib; - if (GetAttrib(fieldAttribs, out headerAttrib)) { + if (NodeEditorUtilities.GetAttrib(fieldAttribs, out headerAttrib)) { EditorGUILayout.LabelField(headerAttrib.header); } @@ -41,15 +40,17 @@ public class NodeEditor { fieldValue = EditorGUILayout.EnumPopup(fieldName, (Enum)fieldValue); } else if (fieldType == typeof(string)) { + + if (fieldName == "name") continue; //Ignore 'name' TextAreaAttribute textAreaAttrib; - if (GetAttrib(fieldAttribs, out textAreaAttrib)) { + if (NodeEditorUtilities.GetAttrib(fieldAttribs, out textAreaAttrib)) { fieldValue = EditorGUILayout.TextArea(fieldValue != null ? (string)fieldValue : ""); } else fieldValue = EditorGUILayout.TextField(fieldName, fieldValue != null ? (string)fieldValue : ""); } else if (fieldType == typeof(Rect)) { - if (fieldName == "position") continue; + if (fieldName == "position") continue; //Ignore 'position' fieldValue = EditorGUILayout.RectField(fieldName, (Rect)fieldValue); } else if (fieldType == typeof(float)) { @@ -80,28 +81,25 @@ public class NodeEditor { fields[i].SetValue(target, fieldValue); } } + EditorGUILayout.Space(); } private static FieldInfo[] GetInspectorFields(Node node) { return node.GetType().GetFields().Where(f => f.IsPublic || f.GetCustomAttributes(typeof(SerializeField),false) != null).ToArray(); } - - private static bool GetAttrib(object[] attribs, out T attribOut) where T : Attribute { - for (int i = 0; i < attribs.Length; i++) { - if (attribs[i].GetType() == typeof(T)) { - attribOut = attribs[i] as T; - return true; - } - } - attribOut = null; - return false; - } } [AttributeUsage(AttributeTargets.Class)] public class CustomNodeEditorAttribute : Attribute { - public Type inspectedType; - public CustomNodeEditorAttribute(Type inspectedType) { - this.inspectedType = inspectedType; + public Type inspectedType { get { return _inspectedType; } } + private Type _inspectedType; + public string contextMenuName { get { return _contextMenuName; } } + private string _contextMenuName; + /// Tells a NodeEditor which Node type it is an editor for + /// Type that this editor can edit + /// Path to the node + public CustomNodeEditorAttribute(Type inspectedType, string contextMenuName) { + _inspectedType = inspectedType; + _contextMenuName = contextMenuName; } } diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs index d3ce874..4cef3e4 100644 --- a/Scripts/Editor/NodeEditorAction.cs +++ b/Scripts/Editor/NodeEditorAction.cs @@ -105,7 +105,7 @@ public partial class NodeEditorWindow { } } else if (e.button == 1) { - if (!isPanning) RightClickContextMenu(); + if (!isPanning) ShowContextMenu(); isPanning = false; } UpdateHovered(); diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index 3acaffa..6e5ae5d 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -76,18 +76,26 @@ public partial class NodeEditorWindow { return GUILayout.Button(name, EditorStyles.toolbarDropDown, GUILayout.Width(width)); } - public void RightClickContextMenu() { + /// Show right-click context menu + public void ShowContextMenu() { GenericMenu contextMenu = new GenericMenu(); + Vector2 pos = WindowToGridPosition(Event.current.mousePosition); if (hoveredNode != null) { Node node = hoveredNode; contextMenu.AddItem(new GUIContent("Remove"), false, () => graph.RemoveNode(node)); } else { - Vector2 pos = WindowToGridPosition(Event.current.mousePosition); for (int i = 0; i < nodeTypes.Length; i++) { Type type = nodeTypes[i]; - contextMenu.AddItem(new GUIContent(nodeTypes[i].ToString()), false, () => { + Type editorType = GetNodeEditor(type).GetType(); + + string name = nodeTypes[i].ToString().Replace('.', '/'); + CustomNodeEditorAttribute attrib; + if (NodeEditorUtilities.GetAttrib(editorType, out attrib)) { + name = attrib.contextMenuName; + } + contextMenu.AddItem(new GUIContent(name), false, () => { CreateNode(type, pos); }); } diff --git a/Scripts/Editor/NodeEditorReflection.cs b/Scripts/Editor/NodeEditorReflection.cs index ce7e7e8..2b8c46c 100644 --- a/Scripts/Editor/NodeEditorReflection.cs +++ b/Scripts/Editor/NodeEditorReflection.cs @@ -1,15 +1,14 @@ using System.Collections.Generic; using System.Reflection; -using System.Linq; +using System.Linq; using System; using UnityEngine; /// Contains reflection-related info public partial class NodeEditorWindow { - - private static Dictionary customNodeEditor; + [NonSerialized] private static Dictionary customNodeEditor; public static Type[] nodeTypes { get { return _nodeTypes != null ? _nodeTypes : _nodeTypes = GetNodeTypes(); } } - private static Type[] _nodeTypes; + [NonSerialized] private static Type[] _nodeTypes = null; public static NodeEditor GetNodeEditor(Type node) { if (customNodeEditor == null) CacheCustomNodeEditors(); @@ -30,6 +29,7 @@ public partial class NodeEditorWindow { for (int i = 0; i < nodeEditors.Length; i++) { var attribs = nodeEditors[i].GetCustomAttributes(typeof(CustomNodeEditorAttribute), false); if (attribs == null || attribs.Length == 0) continue; + if (nodeEditors[i].IsAbstract) continue; CustomNodeEditorAttribute attrib = attribs[0] as CustomNodeEditorAttribute; customNodeEditor.Add(attrib.inspectedType, Activator.CreateInstance(nodeEditors[i]) as NodeEditor); } @@ -39,7 +39,7 @@ public partial class NodeEditorWindow { //Get all classes deriving from baseType via reflection Assembly assembly = Assembly.GetAssembly(baseType); return assembly.GetTypes().Where(t => - t != baseType && + !t.IsAbstract && baseType.IsAssignableFrom(t) ).ToArray(); } diff --git a/Scripts/Editor/NodeEditorUtilities.cs b/Scripts/Editor/NodeEditorUtilities.cs new file mode 100644 index 0000000..37af764 --- /dev/null +++ b/Scripts/Editor/NodeEditorUtilities.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using System; + +public static class NodeEditorUtilities { + + public static bool GetAttrib(Type classType, out T attribOut) where T : Attribute { + object[] attribs = classType.GetCustomAttributes(typeof(T), false); + return GetAttrib(attribs, out attribOut); + } + + public static bool GetAttrib(object[] attribs, out T attribOut) where T : Attribute { + for (int i = 0; i < attribs.Length; i++) { + if (attribs[i].GetType() == typeof(T)) { + attribOut = attribs[i] as T; + return true; + } + } + attribOut = null; + return false; + } +} diff --git a/Scripts/Editor/NodeEditorUtilities.cs.meta b/Scripts/Editor/NodeEditorUtilities.cs.meta new file mode 100644 index 0000000..a8988ef --- /dev/null +++ b/Scripts/Editor/NodeEditorUtilities.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 120960fe5b50aba418a8e8ad3c4c4bc8 +timeCreated: 1506073499 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Editor/NodeEditorWindow.cs b/Scripts/Editor/NodeEditorWindow.cs index 2423d8d..d830e7d 100644 --- a/Scripts/Editor/NodeEditorWindow.cs +++ b/Scripts/Editor/NodeEditorWindow.cs @@ -4,6 +4,7 @@ using UnityEngine; using UnityEditor; using System.IO; using UnityEditor.Callbacks; +using System; [InitializeOnLoad] public partial class NodeEditorWindow : EditorWindow {