mirror of
https://github.com/Siccity/xNode.git
synced 2026-02-06 07:14:56 +08:00
Connections now draw under port handles
Modulized code. Too many minor changes to address
This commit is contained in:
parent
f8a0bb8f7c
commit
6a92f18618
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84fbc8acdc9656941b529a16e8bbe318
|
||||
timeCreated: 1506462197
|
||||
guid: 2e27fbb85ccd5994e932fd8a6d34e4b3
|
||||
timeCreated: 1506790922
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 11400000
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using System;
|
||||
/// <summary> Defines an example nodegraph. </summary>
|
||||
[CreateAssetMenu(fileName = "NodeGraphExample", menuName = "Node Graph/Example")]
|
||||
[Serializable, CreateAssetMenu(fileName = "NodeGraphExample", menuName = "Node Graph/Example")]
|
||||
public class NodeGraphExample : NodeGraph {
|
||||
|
||||
}
|
||||
@ -1,7 +1,10 @@
|
||||
[CustomNodeEditor(typeof(MathNode), "Math")]
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[CustomNodeEditor(typeof(MathNode), "Math")]
|
||||
public class AddNodeEditor : NodeEditor {
|
||||
|
||||
public override void OnNodeGUI() {
|
||||
base.OnNodeGUI();
|
||||
public override void OnNodeGUI(out Dictionary<NodePort, Vector2> portPositions) {
|
||||
base.OnNodeGUI(out portPositions);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,17 +8,18 @@ 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 {
|
||||
|
||||
public Dictionary<NodePort, Rect> portRects = new Dictionary<NodePort, Rect>();
|
||||
public Node target;
|
||||
|
||||
public virtual void OnNodeGUI() {
|
||||
portRects.Clear();
|
||||
DrawDefaultNodePortsGUI();
|
||||
/// <summary> Draws the node GUI.</summary>
|
||||
/// <param name="portPositions">Port handle positions need to be returned to the NodeEditorWindow </param>
|
||||
public virtual void OnNodeGUI(out Dictionary<NodePort,Vector2> portPositions) {
|
||||
DrawDefaultNodePortsGUI(out portPositions);
|
||||
DrawDefaultNodeBodyGUI();
|
||||
}
|
||||
|
||||
/// <summary> Draws standard editors for all fields marked with <see cref="Node.InputAttribute"/> or <see cref="Node.OutputAttribute"/> </summary>
|
||||
protected void DrawDefaultNodePortsGUI() {
|
||||
protected void DrawDefaultNodePortsGUI(out Dictionary<NodePort, Vector2> portPositions) {
|
||||
portPositions = new Dictionary<NodePort, Vector2>();
|
||||
|
||||
Event e = Event.current;
|
||||
|
||||
@ -27,14 +28,16 @@ public class NodeEditor {
|
||||
//Inputs
|
||||
GUILayout.BeginVertical();
|
||||
for (int i = 0; i < target.InputCount; i++) {
|
||||
DrawNodePortGUI(target.inputs[i]);
|
||||
Vector2 handlePoint = DrawNodePortGUI(target.inputs[i]);
|
||||
portPositions.Add(target.inputs[i], handlePoint);
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
//Outputs
|
||||
GUILayout.BeginVertical();
|
||||
for (int i = 0; i < target.OutputCount; i++) {
|
||||
DrawNodePortGUI(target.outputs[i]);
|
||||
Vector2 handlePoint = DrawNodePortGUI(target.outputs[i]);
|
||||
portPositions.Add(target.outputs[i], handlePoint);
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
@ -52,31 +55,25 @@ public class NodeEditor {
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
protected void DrawNodePortGUI(NodePort port) {
|
||||
/// <summary> Draw node port GUI using automatic layouting. Returns port handle position. </summary>
|
||||
protected Vector2 DrawNodePortGUI(NodePort port) {
|
||||
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputStyle : NodeEditorResources.styles.outputStyle;
|
||||
Rect rect = GUILayoutUtility.GetRect(new GUIContent(port.name.PrettifyCamelCase()), style);
|
||||
DrawNodePortGUI(rect, port);
|
||||
return DrawNodePortGUI(rect, port);
|
||||
}
|
||||
|
||||
protected void DrawNodePortGUI(Rect rect, NodePort port) {
|
||||
/// <summary> Draw node port GUI in rect. Returns port handle position. </summary>
|
||||
protected Vector2 DrawNodePortGUI(Rect rect, NodePort port) {
|
||||
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputStyle : NodeEditorResources.styles.outputStyle;
|
||||
GUI.Label(rect, new GUIContent(port.name.PrettifyCamelCase()), style);
|
||||
Rect handleRect = new Rect(0, 0, 16, 16);
|
||||
|
||||
Vector2 handlePoint = rect.center;
|
||||
|
||||
switch (port.direction) {
|
||||
case NodePort.IO.Input:
|
||||
handleRect.position = new Vector2(rect.xMin - 8, rect.position.y + (rect.height * 0.5f) - 8);
|
||||
break;
|
||||
case NodePort.IO.Output:
|
||||
handleRect.position = new Vector2(rect.xMax - 8, rect.position.y + (rect.height * 0.5f) - 8);
|
||||
break;
|
||||
case NodePort.IO.Input: handlePoint.x = rect.xMin; break;
|
||||
case NodePort.IO.Output: handlePoint.x = rect.xMax; break;
|
||||
}
|
||||
portRects.Add(port, handleRect);
|
||||
Color col = GUI.color;
|
||||
GUI.color = NodeEditorUtilities.GetTypeColor(port.type);
|
||||
GUI.DrawTexture(handleRect, NodeEditorResources.dot);
|
||||
GUI.color = new Color(0.29f,0.31f,0.32f);
|
||||
GUI.DrawTexture(handleRect, NodeEditorResources.dotOuter);
|
||||
GUI.color = col;
|
||||
return handlePoint;
|
||||
}
|
||||
|
||||
private static FieldInfo[] GetInspectorFields(Node node) {
|
||||
|
||||
@ -129,8 +129,8 @@ public partial class NodeEditorWindow {
|
||||
public void DrawDraggedConnection() {
|
||||
if (IsDraggingPort) {
|
||||
if (!_portConnectionPoints.ContainsKey(draggedOutput)) return;
|
||||
Vector2 from = draggedOutput.node.rect.position + _portConnectionPoints[draggedOutput].center;
|
||||
Vector2 to = draggedOutputTarget != null ? draggedOutputTarget.node.rect.position + portConnectionPoints[draggedOutputTarget].center : WindowToGridPosition(Event.current.mousePosition);
|
||||
Vector2 from = _portConnectionPoints[draggedOutput].center;
|
||||
Vector2 to = draggedOutputTarget != null ? portConnectionPoints[draggedOutputTarget].center : WindowToGridPosition(Event.current.mousePosition);
|
||||
Color col = NodeEditorUtilities.GetTypeColor(draggedOutput.type);
|
||||
col.a = 0.6f;
|
||||
DrawConnection(from, to, col);
|
||||
@ -154,33 +154,29 @@ public partial class NodeEditorWindow {
|
||||
Repaint();
|
||||
}
|
||||
//If we are hovering a node, check if we are also hovering a port
|
||||
if (IsHoveringNode) {
|
||||
NodePort newHoverPort = null;
|
||||
//Check all input ports
|
||||
for (int i = 0; i < hoveredNode.InputCount; i++) {
|
||||
NodePort port = hoveredNode.inputs[i];
|
||||
NodePort newHoverPort = null;
|
||||
//Check all input ports
|
||||
for (int k = 0; k < graph.nodes.Count; k++) {
|
||||
|
||||
for (int i = 0; i < graph.nodes[k].InputCount; i++) {
|
||||
NodePort port = graph.nodes[k].inputs[i];
|
||||
//Check if port rect is available
|
||||
if (!portConnectionPoints.ContainsKey(port)) continue;
|
||||
Rect r = portConnectionPoints[port];
|
||||
r.position = GridToWindowPosition(r.position + hoveredNode.rect.position);
|
||||
r.size /= zoom;
|
||||
Rect r = GridToWindowRect(portConnectionPoints[port]);
|
||||
if (r.Contains(mousePos)) newHoverPort = port;
|
||||
}
|
||||
//Check all output ports
|
||||
for (int i = 0; i < hoveredNode.OutputCount; i++) {
|
||||
NodePort port = hoveredNode.outputs[i];
|
||||
for (int i = 0; i < graph.nodes[k].OutputCount; i++) {
|
||||
NodePort port = graph.nodes[k].outputs[i];
|
||||
//Check if port rect is available
|
||||
if (!portConnectionPoints.ContainsKey(port)) continue;
|
||||
Rect r = portConnectionPoints[port];
|
||||
r.position = GridToWindowPosition(r.position + hoveredNode.rect.position);
|
||||
r.size /= zoom;
|
||||
Rect r = GridToWindowRect(portConnectionPoints[port]);
|
||||
if (r.Contains(mousePos)) newHoverPort = port;
|
||||
}
|
||||
if (newHoverPort != hoveredPort) {
|
||||
hoveredPort = newHoverPort;
|
||||
}
|
||||
}
|
||||
else hoveredPort = null;
|
||||
if (newHoverPort != hoveredPort) {
|
||||
hoveredPort = newHoverPort;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsHoveringTitle(Node node) {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary> Contains GUI methods </summary>
|
||||
public partial class NodeEditorWindow {
|
||||
@ -14,6 +15,7 @@ public partial class NodeEditorWindow {
|
||||
DrawNodes();
|
||||
DrawConnections();
|
||||
DrawDraggedConnection();
|
||||
DrawPortHandles();
|
||||
DrawToolbar();
|
||||
|
||||
GUI.matrix = m;
|
||||
@ -117,6 +119,7 @@ public partial class NodeEditorWindow {
|
||||
GUI.color = prevCol;
|
||||
}
|
||||
|
||||
/// <summary> Draws all connections </summary>
|
||||
public void DrawConnections() {
|
||||
foreach (Node node in graph.nodes) {
|
||||
for (int i = 0; i < node.OutputCount; i++) {
|
||||
@ -124,16 +127,30 @@ public partial class NodeEditorWindow {
|
||||
|
||||
//Needs cleanup. Null checks are ugly
|
||||
if (!portConnectionPoints.ContainsKey(output)) continue;
|
||||
Vector2 from = _portConnectionPoints[output].center + node.rect.position;
|
||||
Vector2 from = _portConnectionPoints[output].center;
|
||||
for (int k = 0; k < output.ConnectionCount; k++) {
|
||||
NodePort input = output.GetConnection(k);
|
||||
Vector2 to = input.node.rect.position + _portConnectionPoints[input].center;
|
||||
Vector2 to = _portConnectionPoints[input].center;
|
||||
DrawConnection(from, to, NodeEditorUtilities.GetTypeColor(output.type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Draws the draggable circle handles on the ports </summary>
|
||||
public void DrawPortHandles() {
|
||||
Color col = GUI.color;
|
||||
foreach(var kvp in portConnectionPoints) {
|
||||
Rect rect = GridToWindowRect(kvp.Value);
|
||||
GUI.color = new Color(0.29f, 0.31f, 0.32f);
|
||||
GUI.DrawTexture(rect, NodeEditorResources.dotOuter);
|
||||
GUI.color = NodeEditorUtilities.GetTypeColor(kvp.Key.type);
|
||||
GUI.DrawTexture(rect, NodeEditorResources.dot);
|
||||
|
||||
}
|
||||
GUI.color = col;
|
||||
}
|
||||
|
||||
private void DrawNodes() {
|
||||
Event e = Event.current;
|
||||
if (e.type == EventType.Repaint) portConnectionPoints.Clear();
|
||||
@ -164,10 +181,14 @@ public partial class NodeEditorWindow {
|
||||
|
||||
nodeEditor.target = node;
|
||||
|
||||
nodeEditor.OnNodeGUI();
|
||||
Dictionary<NodePort, Vector2> portHandlePoints;
|
||||
nodeEditor.OnNodeGUI(out portHandlePoints);
|
||||
if (e.type == EventType.Repaint) {
|
||||
foreach (var kvp in nodeEditor.portRects) {
|
||||
portConnectionPoints.Add(kvp.Key, kvp.Value);
|
||||
foreach (var kvp in portHandlePoints) {
|
||||
Vector2 portHandlePos = kvp.Value;
|
||||
portHandlePos += node.rect.position;
|
||||
Rect rect = new Rect(portHandlePos.x - 8, portHandlePos.y - 8, 16, 16);
|
||||
portConnectionPoints.Add(kvp.Key, rect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,15 +7,16 @@ using UnityEditor.Callbacks;
|
||||
using System;
|
||||
|
||||
[InitializeOnLoad]
|
||||
public partial class NodeEditorWindow : EditorWindow {
|
||||
public partial class NodeEditorWindow : EditorWindow {
|
||||
/// <summary> Stores node positions for all nodePorts. </summary>
|
||||
public Dictionary<NodePort, Rect> portConnectionPoints { get { return _portConnectionPoints; } }
|
||||
private Dictionary<NodePort, Rect> _portConnectionPoints = new Dictionary<NodePort, Rect>();
|
||||
public NodeGraph graph { get { return _graph != null ? _graph : _graph = CreateInstance<NodeGraph>(); } }
|
||||
public NodeGraph _graph;
|
||||
public NodeGraph 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, 5f); Repaint(); } }
|
||||
private float _zoom = 1;
|
||||
private float _zoom = 1;
|
||||
|
||||
|
||||
partial void OnEnable();
|
||||
/// <summary> Create editor window </summary>
|
||||
@ -29,8 +30,8 @@ public partial class NodeEditorWindow : EditorWindow {
|
||||
}
|
||||
|
||||
public void Save() {
|
||||
if (AssetDatabase.Contains(_graph)) {
|
||||
EditorUtility.SetDirty(_graph);
|
||||
if (AssetDatabase.Contains(graph)) {
|
||||
EditorUtility.SetDirty(graph);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
else SaveAs();
|
||||
@ -42,8 +43,8 @@ public partial class NodeEditorWindow : EditorWindow {
|
||||
else {
|
||||
NodeGraph existingGraph = AssetDatabase.LoadAssetAtPath<NodeGraph>(path);
|
||||
if (existingGraph != null) AssetDatabase.DeleteAsset(path);
|
||||
AssetDatabase.CreateAsset(_graph, path);
|
||||
EditorUtility.SetDirty(_graph);
|
||||
AssetDatabase.CreateAsset(graph, path);
|
||||
EditorUtility.SetDirty(graph);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
}
|
||||
@ -60,6 +61,12 @@ public partial class NodeEditorWindow : EditorWindow {
|
||||
return (position.size * 0.5f) + (panOffset / zoom) + (gridPosition/zoom);
|
||||
}
|
||||
|
||||
public Rect GridToWindowRect(Rect gridRect) {
|
||||
gridRect.position = GridToWindowPosition(gridRect.position);
|
||||
gridRect.size /= zoom;
|
||||
return gridRect;
|
||||
}
|
||||
|
||||
public Vector2 GridToWindowPositionNoClipped(Vector2 gridPosition) {
|
||||
Vector2 center = position.size * 0.5f;
|
||||
float xOffset = (center.x * zoom + (panOffset.x + gridPosition.x));
|
||||
@ -71,12 +78,13 @@ public partial class NodeEditorWindow : EditorWindow {
|
||||
selectedNode = node;
|
||||
}
|
||||
|
||||
|
||||
[OnOpenAsset(0)]
|
||||
public static bool OnOpen(int instanceID, int line) {
|
||||
NodeGraph nodeGraph = EditorUtility.InstanceIDToObject(instanceID) as NodeGraph;
|
||||
if (nodeGraph != null) {
|
||||
NodeEditorWindow w = Init();
|
||||
w._graph = nodeGraph;
|
||||
w.graph = nodeGraph;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -4,13 +4,11 @@ using UnityEngine;
|
||||
using System;
|
||||
|
||||
/// <summary> Base class for all node graphs </summary>
|
||||
[Serializable]
|
||||
public abstract class NodeGraph : ScriptableObject {
|
||||
/// <summary> All nodes in the graph. <para/>
|
||||
/// See: <see cref="AddNode{T}"/> </summary>
|
||||
[NonSerialized] public List<Node> nodes = new List<Node>();
|
||||
|
||||
/// <summary> Serialized nodes. </summary>
|
||||
[SerializeField] public string[] s_nodes;
|
||||
[SerializeField] public List<Node> nodes = new List<Node>();
|
||||
|
||||
public T AddNode<T>() where T : Node {
|
||||
return AddNode(typeof(T)) as T;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user