mirror of
https://github.com/Siccity/xNode.git
synced 2025-12-20 09:16:01 +08:00
WIP
This commit is contained in:
parent
f03dbeb159
commit
e89671480c
@ -7,11 +7,11 @@ using UnityEngine;
|
||||
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>
|
||||
|
||||
[CustomNodeEditor(typeof(XNode.Node))]
|
||||
public class NodeEditor : XNodeEditor.Internal.NodeEditorBase<NodeEditor, NodeEditor.CustomNodeEditorAttribute, XNode.Node> {
|
||||
[CustomNodeEditor(typeof(XNode.INode))]
|
||||
public class NodeEditor : XNodeEditor.Internal.NodeEditorBase<NodeEditor, NodeEditor.CustomNodeEditorAttribute, XNode.INode> {
|
||||
|
||||
/// <summary> Fires every whenever a node was modified through the editor </summary>
|
||||
public static Action<XNode.Node> onUpdateNode;
|
||||
public static Action<XNode.INode> onUpdateNode;
|
||||
public static Dictionary<XNode.NodePort, Vector2> portPositions;
|
||||
|
||||
public virtual void OnHeaderGUI() {
|
||||
@ -67,9 +67,9 @@ namespace XNodeEditor {
|
||||
/// <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) {
|
||||
// Actions if only one node is selected
|
||||
if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) {
|
||||
XNode.Node node = Selection.activeObject as XNode.Node;
|
||||
menu.AddItem(new GUIContent("Move To Top"), false, () => NodeEditorWindow.current.MoveNodeToTop(node));
|
||||
if (Selection.objects.Length == 1 && Selection.activeObject is XNode.INode) {
|
||||
XNode.INode node = Selection.activeObject as XNode.INode;
|
||||
menu.AddItem(new GUIContent("Move To Top"), false, () => node.Graph.MoveNodeToTop(node));
|
||||
menu.AddItem(new GUIContent("Rename"), false, NodeEditorWindow.current.RenameSelectedNode);
|
||||
}
|
||||
|
||||
@ -78,8 +78,8 @@ namespace XNodeEditor {
|
||||
menu.AddItem(new GUIContent("Remove"), false, NodeEditorWindow.current.RemoveSelectedNodes);
|
||||
|
||||
// Custom sctions if only one node is selected
|
||||
if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) {
|
||||
XNode.Node node = Selection.activeObject as XNode.Node;
|
||||
if (Selection.objects.Length == 1 && Selection.activeObject is XNode.INode) {
|
||||
XNode.INode node = Selection.activeObject as XNode.INode;
|
||||
NodeEditorWindow.AddCustomContextMenuItems(menu, node);
|
||||
}
|
||||
}
|
||||
@ -93,7 +93,7 @@ namespace XNodeEditor {
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class CustomNodeEditorAttribute : Attribute,
|
||||
XNodeEditor.Internal.NodeEditorBase<NodeEditor, NodeEditor.CustomNodeEditorAttribute, XNode.Node>.INodeEditorAttrib {
|
||||
XNodeEditor.Internal.NodeEditorBase<NodeEditor, NodeEditor.CustomNodeEditorAttribute, XNode.INode>.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>
|
||||
|
||||
@ -83,15 +83,17 @@ namespace XNodeEditor {
|
||||
for (int i = 0; i < Selection.objects.Length; i++) {
|
||||
if (Selection.objects[i] is XNode.INode) {
|
||||
XNode.INode node = Selection.objects[i] as XNode.INode;
|
||||
Vector2 initial = node.position;
|
||||
node.position = mousePos + dragOffset[i];
|
||||
Vector2 initial = node.Position;
|
||||
node.Position = mousePos + dragOffset[i];
|
||||
if (gridSnap) {
|
||||
node.position.x = (Mathf.Round((node.position.x + 8) / 16) * 16) - 8;
|
||||
node.position.y = (Mathf.Round((node.position.y + 8) / 16) * 16) - 8;
|
||||
Vector2 position = node.Position;
|
||||
position.x = (Mathf.Round((node.Position.x + 8) / 16) * 16) - 8;
|
||||
position.y = (Mathf.Round((node.Position.y + 8) / 16) * 16) - 8;
|
||||
node.Position = position;
|
||||
}
|
||||
|
||||
// Offset portConnectionPoints instantly if a node is dragged so they aren't delayed by a frame.
|
||||
Vector2 offset = node.position - initial;
|
||||
Vector2 offset = node.Position - initial;
|
||||
if (offset.sqrMagnitude > 0) {
|
||||
foreach (XNode.NodePort output in node.Outputs) {
|
||||
Rect rect;
|
||||
@ -163,7 +165,7 @@ namespace XNodeEditor {
|
||||
}
|
||||
} else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) {
|
||||
// If mousedown on node header, select or deselect
|
||||
if (!Selection.Contains(hoveredNode)) {
|
||||
if (!Selection.Contains((UnityEngine.Object)hoveredNode)) {
|
||||
SelectNode(hoveredNode, e.control || e.shift);
|
||||
if (!e.control && !e.shift) selectedReroutes.Clear();
|
||||
} else if (e.control || e.shift) DeselectNode(hoveredNode);
|
||||
@ -243,7 +245,7 @@ namespace XNodeEditor {
|
||||
// Double click to center node
|
||||
if (isDoubleClick) {
|
||||
Vector2 nodeDimension = nodeSizes.ContainsKey(hoveredNode) ? nodeSizes[hoveredNode] / 2 : Vector2.zero;
|
||||
panOffset = -hoveredNode.position - nodeDimension;
|
||||
panOffset = -hoverednode.Position - nodeDimension;
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,7 +269,7 @@ namespace XNodeEditor {
|
||||
} else if (IsHoveringPort) {
|
||||
ShowPortContextMenu(hoveredPort);
|
||||
} else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) {
|
||||
if (!Selection.Contains(hoveredNode)) SelectNode(hoveredNode, false);
|
||||
if (!Selection.Contains((UnityEngine.Object)hoveredNode)) SelectNode(hoveredNode, false);
|
||||
GenericMenu menu = new GenericMenu();
|
||||
NodeEditor.GetEditor(hoveredNode, this).AddContextMenuItems(menu);
|
||||
menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero));
|
||||
@ -330,7 +332,7 @@ namespace XNodeEditor {
|
||||
for (int i = 0; i < Selection.objects.Length; i++) {
|
||||
if (Selection.objects[i] is XNode.INode) {
|
||||
XNode.INode node = Selection.objects[i] as XNode.INode;
|
||||
dragOffset[i] = node.position - WindowToGridPosition(current.mousePosition);
|
||||
dragOffset[i] = node.Position - WindowToGridPosition(current.mousePosition);
|
||||
}
|
||||
}
|
||||
|
||||
@ -355,8 +357,8 @@ namespace XNodeEditor {
|
||||
}
|
||||
selectedReroutes.Clear();
|
||||
foreach (UnityEngine.Object item in Selection.objects) {
|
||||
if (item is XNode.Node) {
|
||||
XNode.Node node = item as XNode.Node;
|
||||
if (item is XNode.INode) {
|
||||
XNode.INode node = item as XNode.INode;
|
||||
graphEditor.RemoveNode(node);
|
||||
}
|
||||
}
|
||||
@ -364,8 +366,8 @@ namespace XNodeEditor {
|
||||
|
||||
/// <summary> Initiate a rename on the currently selected node </summary>
|
||||
public void RenameSelectedNode() {
|
||||
if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) {
|
||||
XNode.Node node = Selection.activeObject as XNode.Node;
|
||||
if (Selection.objects.Length == 1 && Selection.activeObject is XNode.INode) {
|
||||
XNode.INode node = Selection.activeObject as XNode.INode;
|
||||
Vector2 size;
|
||||
if (nodeSizes.TryGetValue(node, out size)) {
|
||||
RenamePopup.Show(Selection.activeObject, size.x);
|
||||
@ -375,41 +377,32 @@ namespace XNodeEditor {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Draw this node on top of other nodes by placing it last in the graph.nodes list </summary>
|
||||
public void MoveNodeToTop(XNode.Node node) {
|
||||
int index;
|
||||
while ((index = graph.nodes.IndexOf(node)) != graph.nodes.Count - 1) {
|
||||
graph.nodes[index] = graph.nodes[index + 1];
|
||||
graph.nodes[index + 1] = node;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Duplicate selected nodes and select the duplicates </summary>
|
||||
public void DuplicateSelectedNodes() {
|
||||
UnityEngine.Object[] newNodes = new UnityEngine.Object[Selection.objects.Length];
|
||||
Dictionary<XNode.Node, XNode.Node> substitutes = new Dictionary<XNode.Node, XNode.Node>();
|
||||
Dictionary<XNode.INode, XNode.INode> substitutes = new Dictionary<XNode.INode, XNode.INode>();
|
||||
for (int i = 0; i < Selection.objects.Length; i++) {
|
||||
if (Selection.objects[i] is XNode.Node) {
|
||||
XNode.Node srcNode = Selection.objects[i] as XNode.Node;
|
||||
if (srcNode.graph != graph) continue; // ignore nodes selected in another graph
|
||||
XNode.Node newNode = graphEditor.CopyNode(srcNode);
|
||||
if (Selection.objects[i] is XNode.INode) {
|
||||
XNode.INode srcNode = Selection.objects[i] as XNode.INode;
|
||||
if (srcNode.Graph != graph) continue; // ignore nodes selected in another graph
|
||||
XNode.INode newNode = graphEditor.CopyNode(srcNode);
|
||||
substitutes.Add(srcNode, newNode);
|
||||
newNode.position = srcNode.position + new Vector2(30, 30);
|
||||
newnode.Position = srcnode.Position + new Vector2(30, 30);
|
||||
newNodes[i] = newNode;
|
||||
}
|
||||
}
|
||||
|
||||
// Walk through the selected nodes again, recreate connections, using the new nodes
|
||||
for (int i = 0; i < Selection.objects.Length; i++) {
|
||||
if (Selection.objects[i] is XNode.Node) {
|
||||
XNode.Node srcNode = Selection.objects[i] as XNode.Node;
|
||||
if (Selection.objects[i] is XNode.INode) {
|
||||
XNode.INode srcNode = Selection.objects[i] as XNode.INode;
|
||||
if (srcNode.graph != graph) continue; // ignore nodes selected in another graph
|
||||
foreach (XNode.NodePort port in srcNode.Ports) {
|
||||
for (int c = 0; c < port.ConnectionCount; c++) {
|
||||
XNode.NodePort inputPort = port.direction == XNode.NodePort.IO.Input ? port : port.GetConnection(c);
|
||||
XNode.NodePort outputPort = port.direction == XNode.NodePort.IO.Output ? port : port.GetConnection(c);
|
||||
|
||||
XNode.Node newNodeIn, newNodeOut;
|
||||
XNode.INode newNodeIn, newNodeOut;
|
||||
if (substitutes.TryGetValue(inputPort.node, out newNodeIn) && substitutes.TryGetValue(outputPort.node, out newNodeOut)) {
|
||||
newNodeIn.UpdateStaticPorts();
|
||||
newNodeOut.UpdateStaticPorts();
|
||||
@ -459,10 +452,10 @@ namespace XNodeEditor {
|
||||
}
|
||||
}
|
||||
|
||||
bool IsHoveringTitle(XNode.Node node) {
|
||||
bool IsHoveringTitle(XNode.INode node) {
|
||||
Vector2 mousePos = Event.current.mousePosition;
|
||||
//Get node position
|
||||
Vector2 nodePos = GridToWindowPosition(node.position);
|
||||
Vector2 nodePos = GridToWindowPosition(node.Position);
|
||||
float width;
|
||||
Vector2 size;
|
||||
if (nodeSizes.TryGetValue(node, out size)) width = size.x;
|
||||
|
||||
@ -17,7 +17,7 @@ namespace XNodeEditor {
|
||||
// Check script type. Return if deleting a non-node script
|
||||
UnityEditor.MonoScript script = obj as UnityEditor.MonoScript;
|
||||
System.Type scriptType = script.GetClass ();
|
||||
if (scriptType == null || (scriptType != typeof (XNode.Node) && !scriptType.IsSubclassOf (typeof (XNode.Node)))) return AssetDeleteResult.DidNotDelete;
|
||||
if (scriptType == null || (scriptType != typeof (XNode.INode) && !scriptType.IsSubclassOf (typeof (XNode.INode)))) return AssetDeleteResult.DidNotDelete;
|
||||
|
||||
// Find all ScriptableObjects using this script
|
||||
string[] guids = AssetDatabase.FindAssets ("t:" + scriptType);
|
||||
@ -25,7 +25,7 @@ namespace XNodeEditor {
|
||||
string assetpath = AssetDatabase.GUIDToAssetPath (guids[i]);
|
||||
Object[] objs = AssetDatabase.LoadAllAssetRepresentationsAtPath (assetpath);
|
||||
for (int k = 0; k < objs.Length; k++) {
|
||||
XNode.Node node = objs[k] as XNode.Node;
|
||||
XNode.INode node = objs[k] as XNode.INode;
|
||||
if (node.GetType () == scriptType) {
|
||||
if (node != null && node.graph != null) {
|
||||
// Delete the node and notify the user
|
||||
@ -51,7 +51,7 @@ namespace XNodeEditor {
|
||||
Object[] objs = AssetDatabase.LoadAllAssetRepresentationsAtPath (assetpath);
|
||||
// Ensure that all sub node assets are present in the graph node list
|
||||
for (int u = 0; u < objs.Length; u++) {
|
||||
if (!graph.nodes.Contains (objs[u] as XNode.Node)) graph.nodes.Add(objs[u] as XNode.Node);
|
||||
if (!graph.nodes.Contains (objs[u] as XNode.INode)) graph.nodes.Add(objs[u] as XNode.INode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,8 +9,8 @@ namespace XNodeEditor.Internal {
|
||||
/// <summary> Handles caching of custom editor classes and their target types. Accessible with GetEditor(Type type) </summary>
|
||||
/// <typeparam name="T">Editor Type. Should be the type of the deriving script itself (eg. NodeEditor) </typeparam>
|
||||
/// <typeparam name="A">Attribute Type. The attribute used to connect with the runtime type (eg. CustomNodeEditorAttribute) </typeparam>
|
||||
/// <typeparam name="K">Runtime Type. The ScriptableObject this can be an editor for (eg. Node) </typeparam>
|
||||
public abstract class NodeEditorBase<T, A, K> : Editor where A : Attribute, NodeEditorBase<T, A, K>.INodeEditorAttrib where T : NodeEditorBase<T, A, K> where K : ScriptableObject {
|
||||
/// <typeparam name="K">Runtime Type. The Object this can be an editor for (eg. Node) </typeparam>
|
||||
public abstract class NodeEditorBase<T, A, K> : Editor where A : Attribute, NodeEditorBase<T, A, K>.INodeEditorAttrib where T : NodeEditorBase<T, A, K> where K : UnityEngine.Object {
|
||||
/// <summary> Custom editors defined with [CustomNodeEditor] </summary>
|
||||
private static Dictionary<Type, Type> editorTypes;
|
||||
private static Dictionary<K, T> editors = new Dictionary<K, T>();
|
||||
|
||||
@ -303,8 +303,8 @@ namespace XNodeEditor {
|
||||
|
||||
NodeEditor.portPositions = new Dictionary<XNode.NodePort, Vector2>();
|
||||
|
||||
//Get node position
|
||||
Vector2 nodePos = GridToWindowPositionNoClipped(node.position);
|
||||
//Get node.Position
|
||||
Vector2 nodePos = GridToWindowPositionNoClipped(node.Position);
|
||||
|
||||
GUILayout.BeginArea(new Rect(nodePos, new Vector2(nodeEditor.GetWidth(), 4000)));
|
||||
|
||||
@ -349,7 +349,7 @@ namespace XNodeEditor {
|
||||
|
||||
foreach (var kvp in NodeEditor.portPositions) {
|
||||
Vector2 portHandlePos = kvp.Value;
|
||||
portHandlePos += node.position;
|
||||
portHandlePos += node.Position;
|
||||
Rect rect = new Rect(portHandlePos.x - 8, portHandlePos.y - 8, 16, 16);
|
||||
if (portConnectionPoints.ContainsKey(kvp.Key)) portConnectionPoints[kvp.Key] = rect;
|
||||
else portConnectionPoints.Add(kvp.Key, rect);
|
||||
@ -400,7 +400,7 @@ namespace XNodeEditor {
|
||||
|
||||
private bool ShouldBeCulled(XNode.Node node) {
|
||||
|
||||
Vector2 nodePos = GridToWindowPositionNoClipped(node.position);
|
||||
Vector2 nodePos = GridToWindowPositionNoClipped(node.Position);
|
||||
if (nodePos.x / _zoom > position.width) return true; // Right
|
||||
else if (nodePos.y / _zoom > position.height) return true; // Bottom
|
||||
else if (nodeSizes.ContainsKey(node)) {
|
||||
|
||||
@ -22,7 +22,7 @@ namespace XNodeEditor {
|
||||
/// <summary> Make a field for a serialized property. Automatically displays relevant node port. </summary>
|
||||
public static void PropertyField(SerializedProperty property, GUIContent label, bool includeChildren = true, params GUILayoutOption[] options) {
|
||||
if (property == null) throw new NullReferenceException();
|
||||
XNode.Node node = property.serializedObject.targetObject as XNode.Node;
|
||||
XNode.INode node = property.serializedObject.targetObject as XNode.INode;
|
||||
XNode.NodePort port = node.GetPort(property.name);
|
||||
PropertyField(property, label, port, includeChildren);
|
||||
}
|
||||
@ -285,7 +285,7 @@ namespace XNodeEditor {
|
||||
/// <param name="connectionType">Connection type of added dynamic ports</param>
|
||||
/// <param name="onCreation">Called on the list on creation. Use this if you want to customize the created ReorderableList</param>
|
||||
public static void DynamicPortList(string fieldName, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, XNode.Node.TypeConstraint typeConstraint = XNode.Node.TypeConstraint.None, Action<ReorderableList> onCreation = null) {
|
||||
XNode.Node node = serializedObject.targetObject as XNode.Node;
|
||||
XNode.INode node = serializedObject.targetObject as XNode.INode;
|
||||
|
||||
var indexedPorts = node.DynamicPorts.Select(x => {
|
||||
string[] split = x.fieldName.Split(' ');
|
||||
@ -315,9 +315,9 @@ namespace XNodeEditor {
|
||||
list.DoLayoutList();
|
||||
}
|
||||
|
||||
private static ReorderableList CreateReorderableList(string fieldName, List<XNode.NodePort> dynamicPorts, SerializedProperty arrayData, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType, XNode.Node.TypeConstraint typeConstraint, Action<ReorderableList> onCreation) {
|
||||
private static ReorderableList CreateReorderableList(string fieldName, List<XNode.NodePort> dynamicPorts, SerializedProperty arrayData, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.INode.ConnectionType connectionType, XNode.INode.TypeConstraint typeConstraint, Action<ReorderableList> onCreation) {
|
||||
bool hasArrayData = arrayData != null && arrayData.isArray;
|
||||
XNode.Node node = serializedObject.targetObject as XNode.Node;
|
||||
XNode.INode node = serializedObject.targetObject as XNode.INode;
|
||||
ReorderableList list = new ReorderableList(dynamicPorts, null, true, true, true, true);
|
||||
string label = arrayData != null ? arrayData.displayName : ObjectNames.NicifyVariableName(fieldName);
|
||||
|
||||
@ -404,7 +404,7 @@ namespace XNodeEditor {
|
||||
int i = 0;
|
||||
while (node.HasPort(newName)) newName = fieldName + " " + (++i);
|
||||
|
||||
if (io == XNode.NodePort.IO.Output) node.AddDynamicOutput(type, connectionType, XNode.Node.TypeConstraint.None, newName);
|
||||
if (io == XNode.NodePort.IO.Output) node.AddDynamicOutput(type, connectionType, XNode.INode.TypeConstraint.None, newName);
|
||||
else node.AddDynamicInput(type, connectionType, typeConstraint, newName);
|
||||
serializedObject.Update();
|
||||
EditorUtility.SetDirty(node);
|
||||
|
||||
@ -47,7 +47,7 @@ namespace XNodeEditor {
|
||||
UnityEngine.Object[] objs = AssetDatabase.LoadAllAssetRepresentationsAtPath(assetpath);
|
||||
// Loop through graph asset and search for nodes (nodes exist inside the graph asset as sub-assets)
|
||||
for (int k = 0; k < objs.Length; k++) {
|
||||
XNode.Node node = objs[k] as XNode.Node;
|
||||
XNode.INode node = objs[k] as XNode.INode;
|
||||
if (node != null) node.UpdateStaticPorts();
|
||||
}
|
||||
}
|
||||
@ -55,15 +55,15 @@ namespace XNodeEditor {
|
||||
|
||||
public static Type[] GetNodeTypes() {
|
||||
//Get all classes deriving from Node via reflection
|
||||
return GetDerivedTypes(typeof(XNode.Node));
|
||||
return GetDerivedTypes(typeof(XNode.INode));
|
||||
}
|
||||
|
||||
public static Dictionary<Type, Color> GetNodeTint() {
|
||||
Dictionary<Type, Color> tints = new Dictionary<Type, Color>();
|
||||
for (int i = 0; i < nodeTypes.Length; i++) {
|
||||
var attribs = nodeTypes[i].GetCustomAttributes(typeof(XNode.Node.NodeTintAttribute), true);
|
||||
var attribs = nodeTypes[i].GetCustomAttributes(typeof(XNode.INode.NodeTintAttribute), true);
|
||||
if (attribs == null || attribs.Length == 0) continue;
|
||||
XNode.Node.NodeTintAttribute attrib = attribs[0] as XNode.Node.NodeTintAttribute;
|
||||
XNode.INode.NodeTintAttribute attrib = attribs[0] as XNode.INode.NodeTintAttribute;
|
||||
tints.Add(nodeTypes[i], attrib.color);
|
||||
}
|
||||
return tints;
|
||||
@ -72,9 +72,9 @@ namespace XNodeEditor {
|
||||
public static Dictionary<Type, int> GetNodeWidth() {
|
||||
Dictionary<Type, int> widths = new Dictionary<Type, int>();
|
||||
for (int i = 0; i < nodeTypes.Length; i++) {
|
||||
var attribs = nodeTypes[i].GetCustomAttributes(typeof(XNode.Node.NodeWidthAttribute), true);
|
||||
var attribs = nodeTypes[i].GetCustomAttributes(typeof(XNode.INode.NodeWidthAttribute), true);
|
||||
if (attribs == null || attribs.Length == 0) continue;
|
||||
XNode.Node.NodeWidthAttribute attrib = attribs[0] as XNode.Node.NodeWidthAttribute;
|
||||
XNode.INode.NodeWidthAttribute attrib = attribs[0] as XNode.INode.NodeWidthAttribute;
|
||||
widths.Add(nodeTypes[i], attrib.width);
|
||||
}
|
||||
return widths;
|
||||
@ -85,7 +85,7 @@ namespace XNodeEditor {
|
||||
// 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);
|
||||
// Search base classes for private fields only. Public fields are found above
|
||||
while (field == null && (type = type.BaseType) != typeof(XNode.Node)) field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
while (field == null && (type = type.BaseType) != typeof(XNode.INode)) field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
return field;
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ namespace XNodeEditor {
|
||||
private static Texture2D _dot;
|
||||
public static Texture2D dotOuter { get { return _dotOuter != null ? _dotOuter : _dotOuter = Resources.Load<Texture2D>("xnode_dot_outer"); } }
|
||||
private static Texture2D _dotOuter;
|
||||
public static Texture2D nodeBody { get { return _nodeBody != null ? _nodeBody : _nodeBody = Resources.Load<Texture2D>("xnode_node"); } }
|
||||
public static Texture2D nodeBody { get { return _nodeBody != null ? _nodeBody : _nodeBody = Resources.Load<Texture2D>("XNode.INode"); } }
|
||||
private static Texture2D _nodeBody;
|
||||
public static Texture2D nodeHighlight { get { return _nodeHighlight != null ? _nodeHighlight : _nodeHighlight = Resources.Load<Texture2D>("xnode_node_highlight"); } }
|
||||
private static Texture2D _nodeHighlight;
|
||||
|
||||
@ -134,7 +134,7 @@ namespace XNodeEditor {
|
||||
}
|
||||
|
||||
/// <summary>Creates a new C# Class.</summary>
|
||||
[MenuItem("Assets/Create/xNode/Node C# Script", false, 89)]
|
||||
[MenuItem("Assets/Create/XNode.INode C# Script", false, 89)]
|
||||
private static void CreateNode() {
|
||||
string[] guids = AssetDatabase.FindAssets("xNode_NodeTemplate.cs");
|
||||
if (guids.Length == 0) {
|
||||
|
||||
@ -8,7 +8,7 @@ namespace XNodeEditor {
|
||||
public partial class NodeEditorWindow : EditorWindow {
|
||||
public static NodeEditorWindow current;
|
||||
|
||||
/// <summary> Stores node positions for all nodePorts. </summary>
|
||||
/// <summary> Stores node.Positions for all nodePorts. </summary>
|
||||
public Dictionary<XNode.NodePort, Rect> portConnectionPoints { get { return _portConnectionPoints; } }
|
||||
private Dictionary<XNode.NodePort, Rect> _portConnectionPoints = new Dictionary<XNode.NodePort, Rect>();
|
||||
[SerializeField] private NodePortReference[] _references = new NodePortReference[0];
|
||||
@ -56,9 +56,9 @@ namespace XNodeEditor {
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<XNode.Node, Vector2> nodeSizes { get { return _nodeSizes; } }
|
||||
private Dictionary<XNode.Node, Vector2> _nodeSizes = new Dictionary<XNode.Node, Vector2>();
|
||||
public XNode.NodeGraph graph;
|
||||
public Dictionary<XNode.INode, Vector2> nodeSizes { get { return _nodeSizes; } }
|
||||
private Dictionary<XNode.INode, Vector2> _nodeSizes = new Dictionary<XNode.INode, Vector2>();
|
||||
public XNode.INodeGraph graph;
|
||||
public Vector2 panOffset { get { return _panOffset; } set { _panOffset = value; Repaint(); } }
|
||||
private Vector2 _panOffset;
|
||||
public float zoom { get { return _zoom; } set { _zoom = Mathf.Clamp(value, 1f, NodeEditorPreferences.GetSettings().zoomOutLimit); Repaint(); } }
|
||||
@ -78,7 +78,7 @@ namespace XNodeEditor {
|
||||
|
||||
/// <summary> Handle Selection Change events</summary>
|
||||
private static void OnSelectionChanged() {
|
||||
XNode.NodeGraph nodeGraph = Selection.activeObject as XNode.NodeGraph;
|
||||
XNode.INodeGraph nodeGraph = Selection.activeObject as XNode.INodeGraph;
|
||||
if (nodeGraph && !AssetDatabase.Contains(nodeGraph)) {
|
||||
Open(nodeGraph);
|
||||
}
|
||||
@ -113,7 +113,7 @@ namespace XNodeEditor {
|
||||
string path = EditorUtility.SaveFilePanelInProject("Save NodeGraph", "NewNodeGraph", "asset", "");
|
||||
if (string.IsNullOrEmpty(path)) return;
|
||||
else {
|
||||
XNode.NodeGraph existingGraph = AssetDatabase.LoadAssetAtPath<XNode.NodeGraph>(path);
|
||||
XNode.INodeGraph existingGraph = AssetDatabase.LoadAssetAtPath<XNode.INodeGraph>(path);
|
||||
if (existingGraph != null) AssetDatabase.DeleteAsset(path);
|
||||
AssetDatabase.CreateAsset(graph, path);
|
||||
EditorUtility.SetDirty(graph);
|
||||
@ -152,7 +152,7 @@ namespace XNodeEditor {
|
||||
return new Vector2(xOffset, yOffset);
|
||||
}
|
||||
|
||||
public void SelectNode(XNode.Node node, bool add) {
|
||||
public void SelectNode(XNode.INode node, bool add) {
|
||||
if (add) {
|
||||
List<Object> selection = new List<Object>(Selection.objects);
|
||||
selection.Add(node);
|
||||
@ -160,7 +160,7 @@ namespace XNodeEditor {
|
||||
} else Selection.objects = new Object[] { node };
|
||||
}
|
||||
|
||||
public void DeselectNode(XNode.Node node) {
|
||||
public void DeselectNode(XNode.INode node) {
|
||||
List<Object> selection = new List<Object>(Selection.objects);
|
||||
selection.Remove(node);
|
||||
Selection.objects = selection.ToArray();
|
||||
@ -168,7 +168,7 @@ namespace XNodeEditor {
|
||||
|
||||
[OnOpenAsset(0)]
|
||||
public static bool OnOpen(int instanceID, int line) {
|
||||
XNode.NodeGraph nodeGraph = EditorUtility.InstanceIDToObject(instanceID) as XNode.NodeGraph;
|
||||
XNode.INodeGraph nodeGraph = EditorUtility.InstanceIDToObject(instanceID) as XNode.INodeGraph;
|
||||
if (nodeGraph != null) {
|
||||
Open(nodeGraph);
|
||||
return true;
|
||||
@ -177,7 +177,7 @@ namespace XNodeEditor {
|
||||
}
|
||||
|
||||
/// <summary>Open the provided graph in the NodeEditor</summary>
|
||||
public static void Open(XNode.NodeGraph graph) {
|
||||
public static void Open(XNode.INodeGraph graph) {
|
||||
if (!graph) return;
|
||||
|
||||
NodeEditorWindow w = GetWindow(typeof(NodeEditorWindow), false, "xNode", true) as NodeEditorWindow;
|
||||
|
||||
@ -34,7 +34,7 @@ namespace XNodeEditor {
|
||||
/// <summary> Returns context node menu path. Null or empty strings for hidden nodes. </summary>
|
||||
public virtual string GetNodeMenuName(Type type) {
|
||||
//Check if type has the CreateNodeMenuAttribute
|
||||
XNode.Node.CreateNodeMenuAttribute attrib;
|
||||
XNode.INode.CreateNodeMenuAttribute attrib;
|
||||
if (NodeEditorUtilities.GetAttrib(type, out attrib)) // Return custom path
|
||||
return attrib.menuName;
|
||||
else // Return generated path
|
||||
@ -70,8 +70,8 @@ namespace XNodeEditor {
|
||||
|
||||
/// <summary> Create a node and save it in the graph asset </summary>
|
||||
public virtual void CreateNode(Type type, Vector2 position) {
|
||||
XNode.Node node = target.AddNode(type);
|
||||
node.position = position;
|
||||
XNode.INode node = target.AddNode(type);
|
||||
node.Position = position;
|
||||
if (string.IsNullOrEmpty(node.name)) node.name = UnityEditor.ObjectNames.NicifyVariableName(type.Name);
|
||||
AssetDatabase.AddObjectToAsset(node, target);
|
||||
if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();
|
||||
@ -79,8 +79,8 @@ namespace XNodeEditor {
|
||||
}
|
||||
|
||||
/// <summary> Creates a copy of the original node in the graph </summary>
|
||||
public XNode.Node CopyNode(XNode.Node original) {
|
||||
XNode.Node node = target.CopyNode(original);
|
||||
public XNode.INode CopyNode(XNode.INode original) {
|
||||
XNode.INode node = target.CopyNode(original);
|
||||
node.name = original.name;
|
||||
AssetDatabase.AddObjectToAsset(node, target);
|
||||
if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();
|
||||
@ -88,7 +88,7 @@ namespace XNodeEditor {
|
||||
}
|
||||
|
||||
/// <summary> Safely remove a node and all its connections. </summary>
|
||||
public void RemoveNode(XNode.Node node) {
|
||||
public void RemoveNode(XNode.INode node) {
|
||||
UnityEngine.Object.DestroyImmediate(node, true);
|
||||
target.RemoveNode(node);
|
||||
if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();
|
||||
|
||||
@ -5,7 +5,12 @@ using XNode;
|
||||
|
||||
public class #SCRIPTNAME# : Node {
|
||||
|
||||
// Use OnEnable for initialization
|
||||
// Reset is called on creation
|
||||
private void Reset() {
|
||||
#NOTRIM#
|
||||
}
|
||||
|
||||
// OnEnable is called on load
|
||||
private void OnEnable() {
|
||||
#NOTRIM#
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ using UnityEngine;
|
||||
|
||||
namespace XNode {
|
||||
public interface INode {
|
||||
string name { get; set; }
|
||||
string Name { get; set; }
|
||||
INodeGraph Graph { get; }
|
||||
Vector2 Position { get; set; }
|
||||
object GetValue(NodePort port);
|
||||
@ -15,8 +15,8 @@ namespace XNode {
|
||||
IEnumerable<NodePort> Outputs { get; }
|
||||
IEnumerable<NodePort> Inputs { get; }
|
||||
IEnumerable<NodePort> InstancePorts { get; }
|
||||
NodePort AddDynamicOutput(Type type, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = Node.TypeConstraint.None, string fieldName = null);
|
||||
NodePort AddDynamicInput(Type type, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = Node.TypeConstraint.None, string fieldName = null);
|
||||
NodePort AddDynamicPort(Type type, NodePort.IO direction, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = Node.TypeConstraint.None, string fieldName = null);
|
||||
NodePort RemoveDynamicPort(string fieldName);
|
||||
NodePort GetInputPort(string fieldName);
|
||||
NodePort GetOutputPort(string fieldName);
|
||||
void OnCreateConnection(NodePort from, NodePort to);
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace XNode {
|
||||
/// <summary> Used by advanced extensions that need to alter the base classes of NodeGraphs </summary>
|
||||
public interface INodeGraph {
|
||||
int NodesCount { get; }
|
||||
void MoveNodeToTop(INode node);
|
||||
INode[] GetNodes();
|
||||
IEnumerable<INode> Nodes { get; }
|
||||
INode AddNode(Type type);
|
||||
INode CopyNode(INode original);
|
||||
void RemoveNode(INode node);
|
||||
|
||||
@ -92,6 +92,12 @@ namespace XNode {
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Interface implementation
|
||||
string INode.Name { get { return name; } set { name = value; } }
|
||||
INodeGraph INode.Graph { get { return graph; } }
|
||||
Vector2 INode.Position { get { return position; } set { position = value; } }
|
||||
#endregion
|
||||
|
||||
/// <summary> Iterate over all ports on this node. </summary>
|
||||
public IEnumerable<NodePort> Ports { get { foreach (NodePort port in ports.Values) yield return port; } }
|
||||
/// <summary> Iterate over all outputs on this node. </summary>
|
||||
@ -105,9 +111,7 @@ namespace XNode {
|
||||
/// <summary> Iterate over all dynamic inputs on this node. </summary>
|
||||
public IEnumerable<NodePort> DynamicInputs { get { foreach (NodePort port in Ports) { if (port.IsDynamic && port.IsInput) yield return port; } } }
|
||||
/// <summary> Parent <see cref="NodeGraph"/> </summary>
|
||||
public INodeGraph Graph { get { return graph; } }
|
||||
/// <summary> Parent <see cref="NodeGraph"/> </summary>
|
||||
[SerializeField] private NodeGraph graph;
|
||||
[SerializeField] public NodeGraph graph;
|
||||
/// <summary> Position on the <see cref="NodeGraph"/> </summary>
|
||||
[SerializeField] public Vector2 position;
|
||||
/// <summary> It is recommended not to modify these at hand. Instead, see <see cref="InputAttribute"/> and <see cref="OutputAttribute"/> </summary>
|
||||
@ -136,20 +140,20 @@ namespace XNode {
|
||||
/// <seealso cref="AddInstancePort"/>
|
||||
/// <seealso cref="AddInstanceOutput"/>
|
||||
public NodePort AddDynamicInput(Type type, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None, string fieldName = null) {
|
||||
return AddDynamicPort(type, NodePort.IO.Input, connectionType, typeConstraint, fieldName);
|
||||
return ((INode)this).AddDynamicPort(type, NodePort.IO.Input, connectionType, typeConstraint, fieldName);
|
||||
}
|
||||
|
||||
/// <summary> Convenience function. </summary>
|
||||
/// <seealso cref="AddInstancePort"/>
|
||||
/// <seealso cref="AddInstanceInput"/>
|
||||
public NodePort AddDynamicOutput(Type type, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None, string fieldName = null) {
|
||||
return AddDynamicPort(type, NodePort.IO.Output, connectionType, typeConstraint, fieldName);
|
||||
return ((INode)this).AddDynamicPort(type, NodePort.IO.Output, connectionType, typeConstraint, fieldName);
|
||||
}
|
||||
|
||||
/// <summary> Add a dynamic, serialized port to this node. </summary>
|
||||
/// <seealso cref="AddDynamicInput"/>
|
||||
/// <seealso cref="AddDynamicOutput"/>
|
||||
private NodePort AddDynamicPort(Type type, NodePort.IO direction, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None, string fieldName = null) {
|
||||
NodePort INode.AddDynamicPort(Type type, NodePort.IO direction, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None, string fieldName = null) {
|
||||
if (fieldName == null) {
|
||||
fieldName = "dynamicInput_0";
|
||||
int i = 0;
|
||||
|
||||
@ -11,11 +11,28 @@ namespace XNode {
|
||||
/// See: <see cref="AddNode{T}"/> </summary>
|
||||
[SerializeField] public List<Node> nodes = new List<Node>();
|
||||
|
||||
#region Interface implementation
|
||||
IEnumerable<INode> INodeGraph.Nodes { get { foreach (Node node in nodes) yield return node; } }
|
||||
INode INodeGraph.AddNode(Type type) { return AddNode(type); }
|
||||
void INodeGraph.MoveNodeToTop(INode node) { MoveNodeToTop(node as Node); }
|
||||
INode INodeGraph.CopyNode(INode original) { return CopyNode(original as Node); }
|
||||
void INodeGraph.RemoveNode(INode node) { RemoveNode(node as Node); }
|
||||
#endregion
|
||||
|
||||
/// <summary> Add a node to the graph by type (convenience method - will call the System.Type version) </summary>
|
||||
public T AddNode<T>() where T : Node {
|
||||
return AddNode(typeof(T)) as T;
|
||||
}
|
||||
|
||||
/// <summary> Draw this node on top of other nodes by placing it last in the graph.nodes list </summary>
|
||||
public void MoveNodeToTop(XNode.Node node) {
|
||||
int index;
|
||||
while ((index = nodes.IndexOf(node as Node)) != nodes.Count - 1) {
|
||||
nodes[index] = nodes[index + 1];
|
||||
nodes[index + 1] = node as Node;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Add a node to the graph by type </summary>
|
||||
public virtual Node AddNode(Type type) {
|
||||
Node.graphHotfix = this;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user