mirror of
https://github.com/Siccity/xNode.git
synced 2025-12-20 09:16:01 +08:00
Initial NodeGraphEditor implementation
This commit is contained in:
parent
dcff69979c
commit
4ea25f6aee
@ -7,7 +7,9 @@ using XNode;
|
|||||||
|
|
||||||
namespace XNodeEditor {
|
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>
|
/// <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>
|
/// <summary> Fires every whenever a node was modified through the editor </summary>
|
||||||
public static Action<Node> onUpdateNode;
|
public static Action<Node> onUpdateNode;
|
||||||
public Node target;
|
public Node target;
|
||||||
@ -45,17 +47,21 @@ namespace XNodeEditor {
|
|||||||
public virtual int GetWidth() {
|
public virtual int GetWidth() {
|
||||||
return 200;
|
return 200;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
public class CustomNodeEditorAttribute : Attribute {
|
public class CustomNodeEditorAttribute : Attribute,
|
||||||
public Type inspectedType { get { return _inspectedType; } }
|
INodeEditorAttrib {
|
||||||
private Type _inspectedType;
|
private Type inspectedType;
|
||||||
/// <summary> Tells a NodeEditor which Node type it is an editor for </summary>
|
/// <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="inspectedType">Type that this editor can edit</param>
|
||||||
/// <param name="contextMenuName">Path to the node</param>
|
/// <param name="contextMenuName">Path to the node</param>
|
||||||
public CustomNodeEditorAttribute(Type inspectedType) {
|
public CustomNodeEditorAttribute(Type inspectedType) {
|
||||||
_inspectedType = inspectedType;
|
this.inspectedType = inspectedType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type GetInspectedType() {
|
||||||
|
return inspectedType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
41
Scripts/Editor/NodeEditorBase.cs
Normal file
41
Scripts/Editor/NodeEditorBase.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Scripts/Editor/NodeEditorBase.cs.meta
Normal file
13
Scripts/Editor/NodeEditorBase.cs.meta
Normal 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:
|
||||||
@ -193,7 +193,7 @@ namespace XNodeEditor {
|
|||||||
Node node = graph.nodes[n];
|
Node node = graph.nodes[n];
|
||||||
Type nodeType = node.GetType();
|
Type nodeType = node.GetType();
|
||||||
|
|
||||||
NodeEditor nodeEditor = GetNodeEditor(nodeType);
|
NodeEditor nodeEditor = NodeEditor.GetEditor(nodeType);
|
||||||
nodeEditor.target = node;
|
nodeEditor.target = node;
|
||||||
nodeEditor.serializedObject = new SerializedObject(node);
|
nodeEditor.serializedObject = new SerializedObject(node);
|
||||||
NodeEditor.portPositions = new Dictionary<NodePort, Vector2>();
|
NodeEditor.portPositions = new Dictionary<NodePort, Vector2>();
|
||||||
|
|||||||
@ -10,8 +10,6 @@ using XNode;
|
|||||||
namespace XNodeEditor {
|
namespace XNodeEditor {
|
||||||
/// <summary> Contains reflection-related info </summary>
|
/// <summary> Contains reflection-related info </summary>
|
||||||
public partial class NodeEditorWindow {
|
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>
|
/// <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(); } }
|
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;
|
||||||
@ -19,31 +17,11 @@ namespace XNodeEditor {
|
|||||||
public static Type[] nodeTypes { get { return _nodeTypes != null ? _nodeTypes : _nodeTypes = GetNodeTypes(); } }
|
public static Type[] nodeTypes { get { return _nodeTypes != null ? _nodeTypes : _nodeTypes = GetNodeTypes(); } }
|
||||||
[NonSerialized] private static Type[] _nodeTypes = null;
|
[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)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Type[] GetNodeTypes() {
|
public static Type[] GetNodeTypes() {
|
||||||
//Get all classes deriving from Node via reflection
|
//Get all classes deriving from Node via reflection
|
||||||
return GetDerivedTypes(typeof(Node));
|
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() {
|
public static Dictionary<Type, Color> GetNodeTint() {
|
||||||
Dictionary<Type, Color> tints = new Dictionary<Type, Color>();
|
Dictionary<Type, Color> tints = new Dictionary<Type, Color>();
|
||||||
for (int i = 0; i < nodeTypes.Length; i++) {
|
for (int i = 0; i < nodeTypes.Length; i++) {
|
||||||
@ -121,7 +99,6 @@ namespace XNodeEditor {
|
|||||||
FieldInfo sectionsField = type.GetField("m_Sections", BindingFlags.Instance | BindingFlags.NonPublic);
|
FieldInfo sectionsField = type.GetField("m_Sections", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
IList sections = sectionsField.GetValue(window) as IList;
|
IList sections = sectionsField.GetValue(window) as IList;
|
||||||
|
|
||||||
|
|
||||||
//Iterate through sections and check contents
|
//Iterate through sections and check contents
|
||||||
Type sectionType = sectionsField.FieldType.GetGenericArguments() [0];
|
Type sectionType = sectionsField.FieldType.GetGenericArguments() [0];
|
||||||
FieldInfo sectionContentField = sectionType.GetField("content", BindingFlags.Instance | BindingFlags.Public);
|
FieldInfo sectionContentField = sectionType.GetField("content", BindingFlags.Instance | BindingFlags.Public);
|
||||||
|
|||||||
38
Scripts/Editor/NodeGraphEditor.cs
Normal file
38
Scripts/Editor/NodeGraphEditor.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
Scripts/Editor/NodeGraphEditor.cs.meta
Normal file
12
Scripts/Editor/NodeGraphEditor.cs.meta
Normal 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:
|
||||||
Loading…
x
Reference in New Issue
Block a user