1
0
mirror of https://github.com/Siccity/xNode.git synced 2025-12-20 01:06:01 +08:00

Initial NodeGraphEditor implementation

This commit is contained in:
Thor Kramer Brigsted 2017-11-22 14:54:06 +01:00
parent dcff69979c
commit 4ea25f6aee
7 changed files with 124 additions and 37 deletions

View File

@ -7,7 +7,9 @@ using XNode;
namespace XNodeEditor {
/// <summary> Base class to derive custom Node editors from. Use this to create your own custom inspectors and editors for your nodes. </summary>
public class NodeEditor {
[CustomNodeEditor(typeof(Node))]
public class NodeEditor : XNodeInternal.NodeEditorBase<NodeEditor, NodeEditor.CustomNodeEditorAttribute> {
/// <summary> Fires every whenever a node was modified through the editor </summary>
public static Action<Node> onUpdateNode;
public Node target;
@ -45,17 +47,21 @@ namespace XNodeEditor {
public virtual int GetWidth() {
return 200;
}
}
[AttributeUsage(AttributeTargets.Class)]
public class CustomNodeEditorAttribute : Attribute {
public Type inspectedType { get { return _inspectedType; } }
private Type _inspectedType;
/// <summary> Tells a NodeEditor which Node type it is an editor for </summary>
/// <param name="inspectedType">Type that this editor can edit</param>
/// <param name="contextMenuName">Path to the node</param>
public CustomNodeEditorAttribute(Type inspectedType) {
_inspectedType = inspectedType;
[AttributeUsage(AttributeTargets.Class)]
public class CustomNodeEditorAttribute : Attribute,
INodeEditorAttrib {
private Type inspectedType;
/// <summary> Tells a NodeEditor which Node type it is an editor for </summary>
/// <param name="inspectedType">Type that this editor can edit</param>
/// <param name="contextMenuName">Path to the node</param>
public CustomNodeEditorAttribute(Type inspectedType) {
this.inspectedType = inspectedType;
}
public Type GetInspectedType() {
return inspectedType;
}
}
}
}

View File

@ -0,0 +1,41 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using XNode;
using XNodeEditor;
namespace XNodeInternal {
/// <summary> Handles caching of custom editor classes and their target types. Accessible with GetEditor(Type type) </summary>
public class NodeEditorBase<T, A> where A : Attribute, NodeEditorBase<T, A>.INodeEditorAttrib where T : class {
/// <summary> Custom editors defined with [CustomNodeEditor] </summary>
private static Dictionary<Type, T> editors;
public static T GetEditor(Type type) {
if (type == null) return null;
if (editors == null) CacheCustomEditors();
if (editors.ContainsKey(type)) return editors[type];
//If type isn't found, try base type
return GetEditor(type.BaseType);
}
private static void CacheCustomEditors() {
editors = new Dictionary<Type, T>();
//Get all classes deriving from NodeEditor via reflection
Type[] nodeEditors = NodeEditorWindow.GetDerivedTypes(typeof(T));
for (int i = 0; i < nodeEditors.Length; i++) {
var attribs = nodeEditors[i].GetCustomAttributes(typeof(A), false);
if (attribs == null || attribs.Length == 0) continue;
if (nodeEditors[i].IsAbstract) continue;
A attrib = attribs[0] as A;
editors.Add(attrib.GetInspectedType(), Activator.CreateInstance(nodeEditors[i]) as T);
}
}
public interface INodeEditorAttrib {
Type GetInspectedType();
}
}
}

View File

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: e85122ded59aceb4eb4b1bd9d9202642
timeCreated: 1511353946
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -193,7 +193,7 @@ namespace XNodeEditor {
Node node = graph.nodes[n];
Type nodeType = node.GetType();
NodeEditor nodeEditor = GetNodeEditor(nodeType);
NodeEditor nodeEditor = NodeEditor.GetEditor(nodeType);
nodeEditor.target = node;
nodeEditor.serializedObject = new SerializedObject(node);
NodeEditor.portPositions = new Dictionary<NodePort, Vector2>();

View File

@ -10,40 +10,18 @@ using XNode;
namespace XNodeEditor {
/// <summary> Contains reflection-related info </summary>
public partial class NodeEditorWindow {
/// <summary> Custom node editors defined with [CustomNodeInspector] </summary>
[NonSerialized] private static Dictionary<Type, NodeEditor> customNodeEditor;
/// <summary> Custom node tint colors defined with [NodeColor(r, g, b)] </summary>
public static Dictionary<Type, Color> nodeTint { get { return _nodeTint != null ? _nodeTint : _nodeTint = GetNodeTint(); } }
[NonSerialized] private static Dictionary<Type, Color> _nodeTint;
[NonSerialized] private static Dictionary<Type, Color> _nodeTint;
/// <summary> All available node types </summary>
public static Type[] nodeTypes { get { return _nodeTypes != null ? _nodeTypes : _nodeTypes = GetNodeTypes(); } }
[NonSerialized] private static Type[] _nodeTypes = null;
public static NodeEditor GetNodeEditor(Type node) {
if (customNodeEditor == null) CacheCustomNodeEditors();
if (customNodeEditor.ContainsKey(node)) return customNodeEditor[node];
return customNodeEditor[typeof(Node)];
}
[NonSerialized] private static Type[] _nodeTypes = null;
public static Type[] GetNodeTypes() {
//Get all classes deriving from Node via reflection
return GetDerivedTypes(typeof(Node));
}
public static void CacheCustomNodeEditors() {
customNodeEditor = new Dictionary<Type, NodeEditor>();
customNodeEditor.Add(typeof(Node), new NodeEditor());
//Get all classes deriving from NodeEditor via reflection
Type[] nodeEditors = GetDerivedTypes(typeof(NodeEditor));
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);
}
}
public static Dictionary<Type, Color> GetNodeTint() {
Dictionary<Type, Color> tints = new Dictionary<Type, Color>();
for (int i = 0; i < nodeTypes.Length; i++) {
@ -121,7 +99,6 @@ namespace XNodeEditor {
FieldInfo sectionsField = type.GetField("m_Sections", BindingFlags.Instance | BindingFlags.NonPublic);
IList sections = sectionsField.GetValue(window) as IList;
//Iterate through sections and check contents
Type sectionType = sectionsField.FieldType.GetGenericArguments() [0];
FieldInfo sectionContentField = sectionType.GetField("content", BindingFlags.Instance | BindingFlags.Public);

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using XNode;
namespace XNodeEditor {
/// <summary> Base class to derive custom Node Graph editors from. Use this to override how graphs are drawn in the editor. </summary>
[CustomNodeGraphEditor(typeof(NodeGraph))]
public class NodeGraphEditor : XNodeInternal.NodeEditorBase<NodeGraphEditor, NodeGraphEditor.CustomNodeGraphEditorAttribute> {
/// <summary> Custom node editors defined with [CustomNodeGraphEditor] </summary>
[NonSerialized] private static Dictionary<Type, NodeGraphEditor> editors;
public NodeGraph target;
public SerializedObject serializedObject;
public virtual Texture2D GetGridTexture() {
return NodeEditorPreferences.gridTexture;
}
[AttributeUsage(AttributeTargets.Class)]
public class CustomNodeGraphEditorAttribute : Attribute,
INodeEditorAttrib {
private Type inspectedType;
/// <summary> Tells a NodeEditor which Node type it is an editor for </summary>
/// <param name="inspectedType">Type that this editor can edit</param>
/// <param name="contextMenuName">Path to the node</param>
public CustomNodeGraphEditorAttribute(Type inspectedType) {
this.inspectedType = inspectedType;
}
public Type GetInspectedType() {
return inspectedType;
}
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ddcbb5432255d3247a0718b15a9c193c
timeCreated: 1505462176
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: