mirror of
https://github.com/Siccity/xNode.git
synced 2025-12-20 09:16:01 +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 bool concat;
|
||||
|
||||
[TextArea]
|
||||
public string SomeString;
|
||||
[Header("New stuff")]
|
||||
public Color col;
|
||||
public AnimationCurve anim;
|
||||
public Vector3 vec;
|
||||
protected override void Init() {
|
||||
inputs = new NodePort[2];
|
||||
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;
|
||||
|
||||
[System.Serializable]
|
||||
public class AddNode : Node {
|
||||
public class MathNode : Node {
|
||||
|
||||
public int someValue;
|
||||
public enum MathType { Add, Subtract, Multiply, Divide}
|
||||
public MathType mathType = MathType.Add;
|
||||
|
||||
protected override void Init() {
|
||||
inputs = new NodePort[2];
|
||||
@ -2,11 +2,102 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
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>
|
||||
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();
|
||||
|
||||
// GUI
|
||||
NodeEditor nodeEditor = GetNodeEditor(node.GetType());
|
||||
nodeEditor.target = node;
|
||||
nodeEditor.OnNodeGUI();
|
||||
|
||||
GUILayout.EndArea();
|
||||
|
||||
|
||||
@ -1,20 +1,50 @@
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary> Contains reflection-related info </summary>
|
||||
public partial class NodeEditorWindow {
|
||||
|
||||
private static Dictionary<Type, NodeEditor> customNodeEditor;
|
||||
public static Type[] nodeTypes { get { return _nodeTypes != null ? _nodeTypes : _nodeTypes = GetNodeTypes(); } }
|
||||
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() {
|
||||
//Get all classes deriving from Node via reflection
|
||||
Type derivedType = typeof(Node);
|
||||
Assembly assembly = Assembly.GetAssembly(derivedType);
|
||||
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;
|
||||
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 != derivedType &&
|
||||
derivedType.IsAssignableFrom(t)
|
||||
t != baseType &&
|
||||
baseType.IsAssignableFrom(t)
|
||||
).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("View", 50)) { }
|
||||
if (DropdownButton("Settings", 70)) { }
|
||||
if (DropdownButton("Tools", 50)) { }
|
||||
if (DropdownButton("Tools", 50)) ToolsContextMenu();
|
||||
if (IsHoveringNode) {
|
||||
GUILayout.Space(20);
|
||||
string hoverInfo = hoveredNode.GetType().ToString();
|
||||
@ -44,4 +44,11 @@ public partial class NodeEditorWindow {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/*public byte[] ProtoSerialize<T>(T value) {
|
||||
using (var ms = new MemoryStream()) {
|
||||
ProtoBuf.Serializer.Serialize(ms, value);
|
||||
return ms.ToArray();
|
||||
}
|
||||
}*/
|
||||
|
||||
public Vector2 WindowToGridPosition(Vector2 windowPosition) {
|
||||
return (windowPosition - (position.size * 0.5f) - (panOffset / zoom)) * zoom;
|
||||
}
|
||||
|
||||
@ -41,8 +41,10 @@ public class NodePort :ISerializationCallbackReceiver{
|
||||
}
|
||||
|
||||
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 (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; }
|
||||
connections.Add(port);
|
||||
port.connections.Add(this);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user