mirror of
https://github.com/Siccity/xNode.git
synced 2026-02-06 15:24:55 +08:00
Merge pull request #52 from zulfajuniadi/examples
Merged Example Branch with Master
This commit is contained in:
commit
2675c088f1
@ -8,12 +8,12 @@ namespace XNodeEditor.Examples {
|
||||
public class MathGraphEditor : NodeGraphEditor {
|
||||
|
||||
/// <summary>
|
||||
/// Overriding GetNodePath lets you control if and how nodes are categorized.
|
||||
/// Overriding GetNodeMenuName lets you control if and how nodes are categorized.
|
||||
/// In this example we are sorting out all node types that are not in the XNode.Examples namespace.
|
||||
/// </summary>
|
||||
public override string GetNodePath(System.Type type) {
|
||||
public override string GetNodeMenuName(System.Type type) {
|
||||
if (type.Namespace == "XNode.Examples.MathNodes") {
|
||||
return base.GetNodePath(type).Replace("X Node/Examples/Math Nodes/", "");
|
||||
return base.GetNodeMenuName(type).Replace("X Node/Examples/Math Nodes/", "");
|
||||
} else return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,12 +9,12 @@ namespace XNodeEditor.Examples {
|
||||
public class StateGraphEditor : NodeGraphEditor {
|
||||
|
||||
/// <summary>
|
||||
/// Overriding GetNodePath lets you control if and how nodes are categorized.
|
||||
/// Overriding GetNodeMenuName lets you control if and how nodes are categorized.
|
||||
/// In this example we are sorting out all node types that are not in the XNode.Examples namespace.
|
||||
/// </summary>
|
||||
public override string GetNodePath(System.Type type) {
|
||||
public override string GetNodeMenuName(System.Type type) {
|
||||
if (type.Namespace == "XNode.Examples.StateGraph") {
|
||||
return base.GetNodePath(type).Replace("X Node/Examples/State Graph/", "");
|
||||
return base.GetNodeMenuName(type).Replace("X Node/Examples/State Graph/", "");
|
||||
} else return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||

|
||||
|
||||
[](https://discord.gg/qgPrHv4)
|
||||
[](https://github.com/Siccity/xNode/issues)
|
||||
[](https://raw.githubusercontent.com/Siccity/xNode/master/LICENSE.md)
|
||||
@ -5,6 +7,8 @@
|
||||
|
||||
[Downloads](https://github.com/Siccity/xNode/releases) / [Asset Store](http://u3d.as/108S) / [Documentation](https://github.com/Siccity/xNode/wiki)
|
||||
|
||||
[Support Me on Ko-fi](https://ko-fi.com/Z8Z5DYWA)
|
||||
|
||||
### xNode
|
||||
Thinking of developing a node-based plugin? Then this is for you. You can download it as an archive and unpack to a new unity project, or connect it as git submodule.
|
||||
|
||||
|
||||
@ -23,7 +23,6 @@ namespace XNodeEditor {
|
||||
}
|
||||
|
||||
public virtual void OnHeaderGUI() {
|
||||
GUI.color = Color.white;
|
||||
string title = target.name;
|
||||
if (renaming != 0 && Selection.Contains(target)) {
|
||||
int controlID = EditorGUIUtility.GetControlID(FocusType.Keyboard) + 1;
|
||||
@ -58,7 +57,9 @@ namespace XNodeEditor {
|
||||
}
|
||||
|
||||
public virtual int GetWidth() {
|
||||
return 208;
|
||||
Type type = target.GetType();
|
||||
if (NodeEditorWindow.nodeWidth.ContainsKey(type)) return NodeEditorWindow.nodeWidth[type];
|
||||
else return 208;
|
||||
}
|
||||
|
||||
public virtual Color GetTint() {
|
||||
|
||||
@ -203,16 +203,13 @@ namespace XNodeEditor {
|
||||
EditorUtility.SetDirty(graph);
|
||||
if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();
|
||||
} else if (currentActivity == NodeActivity.DragNode) {
|
||||
IEnumerable<XNode.Node> nodes = Selection.objects.Where(x => x is XNode.Node).Select(x => x as XNode.Node);
|
||||
foreach (XNode.Node node in nodes) EditorUtility.SetDirty(node);
|
||||
if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();
|
||||
} else if (!IsHoveringNode) {
|
||||
// If click outside node, release field focus
|
||||
if (!isPanning) {
|
||||
// I've got no idea which of these do what, so we'll just reset all of it.
|
||||
GUIUtility.hotControl = 0;
|
||||
GUIUtility.keyboardControl = 0;
|
||||
EditorGUIUtility.editingTextField = false;
|
||||
EditorGUIUtility.keyboardControl = 0;
|
||||
EditorGUIUtility.hotControl = 0;
|
||||
EditorGUI.FocusTextInControl(null);
|
||||
}
|
||||
if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();
|
||||
}
|
||||
@ -231,7 +228,7 @@ namespace XNodeEditor {
|
||||
|
||||
Repaint();
|
||||
currentActivity = NodeActivity.Idle;
|
||||
} else if (e.button == 1) {
|
||||
} else if (e.button == 1 || e.button == 2) {
|
||||
if (!isPanning) {
|
||||
if (IsDraggingPort) {
|
||||
draggedOutputReroutes.Add(WindowToGridPosition(e.mousePosition));
|
||||
@ -255,6 +252,11 @@ namespace XNodeEditor {
|
||||
case EventType.KeyDown:
|
||||
if (EditorGUIUtility.editingTextField) break;
|
||||
else if (e.keyCode == KeyCode.F) Home();
|
||||
if (SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX) {
|
||||
if (e.keyCode == KeyCode.Return) RenameSelectedNode();
|
||||
} else {
|
||||
if (e.keyCode == KeyCode.F2) RenameSelectedNode();
|
||||
}
|
||||
break;
|
||||
case EventType.ValidateCommand:
|
||||
if (e.commandName == "SoftDelete") RemoveSelectedNodes();
|
||||
@ -296,7 +298,7 @@ namespace XNodeEditor {
|
||||
public void CreateNode(Type type, Vector2 position) {
|
||||
XNode.Node node = graph.AddNode(type);
|
||||
node.position = position;
|
||||
node.name = UnityEditor.ObjectNames.NicifyVariableName(type.ToString());
|
||||
node.name = UnityEditor.ObjectNames.NicifyVariableName(type.Name);
|
||||
AssetDatabase.AddObjectToAsset(node, graph);
|
||||
if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();
|
||||
Repaint();
|
||||
@ -318,6 +320,14 @@ 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;
|
||||
NodeEditor.GetEditor(node).InitiateRename();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
@ -407,7 +417,7 @@ namespace XNodeEditor {
|
||||
//Get node position
|
||||
Vector2 nodePos = GridToWindowPosition(node.position);
|
||||
float width = 200;
|
||||
if (nodeWidths.ContainsKey(node)) width = nodeWidths[node];
|
||||
if (nodeSizes.ContainsKey(node)) width = nodeSizes[node].x;
|
||||
Rect windowRect = new Rect(nodePos, new Vector2(width / zoom, 30 / zoom));
|
||||
return windowRect.Contains(mousePos);
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
@ -8,6 +9,7 @@ namespace XNodeEditor {
|
||||
public partial class NodeEditorWindow {
|
||||
public NodeGraphEditor graphEditor;
|
||||
private List<UnityEngine.Object> selectionCache;
|
||||
private List<XNode.Node> culledNodes;
|
||||
|
||||
private void OnGUI() {
|
||||
Event e = Event.current;
|
||||
@ -112,7 +114,7 @@ namespace XNodeEditor {
|
||||
if (Selection.objects.Length == 1 && Selection.activeObject is XNode.Node) {
|
||||
XNode.Node node = Selection.activeObject as XNode.Node;
|
||||
contextMenu.AddItem(new GUIContent("Move To Top"), false, () => MoveNodeToTop(node));
|
||||
contextMenu.AddItem(new GUIContent("Rename"), false, NodeEditor.GetEditor(node).InitiateRename);
|
||||
contextMenu.AddItem(new GUIContent("Rename"), false, RenameSelectedNode);
|
||||
}
|
||||
|
||||
contextMenu.AddItem(new GUIContent("Duplicate"), false, DublicateSelectedNodes);
|
||||
@ -135,8 +137,8 @@ namespace XNodeEditor {
|
||||
Type type = nodeTypes[i];
|
||||
|
||||
//Get node context menu path
|
||||
string path = graphEditor.GetNodePath(type);
|
||||
if (path == null) continue;
|
||||
string path = graphEditor.GetNodeMenuName(type);
|
||||
if (string.IsNullOrEmpty(path)) continue;
|
||||
|
||||
contextMenu.AddItem(new GUIContent(path), false, () => {
|
||||
CreateNode(type, pos);
|
||||
@ -280,10 +282,6 @@ namespace XNodeEditor {
|
||||
if (e.type == EventType.Layout) {
|
||||
selectionCache = new List<UnityEngine.Object>(Selection.objects);
|
||||
}
|
||||
if (e.type == EventType.Repaint) {
|
||||
portConnectionPoints.Clear();
|
||||
nodeWidths.Clear();
|
||||
}
|
||||
|
||||
//Active node is hashed before and after node GUI to detect changes
|
||||
int nodeHash = 0;
|
||||
@ -313,6 +311,8 @@ namespace XNodeEditor {
|
||||
|
||||
//Save guiColor so we can revert it
|
||||
Color guiColor = GUI.color;
|
||||
|
||||
if (e.type == EventType.Layout) culledNodes = new List<XNode.Node>();
|
||||
for (int n = 0; n < graph.nodes.Count; n++) {
|
||||
// Skip null nodes. The user could be in the process of renaming scripts, so removing them at this point is not advisable.
|
||||
if (graph.nodes[n] == null) continue;
|
||||
@ -320,6 +320,20 @@ namespace XNodeEditor {
|
||||
XNode.Node node = graph.nodes[n];
|
||||
|
||||
NodeEditor nodeEditor = NodeEditor.GetEditor(node);
|
||||
|
||||
// Culling
|
||||
if (e.type == EventType.Layout) {
|
||||
// Cull unselected nodes outside view
|
||||
if (!Selection.Contains(node) && ShouldBeCulled(nodeEditor)) {
|
||||
culledNodes.Add(node);
|
||||
continue;
|
||||
}
|
||||
} else if (culledNodes.Contains(node)) continue;
|
||||
|
||||
if (e.type == EventType.Repaint) {
|
||||
_portConnectionPoints = _portConnectionPoints.Where(x => x.Key.node != node).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
}
|
||||
|
||||
NodeEditor.portPositions = new Dictionary<XNode.NodePort, Vector2>();
|
||||
|
||||
//Get node position
|
||||
@ -350,26 +364,30 @@ namespace XNodeEditor {
|
||||
//Draw node contents
|
||||
nodeEditor.OnNodeGUI();
|
||||
|
||||
//Apply
|
||||
nodeEditor.serializedObject.ApplyModifiedProperties();
|
||||
|
||||
//If user changed a value, notify other scripts through onUpdateNode
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
if (NodeEditor.onUpdateNode != null) NodeEditor.onUpdateNode(node);
|
||||
EditorUtility.SetDirty(node);
|
||||
nodeEditor.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
|
||||
//Cache data about the node for next frame
|
||||
if (e.type == EventType.Repaint) {
|
||||
nodeWidths.Add(node, nodeEditor.GetWidth());
|
||||
Vector2 size = GUILayoutUtility.GetLastRect().size;
|
||||
if (nodeSizes.ContainsKey(node)) nodeSizes[node] = size;
|
||||
else nodeSizes.Add(node, size);
|
||||
|
||||
foreach (var kvp in NodeEditor.portPositions) {
|
||||
Vector2 portHandlePos = kvp.Value;
|
||||
portHandlePos += node.position;
|
||||
Rect rect = new Rect(portHandlePos.x - 8, portHandlePos.y - 8, 16, 16);
|
||||
portConnectionPoints.Add(kvp.Key, rect);
|
||||
if (portConnectionPoints.ContainsKey(kvp.Key)) portConnectionPoints[kvp.Key] = rect;
|
||||
else portConnectionPoints.Add(kvp.Key, rect);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
if (selected) GUILayout.EndVertical();
|
||||
|
||||
if (e.type != EventType.Layout) {
|
||||
@ -414,12 +432,25 @@ namespace XNodeEditor {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Returns true if outside window area </summary>
|
||||
private bool ShouldBeCulled(XNodeEditor.NodeEditor nodeEditor) {
|
||||
Vector2 nodePos = GridToWindowPositionNoClipped(nodeEditor.target.position);
|
||||
if (nodePos.x / _zoom > position.width) return true; // Right
|
||||
else if (nodePos.y / _zoom > position.height) return true; // Bottom
|
||||
else if (nodeSizes.ContainsKey(nodeEditor.target)) {
|
||||
Vector2 size = nodeSizes[nodeEditor.target];
|
||||
if (nodePos.x + size.x < 0) return true; // Left
|
||||
else if (nodePos.y + size.y < 0) return true; // Top
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void DrawTooltip() {
|
||||
if (hoveredPort != null) {
|
||||
Type type = hoveredPort.ValueType;
|
||||
GUIContent content = new GUIContent();
|
||||
content.text = type.PrettyName();
|
||||
if (hoveredPort.IsStatic && hoveredPort.IsOutput) {
|
||||
if (hoveredPort.IsOutput) {
|
||||
object obj = hoveredPort.node.GetValue(hoveredPort);
|
||||
content.text += " = " + (obj != null ? obj.ToString() : "null");
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
@ -110,11 +112,26 @@ namespace XNodeEditor {
|
||||
/// <summary> Make a simple port field. </summary>
|
||||
public static void PortField(GUIContent label, XNode.NodePort port, params GUILayoutOption[] options) {
|
||||
if (port == null) return;
|
||||
if (label == null) EditorGUILayout.LabelField(ObjectNames.NicifyVariableName(port.fieldName), options);
|
||||
else EditorGUILayout.LabelField(label, options);
|
||||
Rect rect = GUILayoutUtility.GetLastRect();
|
||||
if (port.direction == XNode.NodePort.IO.Input) rect.position = rect.position - new Vector2(16, 0);
|
||||
else if (port.direction == XNode.NodePort.IO.Output) rect.position = rect.position + new Vector2(rect.width, 0);
|
||||
if (options == null) options = new GUILayoutOption[] { GUILayout.MinWidth(30) };
|
||||
Rect rect = new Rect();
|
||||
GUIContent content = label != null ? label : new GUIContent(ObjectNames.NicifyVariableName(port.fieldName));
|
||||
|
||||
// If property is an input, display a regular property field and put a port handle on the left side
|
||||
if (port.direction == XNode.NodePort.IO.Input) {
|
||||
// Display a label
|
||||
EditorGUILayout.LabelField(content, options);
|
||||
|
||||
rect = GUILayoutUtility.GetLastRect();
|
||||
rect.position = rect.position - new Vector2(16, 0);
|
||||
// If property is an output, display a text label and put a port handle on the right side
|
||||
} else if (port.direction == XNode.NodePort.IO.Output) {
|
||||
// Display a label
|
||||
EditorGUILayout.LabelField(content, NodeEditorResources.OutputPort, options);
|
||||
|
||||
rect = GUILayoutUtility.GetLastRect();
|
||||
rect.position = rect.position + new Vector2(rect.width, 0);
|
||||
}
|
||||
|
||||
rect.size = new Vector2(16, 16);
|
||||
|
||||
Color backgroundColor = new Color32(90, 97, 105, 255);
|
||||
@ -128,13 +145,87 @@ namespace XNodeEditor {
|
||||
else NodeEditor.portPositions.Add(port, portPos);
|
||||
}
|
||||
|
||||
/// <summary> Draws an input and an output port on the same line </summary>
|
||||
public static void PortPair(XNode.NodePort input, XNode.NodePort output) {
|
||||
GUILayout.BeginHorizontal();
|
||||
NodeEditorGUILayout.PortField(input, GUILayout.MinWidth(0));
|
||||
NodeEditorGUILayout.PortField(output, GUILayout.MinWidth(0));
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public static void DrawPortHandle(Rect rect, Color backgroundColor, Color typeColor) {
|
||||
Color col = GUI.color;
|
||||
GUI.color = backgroundColor;
|
||||
GUI.DrawTexture(rect, NodeEditorResources.dotOuter);
|
||||
GUI.color = typeColor;
|
||||
GUI.color = typeColor;
|
||||
GUI.DrawTexture(rect, NodeEditorResources.dot);
|
||||
GUI.color = col;
|
||||
}
|
||||
|
||||
/// <summary> Draw an editable list of instance ports. Port names are named as "[fieldName] [index]" </summary>
|
||||
/// <param name="fieldName">Supply a list for editable values</param>
|
||||
/// <param name="type">Value type of added instance ports</param>
|
||||
/// <param name="serializedObject">The serializedObject of the node</param>
|
||||
/// <param name="connectionType">Connection type of added instance ports</param>
|
||||
public static void InstancePortList(string fieldName, Type type, SerializedObject serializedObject, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple) {
|
||||
XNode.Node node = serializedObject.targetObject as XNode.Node;
|
||||
SerializedProperty arrayData = serializedObject.FindProperty(fieldName);
|
||||
bool hasArrayData = arrayData != null && arrayData.isArray;
|
||||
int arraySize = hasArrayData ? arrayData.arraySize : 0;
|
||||
|
||||
List<XNode.NodePort> instancePorts = node.InstancePorts.Where(x => x.fieldName.StartsWith(fieldName)).OrderBy(x => x.fieldName).ToList();
|
||||
|
||||
for (int i = 0; i < instancePorts.Count(); i++) {
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("-", GUILayout.Width(30))) {
|
||||
// Clear the removed ports connections
|
||||
instancePorts[i].ClearConnections();
|
||||
// Move following connections one step up to replace the missing connection
|
||||
for (int k = i + 1; k < instancePorts.Count(); k++) {
|
||||
for (int j = 0; j < instancePorts[k].ConnectionCount; j++) {
|
||||
XNode.NodePort other = instancePorts[k].GetConnection(j);
|
||||
instancePorts[k].Disconnect(other);
|
||||
instancePorts[k - 1].Connect(other);
|
||||
}
|
||||
}
|
||||
// Remove the last instance port, to avoid messing up the indexing
|
||||
node.RemoveInstancePort(instancePorts[instancePorts.Count() - 1].fieldName);
|
||||
serializedObject.Update();
|
||||
EditorUtility.SetDirty(node);
|
||||
if (hasArrayData) {
|
||||
arrayData.DeleteArrayElementAtIndex(i);
|
||||
arraySize--;
|
||||
}
|
||||
i--;
|
||||
} else {
|
||||
if (hasArrayData) {
|
||||
if (i < arraySize) {
|
||||
SerializedProperty itemData = arrayData.GetArrayElementAtIndex(i);
|
||||
if (itemData != null) EditorGUILayout.PropertyField(itemData, new GUIContent(ObjectNames.NicifyVariableName(fieldName) + " " + i));
|
||||
else EditorGUILayout.LabelField("[Missing array data]");
|
||||
} else EditorGUILayout.LabelField("[Out of bounds]");
|
||||
|
||||
} else {
|
||||
EditorGUILayout.LabelField(instancePorts[i].fieldName);
|
||||
}
|
||||
NodeEditorGUILayout.PortField(new GUIContent(), node.GetPort(instancePorts[i].fieldName), GUILayout.Width(-4));
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
GUILayout.BeginHorizontal();
|
||||
EditorGUILayout.Space();
|
||||
if (GUILayout.Button("+", GUILayout.Width(30))) {
|
||||
|
||||
string newName = fieldName + " 0";
|
||||
int i = 0;
|
||||
while (node.HasPort(newName)) newName = fieldName + " " + (++i);
|
||||
|
||||
instancePorts.Add(node.AddInstanceOutput(type, connectionType, newName));
|
||||
serializedObject.Update();
|
||||
EditorUtility.SetDirty(node);
|
||||
if (hasArrayData) arrayData.InsertArrayElementAtIndex(arraySize);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,10 @@ namespace XNodeEditor {
|
||||
public static Dictionary<Type, Color> nodeTint { get { return _nodeTint != null ? _nodeTint : _nodeTint = GetNodeTint(); } }
|
||||
|
||||
[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>
|
||||
public static Type[] nodeTypes { get { return _nodeTypes != null ? _nodeTypes : _nodeTypes = GetNodeTypes(); } }
|
||||
|
||||
@ -34,6 +38,17 @@ namespace XNodeEditor {
|
||||
return tints;
|
||||
}
|
||||
|
||||
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.NodeWidth), true);
|
||||
if (attribs == null || attribs.Length == 0) continue;
|
||||
XNode.Node.NodeWidth attrib = attribs[0] as XNode.Node.NodeWidth;
|
||||
widths.Add(nodeTypes[i], attrib.width);
|
||||
}
|
||||
return widths;
|
||||
}
|
||||
|
||||
/// <summary> Get all classes deriving from baseType via reflection </summary>
|
||||
public static Type[] GetDerivedTypes(Type baseType) {
|
||||
List<System.Type> types = new List<System.Type>();
|
||||
|
||||
@ -11,8 +11,8 @@ namespace XNodeEditor {
|
||||
/// <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>();
|
||||
public Dictionary<XNode.Node, float> nodeWidths { get { return _nodeWidths; } }
|
||||
private Dictionary<XNode.Node, float> _nodeWidths = new Dictionary<XNode.Node, float>();
|
||||
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 Vector2 panOffset { get { return _panOffset; } set { _panOffset = value; Repaint(); } }
|
||||
private Vector2 _panOffset;
|
||||
@ -22,7 +22,7 @@ namespace XNodeEditor {
|
||||
void OnFocus() {
|
||||
current = this;
|
||||
graphEditor = NodeGraphEditor.GetEditor(graph);
|
||||
if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();
|
||||
if (graphEditor != null && NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
partial void OnEnable();
|
||||
|
||||
@ -28,8 +28,8 @@ namespace XNodeEditor {
|
||||
return new NodeEditorPreferences.Settings();
|
||||
}
|
||||
|
||||
/// <summary> Returns context menu path. Returns null if node is not available. </summary>
|
||||
public virtual string GetNodePath(Type type) {
|
||||
/// <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;
|
||||
if (NodeEditorUtilities.GetAttrib(type, out attrib)) // Return custom path
|
||||
|
||||
@ -57,7 +57,7 @@ namespace XNode {
|
||||
[SerializeField] public NodeGraph graph;
|
||||
/// <summary> Position on the <see cref="NodeGraph"/> </summary>
|
||||
[SerializeField] public Vector2 position;
|
||||
/// <summary> Input <see cref="NodePort"/>s. It is recommended not to modify these at hand. Instead, see <see cref="InputAttribute"/> </summary>
|
||||
/// <summary> It is recommended not to modify these at hand. Instead, see <see cref="InputAttribute"/> and <see cref="OutputAttribute"/> </summary>
|
||||
[SerializeField] private NodePortDictionary ports = new NodePortDictionary();
|
||||
|
||||
protected void OnEnable() {
|
||||
@ -181,7 +181,7 @@ namespace XNode {
|
||||
else return fallback;
|
||||
}
|
||||
|
||||
/// <summary> Returns a value based on requested port output. Should be overridden before used. </summary>
|
||||
/// <summary> Returns a value based on requested port output. Should be overridden in all derived nodes with outputs. </summary>
|
||||
/// <param name="port">The requested port.</param>
|
||||
public virtual object GetValue(NodePort port) {
|
||||
Debug.LogWarning("No GetValue(NodePort port) override defined for " + GetType());
|
||||
@ -194,7 +194,7 @@ namespace XNode {
|
||||
public virtual void OnCreateConnection(NodePort from, NodePort to) { }
|
||||
|
||||
/// <summary> Called after a connection is removed from this port </summary>
|
||||
/// <param name="from">Output</param> <param name="to">Input</param>
|
||||
/// <param name="port">Output or Input</param>
|
||||
public virtual void OnRemoveConnection(NodePort port) { }
|
||||
|
||||
/// <summary> Disconnect everything from this node </summary>
|
||||
@ -240,7 +240,7 @@ namespace XNode {
|
||||
public class CreateNodeMenuAttribute : Attribute {
|
||||
public string menuName;
|
||||
/// <summary> Manually supply node class with a context menu path </summary>
|
||||
/// <param name="menuName"> Path to this node in the context menu </param>
|
||||
/// <param name="menuName"> Path to this node in the context menu. Null or empty hides it. </param>
|
||||
public CreateNodeMenuAttribute(string menuName) {
|
||||
this.menuName = menuName;
|
||||
}
|
||||
@ -272,6 +272,16 @@ namespace XNode {
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
public class NodeWidth : Attribute {
|
||||
public int width;
|
||||
/// <summary> Specify a width for this node type </summary>
|
||||
/// <param name="width"> Width </param>
|
||||
public NodeWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable] private class NodePortDictionary : Dictionary<string, NodePort>, ISerializationCallbackReceiver {
|
||||
[SerializeField] private List<string> keys = new List<string>();
|
||||
[SerializeField] private List<NodePort> values = new List<NodePort>();
|
||||
|
||||
@ -49,12 +49,16 @@ namespace XNode {
|
||||
List<System.Type> nodeTypes = new List<System.Type>();
|
||||
System.Reflection.Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
|
||||
Assembly selfAssembly = Assembly.GetAssembly(baseType);
|
||||
if (selfAssembly.FullName.StartsWith("Assembly-CSharp")) {
|
||||
if (selfAssembly.FullName.StartsWith("Assembly-CSharp") && !selfAssembly.FullName.Contains("-firstpass")) {
|
||||
// If xNode is not used as a DLL, check only CSharp (fast)
|
||||
nodeTypes.AddRange(selfAssembly.GetTypes().Where(t => !t.IsAbstract && baseType.IsAssignableFrom(t)));
|
||||
} else {
|
||||
// Else, check all DDLs (slow)
|
||||
// Else, check all relevant DDLs (slower)
|
||||
// ignore all unity related assemblies
|
||||
foreach (Assembly assembly in assemblies) {
|
||||
if (assembly.FullName.StartsWith("Unity")) continue;
|
||||
// unity created assemblies always have version 0.0.0
|
||||
if (!assembly.FullName.Contains("Version=0.0.0")) continue;
|
||||
nodeTypes.AddRange(assembly.GetTypes().Where(t => !t.IsAbstract && baseType.IsAssignableFrom(t)).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,14 +34,20 @@ namespace XNode {
|
||||
}
|
||||
|
||||
/// <summary> Safely remove a node and all its connections </summary>
|
||||
/// <param name="node"></param>
|
||||
/// <param name="node"> The node to remove </param>
|
||||
public void RemoveNode(Node node) {
|
||||
node.ClearConnections();
|
||||
nodes.Remove(node);
|
||||
if (Application.isPlaying) Destroy(node);
|
||||
}
|
||||
|
||||
/// <summary> Remove all nodes and connections from the graph </summary>
|
||||
public void Clear() {
|
||||
if (Application.isPlaying) {
|
||||
for (int i = 0; i < nodes.Count; i++) {
|
||||
Destroy(nodes[i]);
|
||||
}
|
||||
}
|
||||
nodes.Clear();
|
||||
}
|
||||
|
||||
@ -67,5 +73,10 @@ namespace XNode {
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
private void OnDestroy() {
|
||||
// Remove all nodes prior to graph destruction
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,7 +190,7 @@ namespace XNode {
|
||||
public void Connect(NodePort port) {
|
||||
if (connections == null) connections = new List<PortConnection>();
|
||||
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("Cannot connect port to self."); return; }
|
||||
if (IsConnectedTo(port)) { Debug.LogWarning("Port already connected. "); return; }
|
||||
if (direction == port.direction) { Debug.LogWarning("Cannot connect two " + (direction == IO.Input ? "input" : "output") + " connections"); return; }
|
||||
if (port.connectionType == Node.ConnectionType.Override && port.ConnectionCount != 0) { port.ClearConnections(); }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user