mirror of
https://github.com/Siccity/xNode.git
synced 2025-12-20 17:26:02 +08:00
Exposed fields and custom editors
This commit is contained in:
parent
b7543df012
commit
846f7f30b1
@ -4,7 +4,12 @@
|
|||||||
public class BaseNode : Node {
|
public class BaseNode : Node {
|
||||||
|
|
||||||
public bool concat;
|
public bool concat;
|
||||||
|
[TextArea]
|
||||||
|
public string SomeString;
|
||||||
|
[Header("New stuff")]
|
||||||
|
public Color col;
|
||||||
|
public AnimationCurve anim;
|
||||||
|
public Vector3 vec;
|
||||||
protected override void Init() {
|
protected override void Init() {
|
||||||
inputs = new NodePort[2];
|
inputs = new NodePort[2];
|
||||||
inputs[0] = CreateNodeInput("IntInput", typeof(int));
|
inputs[0] = CreateNodeInput("IntInput", typeof(int));
|
||||||
|
|||||||
9
Examples/Nodes/Editor.meta
Normal file
9
Examples/Nodes/Editor.meta
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0d2300267781fed46a6d964565309cbf
|
||||||
|
folderAsset: yes
|
||||||
|
timeCreated: 1505987971
|
||||||
|
licenseType: Free
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
12
Examples/Nodes/Editor/MathNodeEditor.cs
Normal file
12
Examples/Nodes/Editor/MathNodeEditor.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
[CustomNodeEditor(typeof(MathNode))]
|
||||||
|
public class AddNodeEditor : NodeEditor {
|
||||||
|
|
||||||
|
public override void OnNodeGUI() {
|
||||||
|
GUILayout.Label("YEAH CUSTOM");
|
||||||
|
base.OnNodeGUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
12
Examples/Nodes/Editor/MathNodeEditor.cs.meta
Normal file
12
Examples/Nodes/Editor/MathNodeEditor.cs.meta
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c4cc83d08877562419d86874dd3587e2
|
||||||
|
timeCreated: 1505987983
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -1,9 +1,11 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
[System.Serializable]
|
[System.Serializable]
|
||||||
public class AddNode : Node {
|
public class MathNode : Node {
|
||||||
|
|
||||||
public int someValue;
|
public int someValue;
|
||||||
|
public enum MathType { Add, Subtract, Multiply, Divide}
|
||||||
|
public MathType mathType = MathType.Add;
|
||||||
|
|
||||||
protected override void Init() {
|
protected override void Init() {
|
||||||
inputs = new NodePort[2];
|
inputs = new NodePort[2];
|
||||||
@ -2,11 +2,102 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Linq;
|
||||||
|
using System;
|
||||||
|
|
||||||
/// <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 : Editor {
|
[CustomNodeEditor(typeof(Node))]
|
||||||
|
public class NodeEditor {
|
||||||
public override void OnInspectorGUI() {
|
|
||||||
base.OnInspectorGUI();
|
public Node target;
|
||||||
|
|
||||||
|
public virtual void OnNodeGUI() {
|
||||||
|
DrawDefaultNodeGUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawDefaultNodeGUI() {
|
||||||
|
FieldInfo[] fields = GetInspectorFields(target);
|
||||||
|
for (int i = 0; i < fields.Length; i++) {
|
||||||
|
Type fieldType = fields[i].FieldType;
|
||||||
|
string fieldName = fields[i].Name;
|
||||||
|
object fieldValue = fields[i].GetValue(target);
|
||||||
|
object[] fieldAttribs = fields[i].GetCustomAttributes(false);
|
||||||
|
|
||||||
|
HeaderAttribute headerAttrib;
|
||||||
|
if (GetAttrib(fieldAttribs, out headerAttrib)) {
|
||||||
|
EditorGUILayout.LabelField(headerAttrib.header);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
if (fieldType == typeof(int)) {
|
||||||
|
fieldValue = EditorGUILayout.IntField(fieldName, (int)fieldValue);
|
||||||
|
}
|
||||||
|
else if (fieldType == typeof(bool)) {
|
||||||
|
fieldValue = EditorGUILayout.Toggle(fieldName, (bool)fieldValue);
|
||||||
|
}
|
||||||
|
else if (fieldType.IsEnum) {
|
||||||
|
fieldValue = EditorGUILayout.EnumPopup(fieldName, (Enum)fieldValue);
|
||||||
|
}
|
||||||
|
else if (fieldType == typeof(string)) {
|
||||||
|
TextAreaAttribute textAreaAttrib;
|
||||||
|
if (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;
|
||||||
|
fieldValue = EditorGUILayout.RectField(fieldName, (Rect)fieldValue);
|
||||||
|
}
|
||||||
|
else if (fieldType == typeof(float)) {
|
||||||
|
fieldValue = EditorGUILayout.FloatField(fieldName, (float)fieldValue);
|
||||||
|
}
|
||||||
|
else if (fieldType == typeof(Vector2)) {
|
||||||
|
fieldValue = EditorGUILayout.Vector2Field(fieldName, (Vector2)fieldValue);
|
||||||
|
}
|
||||||
|
else if (fieldType == typeof(Vector3)) {
|
||||||
|
fieldValue = EditorGUILayout.Vector2Field(fieldName, (Vector3)fieldValue);
|
||||||
|
}
|
||||||
|
else if (fieldType == typeof(Vector4)) {
|
||||||
|
fieldValue = EditorGUILayout.Vector2Field(fieldName, (Vector4)fieldValue);
|
||||||
|
}
|
||||||
|
else if (fieldType == typeof(Color)) {
|
||||||
|
fieldValue = EditorGUILayout.ColorField(fieldName, (Color)fieldValue);
|
||||||
|
}
|
||||||
|
else if (fieldType == typeof(AnimationCurve)) {
|
||||||
|
fieldValue = EditorGUILayout.CurveField(fieldName, fieldValue != null ? (AnimationCurve)fieldValue : new AnimationCurve());
|
||||||
|
}
|
||||||
|
else if (fieldType.IsSubclassOf(typeof(UnityEngine.Object)) || fieldType == typeof(UnityEngine.Object)) {
|
||||||
|
fieldValue = EditorGUILayout.ObjectField(fieldName, (UnityEngine.Object)fieldValue, fieldType, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EditorGUI.EndChangeCheck()) {
|
||||||
|
fields[i].SetValue(target, fieldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static FieldInfo[] GetInspectorFields(Node node) {
|
||||||
|
return node.GetType().GetFields().Where(f => f.IsPublic).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool GetAttrib<T>(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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -168,7 +168,9 @@ public partial class NodeEditorWindow {
|
|||||||
|
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
// GUI
|
NodeEditor nodeEditor = GetNodeEditor(node.GetType());
|
||||||
|
nodeEditor.target = node;
|
||||||
|
nodeEditor.OnNodeGUI();
|
||||||
|
|
||||||
GUILayout.EndArea();
|
GUILayout.EndArea();
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +1,50 @@
|
|||||||
using System.Reflection;
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System;
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
/// <summary> Contains reflection-related info </summary>
|
/// <summary> Contains reflection-related info </summary>
|
||||||
public partial class NodeEditorWindow {
|
public partial class NodeEditorWindow {
|
||||||
|
|
||||||
|
private static Dictionary<Type, NodeEditor> customNodeEditor;
|
||||||
public static Type[] nodeTypes { get { return _nodeTypes != null ? _nodeTypes : _nodeTypes = GetNodeTypes(); } }
|
public static Type[] nodeTypes { get { return _nodeTypes != null ? _nodeTypes : _nodeTypes = GetNodeTypes(); } }
|
||||||
private static Type[] _nodeTypes;
|
private static Type[] _nodeTypes;
|
||||||
|
|
||||||
|
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
|
||||||
Type derivedType = typeof(Node);
|
return GetDerivedTypes(typeof(Node));
|
||||||
Assembly assembly = Assembly.GetAssembly(derivedType);
|
}
|
||||||
return assembly.GetTypes().Where(t =>
|
|
||||||
t != derivedType &&
|
public static void CacheCustomNodeEditors(){
|
||||||
derivedType.IsAssignableFrom(t)
|
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;
|
||||||
|
CustomNodeEditorAttribute attrib = attribs[0] as CustomNodeEditorAttribute;
|
||||||
|
customNodeEditor.Add(attrib.inspectedType, Activator.CreateInstance(nodeEditors[i]) as NodeEditor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type[] GetDerivedTypes(Type baseType) {
|
||||||
|
//Get all classes deriving from baseType via reflection
|
||||||
|
Assembly assembly = Assembly.GetAssembly(baseType);
|
||||||
|
return assembly.GetTypes().Where(t =>
|
||||||
|
t != baseType &&
|
||||||
|
baseType.IsAssignableFrom(t)
|
||||||
).ToArray();
|
).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static object ObjectFromType(Type type) {
|
||||||
|
return Activator.CreateInstance(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ public partial class NodeEditorWindow {
|
|||||||
if (DropdownButton("Edit", 50)) EditContextMenu();
|
if (DropdownButton("Edit", 50)) EditContextMenu();
|
||||||
if (DropdownButton("View", 50)) { }
|
if (DropdownButton("View", 50)) { }
|
||||||
if (DropdownButton("Settings", 70)) { }
|
if (DropdownButton("Settings", 70)) { }
|
||||||
if (DropdownButton("Tools", 50)) { }
|
if (DropdownButton("Tools", 50)) ToolsContextMenu();
|
||||||
if (IsHoveringNode) {
|
if (IsHoveringNode) {
|
||||||
GUILayout.Space(20);
|
GUILayout.Space(20);
|
||||||
string hoverInfo = hoveredNode.GetType().ToString();
|
string hoverInfo = hoveredNode.GetType().ToString();
|
||||||
@ -44,4 +44,11 @@ public partial class NodeEditorWindow {
|
|||||||
|
|
||||||
contextMenu.DropDown(new Rect(5f, 17f, 0f, 0f));
|
contextMenu.DropDown(new Rect(5f, 17f, 0f, 0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ToolsContextMenu() {
|
||||||
|
GenericMenu contextMenu = new GenericMenu();
|
||||||
|
contextMenu.AddItem(new GUIContent("Debug Custom Node Editors"), false, () => CacheCustomNodeEditors());
|
||||||
|
|
||||||
|
contextMenu.DropDown(new Rect(5f, 17f, 0f, 0f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,13 +43,6 @@ public partial class NodeEditorWindow : EditorWindow {
|
|||||||
GUI.DragWindow();
|
GUI.DragWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public byte[] ProtoSerialize<T>(T value) {
|
|
||||||
using (var ms = new MemoryStream()) {
|
|
||||||
ProtoBuf.Serializer.Serialize(ms, value);
|
|
||||||
return ms.ToArray();
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
public Vector2 WindowToGridPosition(Vector2 windowPosition) {
|
public Vector2 WindowToGridPosition(Vector2 windowPosition) {
|
||||||
return (windowPosition - (position.size * 0.5f) - (panOffset / zoom)) * zoom;
|
return (windowPosition - (position.size * 0.5f) - (panOffset / zoom)) * zoom;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,8 +41,10 @@ public class NodePort :ISerializationCallbackReceiver{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Connect(NodePort port) {
|
public void Connect(NodePort port) {
|
||||||
|
if (connections == null) connections = new List<NodePort>();
|
||||||
|
if (port == null) { Debug.LogWarning("Cannot connect to null port"); return; }
|
||||||
if (port == this) { Debug.LogWarning("Attempting to connect port to self."); return; }
|
if (port == this) { Debug.LogWarning("Attempting to connect port to self."); return; }
|
||||||
if (connections.Contains(port)) { Debug.LogWarning("Port already connected."); return; }
|
if (connections.Contains(port)) { Debug.LogWarning("Port already connected. "); return; }
|
||||||
if (direction == port.direction) { Debug.LogWarning("Cannot connect two " + (direction == IO.Input ? "input" : "output") + " connections"); return; }
|
if (direction == port.direction) { Debug.LogWarning("Cannot connect two " + (direction == IO.Input ? "input" : "output") + " connections"); return; }
|
||||||
connections.Add(port);
|
connections.Add(port);
|
||||||
port.connections.Add(this);
|
port.connections.Add(this);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user