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

Put NodeEditorReflection into its own static class

This commit is contained in:
Thor Brigsted 2019-07-24 10:04:05 +02:00
parent 93fa101af8
commit 891ecebc3f
8 changed files with 59 additions and 55 deletions

View File

@ -49,7 +49,7 @@ namespace XNodeEditor {
public virtual int GetWidth() { public virtual int GetWidth() {
Type type = target.GetType(); Type type = target.GetType();
int width; int width;
if (NodeEditorWindow.nodeWidth.TryGetValue(type, out width)) return width; if (type.TryGetAttributeWidth(out width)) return width;
else return 208; else return 208;
} }
@ -58,7 +58,7 @@ namespace XNodeEditor {
// Try get color from [NodeTint] attribute // Try get color from [NodeTint] attribute
Type type = target.GetType(); Type type = target.GetType();
Color color; Color color;
if (NodeEditorWindow.nodeTint.TryGetValue(type, out color)) return color; if (type.TryGetAttributeTint(out color)) return color;
// Return default color (grey) // Return default color (grey)
else return DEFAULTCOLOR; else return DEFAULTCOLOR;
} }
@ -84,7 +84,7 @@ namespace XNodeEditor {
// Custom sctions if only one node is selected // Custom sctions if only one node is selected
if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) { if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) {
XNode.Node node = Selection.activeObject as XNode.Node; XNode.Node node = Selection.activeObject as XNode.Node;
NodeEditorWindow.AddCustomContextMenuItems(menu, node); menu.AddCustomContextMenuItems(node);
} }
} }

View File

@ -50,7 +50,7 @@ namespace XNodeEditor.Internal {
editorTypes = new Dictionary<Type, Type>(); editorTypes = new Dictionary<Type, Type>();
//Get all classes deriving from NodeEditor via reflection //Get all classes deriving from NodeEditor via reflection
Type[] nodeEditors = XNodeEditor.NodeEditorWindow.GetDerivedTypes(typeof(T)); Type[] nodeEditors = typeof(T).GetDerivedTypes();
for (int i = 0; i < nodeEditors.Length; i++) { for (int i = 0; i < nodeEditors.Length; i++) {
if (nodeEditors[i].IsAbstract) continue; if (nodeEditors[i].IsAbstract) continue;
var attribs = nodeEditors[i].GetCustomAttributes(typeof(A), false); var attribs = nodeEditors[i].GetCustomAttributes(typeof(A), false);

View File

@ -141,7 +141,7 @@ namespace XNodeEditor {
Color backgroundColor = new Color32(90, 97, 105, 255); Color backgroundColor = new Color32(90, 97, 105, 255);
Color tint; Color tint;
if (NodeEditorWindow.nodeTint.TryGetValue(port.node.GetType(), out tint)) backgroundColor *= tint; if (port.node.GetType().TryGetAttributeTint(out tint)) backgroundColor *= tint;
Color col = NodeEditorWindow.current.graphEditor.GetPortColor(port); Color col = NodeEditorWindow.current.graphEditor.GetPortColor(port);
DrawPortHandle(rect, backgroundColor, col); DrawPortHandle(rect, backgroundColor, col);
@ -153,7 +153,7 @@ namespace XNodeEditor {
private static System.Type GetType(SerializedProperty property) { private static System.Type GetType(SerializedProperty property) {
System.Type parentType = property.serializedObject.targetObject.GetType(); System.Type parentType = property.serializedObject.targetObject.GetType();
System.Reflection.FieldInfo fi = NodeEditorWindow.GetFieldInfo(parentType, property.name); System.Reflection.FieldInfo fi = parentType.GetFieldInfo(property.name);
return fi.FieldType; return fi.FieldType;
} }
@ -197,7 +197,7 @@ namespace XNodeEditor {
Color backgroundColor = new Color32(90, 97, 105, 255); Color backgroundColor = new Color32(90, 97, 105, 255);
Color tint; Color tint;
if (NodeEditorWindow.nodeTint.TryGetValue(port.node.GetType(), out tint)) backgroundColor *= tint; if (port.node.GetType().TryGetAttributeTint(out tint)) backgroundColor *= tint;
Color col = NodeEditorWindow.current.graphEditor.GetPortColor(port); Color col = NodeEditorWindow.current.graphEditor.GetPortColor(port);
DrawPortHandle(rect, backgroundColor, col); DrawPortHandle(rect, backgroundColor, col);
@ -225,7 +225,7 @@ namespace XNodeEditor {
Color backgroundColor = new Color32(90, 97, 105, 255); Color backgroundColor = new Color32(90, 97, 105, 255);
Color tint; Color tint;
if (NodeEditorWindow.nodeTint.TryGetValue(port.node.GetType(), out tint)) backgroundColor *= tint; if (port.node.GetType().TryGetAttributeTint(out tint)) backgroundColor *= tint;
Color col = NodeEditorWindow.current.graphEditor.GetPortColor(port); Color col = NodeEditorWindow.current.graphEditor.GetPortColor(port);
DrawPortHandle(rect, backgroundColor, col); DrawPortHandle(rect, backgroundColor, col);

View File

@ -7,62 +7,55 @@ using UnityEditor;
using UnityEngine; using UnityEngine;
namespace XNodeEditor { namespace XNodeEditor {
/// <summary> Contains reflection-related info </summary> /// <summary> Contains reflection-related extensions built for xNode </summary>
public partial class NodeEditorWindow { public static class NodeEditorReflection {
/// <summary> Custom node tint colors defined with [NodeColor(r, g, b)] </summary> [NonSerialized] private static Dictionary<Type, Color> nodeTint;
public static Dictionary<Type, Color> nodeTint { get { return _nodeTint != null ? _nodeTint : _nodeTint = GetNodeTint(); } } [NonSerialized] private static Dictionary<Type, int> nodeWidth;
[NonSerialized] private static Dictionary<Type, Color> _nodeTint;
/// <summary> Custom node widths defined with [NodeWidth(width)] </summary>
public static Dictionary<Type, int> nodeWidth { get { return _nodeWidth != null ? _nodeWidth : _nodeWidth = GetNodeWidth(); } }
[NonSerialized] private static Dictionary<Type, int> _nodeWidth;
/// <summary> All available node types </summary> /// <summary> All available node types </summary>
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;
private Func<bool> isDocked { /// <summary> Return a delegate used to determine whether window is docked or not. It is faster to cache this delegate than run the reflection required each time. </summary>
get { public static Func<bool> GetIsDockedDelegate(this EditorWindow window) {
if (_isDocked == null) { BindingFlags fullBinding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
BindingFlags fullBinding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; MethodInfo isDockedMethod = typeof(EditorWindow).GetProperty("docked", fullBinding).GetGetMethod(true);
MethodInfo isDockedMethod = typeof(NodeEditorWindow).GetProperty("docked", fullBinding).GetGetMethod(true); return (Func<bool>) Delegate.CreateDelegate(typeof(Func<bool>), window, isDockedMethod);
_isDocked = (Func<bool>) Delegate.CreateDelegate(typeof(Func<bool>), this, isDockedMethod);
}
return _isDocked;
}
} }
private Func<bool> _isDocked;
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(XNode.Node)); return GetDerivedTypes(typeof(XNode.Node));
} }
public static Dictionary<Type, Color> GetNodeTint() { /// <summary> Custom node tint colors defined with [NodeColor(r, g, b)] </summary>
Dictionary<Type, Color> tints = new Dictionary<Type, Color>(); public static bool TryGetAttributeTint(this Type nodeType, out Color tint) {
for (int i = 0; i < nodeTypes.Length; i++) { if (nodeTint == null) {
var attribs = nodeTypes[i].GetCustomAttributes(typeof(XNode.Node.NodeTintAttribute), true); CacheAttributes<Color, XNode.Node.NodeTintAttribute>(ref nodeTint, x => x.color);
if (attribs == null || attribs.Length == 0) continue;
XNode.Node.NodeTintAttribute attrib = attribs[0] as XNode.Node.NodeTintAttribute;
tints.Add(nodeTypes[i], attrib.color);
} }
return tints; return nodeTint.TryGetValue(nodeType, out tint);
} }
public static Dictionary<Type, int> GetNodeWidth() { /// <summary> Get custom node widths defined with [NodeWidth(width)] </summary>
Dictionary<Type, int> widths = new Dictionary<Type, int>(); public static bool TryGetAttributeWidth(this Type nodeType, out int width) {
for (int i = 0; i < nodeTypes.Length; i++) { if (nodeWidth == null) {
var attribs = nodeTypes[i].GetCustomAttributes(typeof(XNode.Node.NodeWidthAttribute), true); CacheAttributes<int, XNode.Node.NodeWidthAttribute>(ref nodeWidth, x => x.width);
if (attribs == null || attribs.Length == 0) continue; }
XNode.Node.NodeWidthAttribute attrib = attribs[0] as XNode.Node.NodeWidthAttribute; return nodeWidth.TryGetValue(nodeType, out width);
widths.Add(nodeTypes[i], attrib.width); }
private static void CacheAttributes<V, A>(ref Dictionary<Type, V> dict, Func<A, V> getter) where A : Attribute {
dict = new Dictionary<Type, V>();
for (int i = 0; i < nodeTypes.Length; i++) {
object[] attribs = nodeTypes[i].GetCustomAttributes(typeof(A), true);
if (attribs == null || attribs.Length == 0) continue;
A attrib = attribs[0] as A;
dict.Add(nodeTypes[i], getter(attrib));
} }
return widths;
} }
/// <summary> Get FieldInfo of a field, including those that are private and/or inherited </summary> /// <summary> Get FieldInfo of a field, including those that are private and/or inherited </summary>
public static FieldInfo GetFieldInfo(Type type, string fieldName) { public static FieldInfo GetFieldInfo(this Type type, string fieldName) {
// If we can't find field in the first run, it's probably a private field in a base class. // If we can't find field in the first run, it's probably a private field in a base class.
FieldInfo field = type.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo field = type.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
// Search base classes for private fields only. Public fields are found above // Search base classes for private fields only. Public fields are found above
@ -71,7 +64,7 @@ namespace XNodeEditor {
} }
/// <summary> Get all classes deriving from baseType via reflection </summary> /// <summary> Get all classes deriving from baseType via reflection </summary>
public static Type[] GetDerivedTypes(Type baseType) { public static Type[] GetDerivedTypes(this Type baseType) {
List<System.Type> types = new List<System.Type>(); List<System.Type> types = new List<System.Type>();
System.Reflection.Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies(); System.Reflection.Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies) { foreach (Assembly assembly in assemblies) {
@ -82,7 +75,8 @@ namespace XNodeEditor {
return types.ToArray(); return types.ToArray();
} }
public static void AddCustomContextMenuItems(GenericMenu contextMenu, object obj) { /// <summary> Find methods marked with the [ContextMenu] attribute and add them to the context menu </summary>
public static void AddCustomContextMenuItems(this GenericMenu contextMenu, object obj) {
KeyValuePair<ContextMenu, MethodInfo>[] items = GetContextMenuMethods(obj); KeyValuePair<ContextMenu, MethodInfo>[] items = GetContextMenuMethods(obj);
if (items.Length != 0) { if (items.Length != 0) {
contextMenu.AddSeparator(""); contextMenu.AddSeparator("");
@ -104,7 +98,7 @@ namespace XNodeEditor {
} }
/// <summary> Call OnValidate on target </summary> /// <summary> Call OnValidate on target </summary>
public static void TriggerOnValidate(UnityEngine.Object target) { public static void TriggerOnValidate(this UnityEngine.Object target) {
System.Reflection.MethodInfo onValidate = null; System.Reflection.MethodInfo onValidate = null;
if (target != null) { if (target != null) {
onValidate = target.GetType().GetMethod("OnValidate", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); onValidate = target.GetType().GetMethod("OnValidate", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

View File

@ -36,7 +36,7 @@ namespace XNodeEditor {
public static bool GetAttrib<T>(Type classType, string fieldName, out T attribOut) where T : Attribute { public static bool GetAttrib<T>(Type classType, string fieldName, out T attribOut) where T : Attribute {
// If we can't find field in the first run, it's probably a private field in a base class. // If we can't find field in the first run, it's probably a private field in a base class.
FieldInfo field = NodeEditorWindow.GetFieldInfo(classType, fieldName); FieldInfo field = classType.GetFieldInfo(fieldName);
// This shouldn't happen. Ever. // This shouldn't happen. Ever.
if (field == null) { if (field == null) {
Debug.LogWarning("Field " + fieldName + " couldnt be found"); Debug.LogWarning("Field " + fieldName + " couldnt be found");

View File

@ -2,6 +2,8 @@ using System.Collections.Generic;
using UnityEditor; using UnityEditor;
using UnityEditor.Callbacks; using UnityEditor.Callbacks;
using UnityEngine; using UnityEngine;
using System;
using Object = UnityEngine.Object;
namespace XNodeEditor { namespace XNodeEditor {
[InitializeOnLoad] [InitializeOnLoad]
@ -14,6 +16,14 @@ namespace XNodeEditor {
[SerializeField] private NodePortReference[] _references = new NodePortReference[0]; [SerializeField] private NodePortReference[] _references = new NodePortReference[0];
[SerializeField] private Rect[] _rects = new Rect[0]; [SerializeField] private Rect[] _rects = new Rect[0];
private Func<bool> isDocked {
get {
if (_isDocked == null) _isDocked = this.GetIsDockedDelegate();
return _isDocked;
}
}
private Func<bool> _isDocked;
[System.Serializable] private class NodePortReference { [System.Serializable] private class NodePortReference {
[SerializeField] private XNode.Node _node; [SerializeField] private XNode.Node _node;
[SerializeField] private string _name; [SerializeField] private string _name;

View File

@ -44,8 +44,8 @@ namespace XNodeEditor {
/// <summary> Add items for the context menu when right-clicking this node. Override to add custom menu items. </summary> /// <summary> Add items for the context menu when right-clicking this node. Override to add custom menu items. </summary>
public virtual void AddContextMenuItems(GenericMenu menu) { public virtual void AddContextMenuItems(GenericMenu menu) {
Vector2 pos = NodeEditorWindow.current.WindowToGridPosition(Event.current.mousePosition); Vector2 pos = NodeEditorWindow.current.WindowToGridPosition(Event.current.mousePosition);
for (int i = 0; i < NodeEditorWindow.nodeTypes.Length; i++) { for (int i = 0; i < NodeEditorReflection.nodeTypes.Length; i++) {
Type type = NodeEditorWindow.nodeTypes[i]; Type type = NodeEditorReflection.nodeTypes[i];
//Get node context menu path //Get node context menu path
string path = GetNodeMenuName(type); string path = GetNodeMenuName(type);
@ -58,8 +58,8 @@ namespace XNodeEditor {
menu.AddSeparator(""); menu.AddSeparator("");
if (NodeEditorWindow.copyBuffer != null && NodeEditorWindow.copyBuffer.Length > 0) menu.AddItem(new GUIContent("Paste"), false, () => NodeEditorWindow.current.PasteNodes(pos)); if (NodeEditorWindow.copyBuffer != null && NodeEditorWindow.copyBuffer.Length > 0) menu.AddItem(new GUIContent("Paste"), false, () => NodeEditorWindow.current.PasteNodes(pos));
else menu.AddDisabledItem(new GUIContent("Paste")); else menu.AddDisabledItem(new GUIContent("Paste"));
menu.AddItem(new GUIContent("Preferences"), false, () => NodeEditorWindow.OpenPreferences()); menu.AddItem(new GUIContent("Preferences"), false, () => NodeEditorReflection.OpenPreferences());
NodeEditorWindow.AddCustomContextMenuItems(menu, target); menu.AddCustomContextMenuItems(target);
} }
public virtual Color GetPortColor(XNode.NodePort port) { public virtual Color GetPortColor(XNode.NodePort port) {

View File

@ -51,7 +51,7 @@ namespace XNodeEditor {
target.name = NodeEditorUtilities.NodeDefaultName(target.GetType()); target.name = NodeEditorUtilities.NodeDefaultName(target.GetType());
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target));
Close(); Close();
NodeEditorWindow.TriggerOnValidate(target); target.TriggerOnValidate();
} }
} }
// Rename asset to input text // Rename asset to input text
@ -60,7 +60,7 @@ namespace XNodeEditor {
target.name = input; target.name = input;
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target));
Close(); Close();
NodeEditorWindow.TriggerOnValidate(target); target.TriggerOnValidate();
} }
} }
} }