mirror of
https://github.com/Siccity/xNode.git
synced 2025-12-22 02:06:05 +08:00
Merge branch 'master' of https://github.com/Siccity/xNode.git into examples
This commit is contained in:
commit
bccd87a199
1
.gitignore
vendored
1
.gitignore
vendored
@ -20,5 +20,6 @@
|
|||||||
# Unity3D Generated File On Crash Reports
|
# Unity3D Generated File On Crash Reports
|
||||||
sysinfo.txt
|
sysinfo.txt
|
||||||
|
|
||||||
|
/Examples/
|
||||||
README.md.meta
|
README.md.meta
|
||||||
LICENSE.md.meta
|
LICENSE.md.meta
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
[](https://raw.githubusercontent.com/Siccity/xNode/master/LICENSE.md)
|
[](https://raw.githubusercontent.com/Siccity/xNode/master/LICENSE.md)
|
||||||
[](https://github.com/Siccity/xNode/wiki)
|
[](https://github.com/Siccity/xNode/wiki)
|
||||||
|
|
||||||
[Go to Downloads](https://github.com/Siccity/xNode/releases)
|
[Go to Downloads](https://github.com/Siccity/xNode/releases) / [Go to Asset Store](http://u3d.as/108S)
|
||||||
|
|
||||||
### xNode
|
### 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.
|
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.
|
||||||
|
|||||||
@ -8,7 +8,7 @@ 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>
|
/// <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))]
|
[CustomNodeEditor(typeof(XNode.Node))]
|
||||||
public class NodeEditor : XNodeInternal.NodeEditorBase<NodeEditor, NodeEditor.CustomNodeEditorAttribute, XNode.Node> {
|
public class NodeEditor : XNodeEditor.Internal.NodeEditorBase<NodeEditor, NodeEditor.CustomNodeEditorAttribute, XNode.Node> {
|
||||||
|
|
||||||
/// <summary> Fires every whenever a node was modified through the editor </summary>
|
/// <summary> Fires every whenever a node was modified through the editor </summary>
|
||||||
public static Action<XNode.Node> onUpdateNode;
|
public static Action<XNode.Node> onUpdateNode;
|
||||||
@ -54,7 +54,7 @@ namespace XNodeEditor {
|
|||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
public class CustomNodeEditorAttribute : Attribute,
|
public class CustomNodeEditorAttribute : Attribute,
|
||||||
XNodeInternal.NodeEditorBase<NodeEditor, NodeEditor.CustomNodeEditorAttribute, XNode.Node>.INodeEditorAttrib {
|
XNodeEditor.Internal.NodeEditorBase<NodeEditor, NodeEditor.CustomNodeEditorAttribute, XNode.Node>.INodeEditorAttrib {
|
||||||
private Type inspectedType;
|
private Type inspectedType;
|
||||||
/// <summary> Tells a NodeEditor which Node type it is an editor for </summary>
|
/// <summary> Tells a NodeEditor which Node type it is an editor for </summary>
|
||||||
/// <param name="inspectedType">Type that this editor can edit</param>
|
/// <param name="inspectedType">Type that this editor can edit</param>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@ -46,7 +47,11 @@ namespace XNodeEditor {
|
|||||||
if (Selection.objects[i] is XNode.Node) {
|
if (Selection.objects[i] is XNode.Node) {
|
||||||
XNode.Node node = Selection.objects[i] as XNode.Node;
|
XNode.Node node = Selection.objects[i] as XNode.Node;
|
||||||
node.position = WindowToGridPosition(e.mousePosition) + dragOffset[i];
|
node.position = WindowToGridPosition(e.mousePosition) + dragOffset[i];
|
||||||
if (NodeEditorPreferences.GridSnap) {
|
bool gridSnap = NodeEditorPreferences.GetSettings().gridSnap;
|
||||||
|
if (e.control) {
|
||||||
|
gridSnap = !gridSnap;
|
||||||
|
}
|
||||||
|
if (gridSnap) {
|
||||||
node.position.x = (Mathf.Round((node.position.x + 8) / 16) * 16) - 8;
|
node.position.x = (Mathf.Round((node.position.x + 8) / 16) * 16) - 8;
|
||||||
node.position.y = (Mathf.Round((node.position.y + 8) / 16) * 16) - 8;
|
node.position.y = (Mathf.Round((node.position.y + 8) / 16) * 16) - 8;
|
||||||
}
|
}
|
||||||
@ -197,16 +202,42 @@ namespace XNodeEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// <summary> Dublicate selected nodes and select the dublicates
|
/// <summary> Dublicate selected nodes and select the dublicates </summary>
|
||||||
public void DublicateSelectedNodes() {
|
public void DublicateSelectedNodes() {
|
||||||
UnityEngine.Object[] newNodes = new UnityEngine.Object[Selection.objects.Length];
|
UnityEngine.Object[] newNodes = new UnityEngine.Object[Selection.objects.Length];
|
||||||
|
Dictionary<XNode.Node, XNode.Node> substitutes = new Dictionary<XNode.Node, XNode.Node>();
|
||||||
for (int i = 0; i < Selection.objects.Length; i++) {
|
for (int i = 0; i < Selection.objects.Length; i++) {
|
||||||
if (Selection.objects[i] is XNode.Node) {
|
if (Selection.objects[i] is XNode.Node) {
|
||||||
XNode.Node node = Selection.objects[i] as XNode.Node;
|
XNode.Node srcNode = Selection.objects[i] as XNode.Node;
|
||||||
if (node.graph != graph) continue; // ignore nodes selected in another graph
|
if (srcNode.graph != graph) continue; // ignore nodes selected in another graph
|
||||||
XNode.Node n = graph.CopyNode(node);
|
XNode.Node newNode = graph.CopyNode(srcNode);
|
||||||
n.position = node.position + new Vector2(30, 30);
|
substitutes.Add(srcNode, newNode);
|
||||||
newNodes[i] = n;
|
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 (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);
|
||||||
|
|
||||||
|
if (substitutes.ContainsKey(inputPort.node) && substitutes.ContainsKey(outputPort.node)) {
|
||||||
|
XNode.Node newNodeIn = substitutes[inputPort.node];
|
||||||
|
XNode.Node newNodeOut = substitutes[outputPort.node];
|
||||||
|
newNodeIn.UpdateStaticPorts();
|
||||||
|
newNodeOut.UpdateStaticPorts();
|
||||||
|
inputPort = newNodeIn.GetInputPort(inputPort.fieldName);
|
||||||
|
outputPort = newNodeOut.GetOutputPort(outputPort.fieldName);
|
||||||
|
}
|
||||||
|
if (!inputPort.IsConnectedTo(outputPort)) inputPort.Connect(outputPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Selection.objects = newNodes;
|
Selection.objects = newNodes;
|
||||||
|
|||||||
@ -5,11 +5,12 @@ using System.Reflection;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
|
||||||
namespace XNodeInternal {
|
namespace XNodeEditor.Internal {
|
||||||
/// <summary> Handles caching of custom editor classes and their target types. Accessible with GetEditor(Type type) </summary>
|
/// <summary> Handles caching of custom editor classes and their target types. Accessible with GetEditor(Type type) </summary>
|
||||||
public class NodeEditorBase<T, A, K> where A : Attribute, NodeEditorBase<T, A, K>.INodeEditorAttrib where T : NodeEditorBase<T,A,K> where K : ScriptableObject {
|
public class NodeEditorBase<T, A, K> where A : Attribute, NodeEditorBase<T, A, K>.INodeEditorAttrib where T : NodeEditorBase<T,A,K> where K : ScriptableObject {
|
||||||
/// <summary> Custom editors defined with [CustomNodeEditor] </summary>
|
/// <summary> Custom editors defined with [CustomNodeEditor] </summary>
|
||||||
private static Dictionary<Type, T> editors;
|
private static Dictionary<Type, T> editors;
|
||||||
|
private static Dictionary<ScriptableObject, SerializedObject> serializeds;
|
||||||
public K target;
|
public K target;
|
||||||
public SerializedObject serializedObject;
|
public SerializedObject serializedObject;
|
||||||
|
|
||||||
@ -18,10 +19,17 @@ namespace XNodeInternal {
|
|||||||
Type type = target.GetType();
|
Type type = target.GetType();
|
||||||
T editor = GetEditor(type);
|
T editor = GetEditor(type);
|
||||||
editor.target = target;
|
editor.target = target;
|
||||||
editor.serializedObject = new SerializedObject(target);
|
editor.serializedObject = GetSerialized(target);
|
||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static SerializedObject GetSerialized(K target) {
|
||||||
|
if (target == null) return null;
|
||||||
|
if (serializeds == null) serializeds = new Dictionary<ScriptableObject, SerializedObject>();
|
||||||
|
if (!serializeds.ContainsKey(target)) serializeds.Add(target, new SerializedObject(target));
|
||||||
|
return serializeds[target];
|
||||||
|
}
|
||||||
|
|
||||||
private static T GetEditor(Type type) {
|
private static T GetEditor(Type type) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
if (editors == null) CacheCustomEditors();
|
if (editors == null) CacheCustomEditors();
|
||||||
|
|||||||
@ -6,14 +6,14 @@ using UnityEngine;
|
|||||||
namespace XNodeEditor {
|
namespace XNodeEditor {
|
||||||
/// <summary> Contains GUI methods </summary>
|
/// <summary> Contains GUI methods </summary>
|
||||||
public partial class NodeEditorWindow {
|
public partial class NodeEditorWindow {
|
||||||
private NodeGraphEditor currentGraphEditor;
|
public NodeGraphEditor graphEditor;
|
||||||
private List<UnityEngine.Object> selectionCache;
|
private List<UnityEngine.Object> selectionCache;
|
||||||
|
|
||||||
private void OnGUI() {
|
private void OnGUI() {
|
||||||
Event e = Event.current;
|
Event e = Event.current;
|
||||||
Matrix4x4 m = GUI.matrix;
|
Matrix4x4 m = GUI.matrix;
|
||||||
if (graph == null) return;
|
if (graph == null) return;
|
||||||
currentGraphEditor = NodeGraphEditor.GetEditor(graph);
|
graphEditor = NodeGraphEditor.GetEditor(graph);
|
||||||
|
|
||||||
Controls();
|
Controls();
|
||||||
|
|
||||||
@ -52,8 +52,8 @@ namespace XNodeEditor {
|
|||||||
rect.position = Vector2.zero;
|
rect.position = Vector2.zero;
|
||||||
|
|
||||||
Vector2 center = rect.size / 2f;
|
Vector2 center = rect.size / 2f;
|
||||||
Texture2D gridTex = currentGraphEditor.GetGridTexture();
|
Texture2D gridTex = graphEditor.GetGridTexture();
|
||||||
Texture2D crossTex = currentGraphEditor.GetSecondaryGridTexture();
|
Texture2D crossTex = graphEditor.GetSecondaryGridTexture();
|
||||||
|
|
||||||
// Offset from origin in tile units
|
// Offset from origin in tile units
|
||||||
float xOffset = -(center.x * zoom + panOffset.x) / gridTex.width;
|
float xOffset = -(center.x * zoom + panOffset.x) / gridTex.width;
|
||||||
@ -122,7 +122,7 @@ namespace XNodeEditor {
|
|||||||
Type type = nodeTypes[i];
|
Type type = nodeTypes[i];
|
||||||
|
|
||||||
//Get node context menu path
|
//Get node context menu path
|
||||||
string path = currentGraphEditor.GetNodePath(type);
|
string path = graphEditor.GetNodePath(type);
|
||||||
if (path == null) continue;
|
if (path == null) continue;
|
||||||
|
|
||||||
contextMenu.AddItem(new GUIContent(path), false, () => {
|
contextMenu.AddItem(new GUIContent(path), false, () => {
|
||||||
@ -151,6 +151,8 @@ namespace XNodeEditor {
|
|||||||
startPoint = GridToWindowPosition(startPoint);
|
startPoint = GridToWindowPosition(startPoint);
|
||||||
endPoint = GridToWindowPosition(endPoint);
|
endPoint = GridToWindowPosition(endPoint);
|
||||||
|
|
||||||
|
switch (NodeEditorPreferences.GetSettings().noodleType) {
|
||||||
|
case NodeEditorPreferences.NoodleType.Curve:
|
||||||
Vector2 startTangent = startPoint;
|
Vector2 startTangent = startPoint;
|
||||||
if (startPoint.x < endPoint.x) startTangent.x = Mathf.LerpUnclamped(startPoint.x, endPoint.x, 0.7f);
|
if (startPoint.x < endPoint.x) startTangent.x = Mathf.LerpUnclamped(startPoint.x, endPoint.x, 0.7f);
|
||||||
else startTangent.x = Mathf.LerpUnclamped(startPoint.x, endPoint.x, -0.7f);
|
else startTangent.x = Mathf.LerpUnclamped(startPoint.x, endPoint.x, -0.7f);
|
||||||
@ -158,8 +160,41 @@ namespace XNodeEditor {
|
|||||||
Vector2 endTangent = endPoint;
|
Vector2 endTangent = endPoint;
|
||||||
if (startPoint.x > endPoint.x) endTangent.x = Mathf.LerpUnclamped(endPoint.x, startPoint.x, -0.7f);
|
if (startPoint.x > endPoint.x) endTangent.x = Mathf.LerpUnclamped(endPoint.x, startPoint.x, -0.7f);
|
||||||
else endTangent.x = Mathf.LerpUnclamped(endPoint.x, startPoint.x, 0.7f);
|
else endTangent.x = Mathf.LerpUnclamped(endPoint.x, startPoint.x, 0.7f);
|
||||||
|
|
||||||
Handles.DrawBezier(startPoint, endPoint, startTangent, endTangent, col, null, 4);
|
Handles.DrawBezier(startPoint, endPoint, startTangent, endTangent, col, null, 4);
|
||||||
|
break;
|
||||||
|
case NodeEditorPreferences.NoodleType.Line:
|
||||||
|
Handles.color = col;
|
||||||
|
Handles.DrawAAPolyLine(5, startPoint, endPoint);
|
||||||
|
break;
|
||||||
|
case NodeEditorPreferences.NoodleType.Angled:
|
||||||
|
Handles.color = col;
|
||||||
|
if (startPoint.x <= endPoint.x - (50 / zoom)) {
|
||||||
|
float midpoint = (startPoint.x + endPoint.x) * 0.5f;
|
||||||
|
Vector2 start_1 = startPoint;
|
||||||
|
Vector2 end_1 = endPoint;
|
||||||
|
start_1.x = midpoint;
|
||||||
|
end_1.x = midpoint;
|
||||||
|
Handles.DrawAAPolyLine(5, startPoint, start_1);
|
||||||
|
Handles.DrawAAPolyLine(5, start_1, end_1);
|
||||||
|
Handles.DrawAAPolyLine(5, end_1, endPoint);
|
||||||
|
} else {
|
||||||
|
float midpoint = (startPoint.y + endPoint.y) * 0.5f;
|
||||||
|
Vector2 start_1 = startPoint;
|
||||||
|
Vector2 end_1 = endPoint;
|
||||||
|
start_1.x += 25 / zoom;
|
||||||
|
end_1.x -= 25 / zoom;
|
||||||
|
Vector2 start_2 = start_1;
|
||||||
|
Vector2 end_2 = end_1;
|
||||||
|
start_2.y = midpoint;
|
||||||
|
end_2.y = midpoint;
|
||||||
|
Handles.DrawAAPolyLine(5, startPoint, start_1);
|
||||||
|
Handles.DrawAAPolyLine(5, start_1, start_2);
|
||||||
|
Handles.DrawAAPolyLine(5, start_2, end_2);
|
||||||
|
Handles.DrawAAPolyLine(5, end_2, end_1);
|
||||||
|
Handles.DrawAAPolyLine(5, end_1, endPoint);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Draws all connections </summary>
|
/// <summary> Draws all connections </summary>
|
||||||
@ -179,7 +214,7 @@ namespace XNodeEditor {
|
|||||||
if (!input.IsConnectedTo(output)) input.Connect(output);
|
if (!input.IsConnectedTo(output)) input.Connect(output);
|
||||||
if (!_portConnectionPoints.ContainsKey(input)) continue;
|
if (!_portConnectionPoints.ContainsKey(input)) continue;
|
||||||
Vector2 to = _portConnectionPoints[input].center;
|
Vector2 to = _portConnectionPoints[input].center;
|
||||||
Color connectionColor = currentGraphEditor.GetTypeColor(output.ValueType);
|
Color connectionColor = graphEditor.GetTypeColor(output.ValueType);
|
||||||
DrawConnection(from, to, connectionColor);
|
DrawConnection(from, to, connectionColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +248,7 @@ namespace XNodeEditor {
|
|||||||
hoveredPort = null;
|
hoveredPort = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UnityEngine.Object> preSelection = new List<UnityEngine.Object>(preBoxSelection);
|
List<UnityEngine.Object> preSelection = preBoxSelection != null ? new List<UnityEngine.Object>(preBoxSelection) : new List<UnityEngine.Object>();
|
||||||
|
|
||||||
//Save guiColor so we can revert it
|
//Save guiColor so we can revert it
|
||||||
Color guiColor = GUI.color;
|
Color guiColor = GUI.color;
|
||||||
@ -240,7 +275,7 @@ namespace XNodeEditor {
|
|||||||
style.padding = new RectOffset();
|
style.padding = new RectOffset();
|
||||||
GUI.color = nodeEditor.GetTint();
|
GUI.color = nodeEditor.GetTint();
|
||||||
GUILayout.BeginVertical(new GUIStyle(style));
|
GUILayout.BeginVertical(new GUIStyle(style));
|
||||||
GUI.color = NodeEditorPreferences.HighlightColor;
|
GUI.color = NodeEditorPreferences.GetSettings().highlightColor;
|
||||||
GUILayout.BeginVertical(new GUIStyle(highlightStyle));
|
GUILayout.BeginVertical(new GUIStyle(highlightStyle));
|
||||||
} else {
|
} else {
|
||||||
GUIStyle style = NodeEditorResources.styles.nodeBody;
|
GUIStyle style = NodeEditorResources.styles.nodeBody;
|
||||||
|
|||||||
@ -92,7 +92,7 @@ namespace XNodeEditor {
|
|||||||
|
|
||||||
Color backgroundColor = new Color32(90, 97, 105, 255);
|
Color backgroundColor = new Color32(90, 97, 105, 255);
|
||||||
if (NodeEditorWindow.nodeTint.ContainsKey(port.node.GetType())) backgroundColor *= NodeEditorWindow.nodeTint[port.node.GetType()];
|
if (NodeEditorWindow.nodeTint.ContainsKey(port.node.GetType())) backgroundColor *= NodeEditorWindow.nodeTint[port.node.GetType()];
|
||||||
Color col = NodeGraphEditor.GetEditor(port.node.graph).GetTypeColor(port.ValueType);
|
Color col = NodeEditorWindow.current.graphEditor.GetTypeColor(port.ValueType);
|
||||||
DrawPortHandle(rect, backgroundColor, col);
|
DrawPortHandle(rect, backgroundColor, col);
|
||||||
|
|
||||||
// Register the handle position
|
// Register the handle position
|
||||||
@ -119,7 +119,7 @@ namespace XNodeEditor {
|
|||||||
|
|
||||||
Color backgroundColor = new Color32(90, 97, 105, 255);
|
Color backgroundColor = new Color32(90, 97, 105, 255);
|
||||||
if (NodeEditorWindow.nodeTint.ContainsKey(port.node.GetType())) backgroundColor *= NodeEditorWindow.nodeTint[port.node.GetType()];
|
if (NodeEditorWindow.nodeTint.ContainsKey(port.node.GetType())) backgroundColor *= NodeEditorWindow.nodeTint[port.node.GetType()];
|
||||||
Color col = NodeGraphEditor.GetEditor(port.node.graph).GetTypeColor(port.ValueType);
|
Color col = NodeEditorWindow.current.graphEditor.GetTypeColor(port.ValueType);
|
||||||
DrawPortHandle(rect, backgroundColor, col);
|
DrawPortHandle(rect, backgroundColor, col);
|
||||||
|
|
||||||
// Register the handle position
|
// Register the handle position
|
||||||
|
|||||||
@ -5,38 +5,44 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace XNodeEditor {
|
namespace XNodeEditor {
|
||||||
public static class NodeEditorPreferences {
|
public static class NodeEditorPreferences {
|
||||||
|
public enum NoodleType { Curve, Line, Angled }
|
||||||
|
|
||||||
public static Texture2D gridTexture {
|
/// <summary> The last editor we checked. This should be the one we modify </summary>
|
||||||
|
private static XNodeEditor.NodeGraphEditor lastEditor;
|
||||||
|
/// <summary> The last key we checked. This should be the one we modify </summary>
|
||||||
|
private static string lastKey = "xNode.Settings";
|
||||||
|
|
||||||
|
private static Dictionary<string, Color> typeColors = new Dictionary<string, Color>();
|
||||||
|
private static Dictionary<string, Settings> settings = new Dictionary<string, Settings>();
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
public class Settings : ISerializationCallbackReceiver {
|
||||||
|
[SerializeField] private Color32 _gridLineColor = new Color(0.45f, 0.45f, 0.45f);
|
||||||
|
public Color32 gridLineColor { get { return _gridLineColor; } set { _gridLineColor = value; _gridTexture = null; _crossTexture = null; } }
|
||||||
|
|
||||||
|
[SerializeField] private Color32 _gridBgColor = new Color(0.18f, 0.18f, 0.18f);
|
||||||
|
public Color32 gridBgColor { get { return _gridBgColor; } set { _gridBgColor = value; _gridTexture = null; } }
|
||||||
|
|
||||||
|
public Color32 highlightColor = new Color32(255, 255, 255, 255);
|
||||||
|
public bool gridSnap = true;
|
||||||
|
[SerializeField] private string typeColorsData = "";
|
||||||
|
[NonSerialized] public Dictionary<string, Color> typeColors = new Dictionary<string, Color>();
|
||||||
|
public NoodleType noodleType = NoodleType.Curve;
|
||||||
|
|
||||||
|
private Texture2D _gridTexture;
|
||||||
|
public Texture2D gridTexture {
|
||||||
get {
|
get {
|
||||||
VerifyLoaded();
|
if (_gridTexture == null) _gridTexture = NodeEditorResources.GenerateGridTexture(gridLineColor, gridBgColor);
|
||||||
if (_gridTexture == null) _gridTexture = NodeEditorResources.GenerateGridTexture(settings.gridLineColor, settings.gridBgColor);
|
|
||||||
return _gridTexture;
|
return _gridTexture;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static Texture2D _gridTexture;
|
private Texture2D _crossTexture;
|
||||||
public static Texture2D crossTexture {
|
public Texture2D crossTexture {
|
||||||
get {
|
get {
|
||||||
VerifyLoaded();
|
if (_crossTexture == null) _crossTexture = NodeEditorResources.GenerateCrossTexture(gridLineColor);
|
||||||
if (_crossTexture == null) _crossTexture = NodeEditorResources.GenerateCrossTexture(settings.gridLineColor);
|
|
||||||
return _crossTexture;
|
return _crossTexture;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static Texture2D _crossTexture;
|
|
||||||
|
|
||||||
public static bool GridSnap { get { VerifyLoaded(); return settings.gridSnap; } }
|
|
||||||
public static Color HighlightColor { get { VerifyLoaded(); return settings.highlightColor; } }
|
|
||||||
|
|
||||||
private static Dictionary<string, Color> typeColors = new Dictionary<string, Color>();
|
|
||||||
private static Settings settings;
|
|
||||||
|
|
||||||
[System.Serializable]
|
|
||||||
private class Settings : ISerializationCallbackReceiver {
|
|
||||||
public Color32 gridLineColor = new Color(0.45f, 0.45f, 0.45f);
|
|
||||||
public Color32 gridBgColor = new Color(0.18f, 0.18f, 0.18f);
|
|
||||||
public Color32 highlightColor = new Color32(255, 223, 255, 255);
|
|
||||||
public bool gridSnap = true;
|
|
||||||
public string typeColorsData = "";
|
|
||||||
public Dictionary<string, Color> typeColors = new Dictionary<string, Color>();
|
|
||||||
|
|
||||||
public void OnAfterDeserialize() {
|
public void OnAfterDeserialize() {
|
||||||
// Deserialize typeColorsData
|
// Deserialize typeColorsData
|
||||||
@ -59,19 +65,34 @@ namespace XNodeEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Get settings of current active editor </summary>
|
||||||
|
public static Settings GetSettings() {
|
||||||
|
if (lastEditor != XNodeEditor.NodeEditorWindow.current.graphEditor) {
|
||||||
|
object[] attribs = XNodeEditor.NodeEditorWindow.current.graphEditor.GetType().GetCustomAttributes(typeof(XNodeEditor.NodeGraphEditor.CustomNodeGraphEditorAttribute), true);
|
||||||
|
if (attribs.Length == 1) {
|
||||||
|
XNodeEditor.NodeGraphEditor.CustomNodeGraphEditorAttribute attrib = attribs[0] as XNodeEditor.NodeGraphEditor.CustomNodeGraphEditorAttribute;
|
||||||
|
lastEditor = XNodeEditor.NodeEditorWindow.current.graphEditor;
|
||||||
|
lastKey = attrib.editorPrefsKey;
|
||||||
|
VerifyLoaded();
|
||||||
|
} else return null;
|
||||||
|
}
|
||||||
|
return settings[lastKey];
|
||||||
|
}
|
||||||
|
|
||||||
[PreferenceItem("Node Editor")]
|
[PreferenceItem("Node Editor")]
|
||||||
private static void PreferencesGUI() {
|
private static void PreferencesGUI() {
|
||||||
VerifyLoaded();
|
VerifyLoaded();
|
||||||
|
Settings settings = NodeEditorPreferences.settings[lastKey];
|
||||||
|
|
||||||
NodeSettingsGUI();
|
NodeSettingsGUI(lastKey, settings);
|
||||||
GridSettingsGUI();
|
GridSettingsGUI(lastKey, settings);
|
||||||
TypeColorsGUI();
|
TypeColorsGUI(lastKey, settings);
|
||||||
if (GUILayout.Button(new GUIContent("Set Default", "Reset all values to default"), GUILayout.Width(120))) {
|
if (GUILayout.Button(new GUIContent("Set Default", "Reset all values to default"), GUILayout.Width(120))) {
|
||||||
ResetPrefs();
|
ResetPrefs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GridSettingsGUI() {
|
private static void GridSettingsGUI(string key, Settings settings) {
|
||||||
//Label
|
//Label
|
||||||
EditorGUILayout.LabelField("Grid", EditorStyles.boldLabel);
|
EditorGUILayout.LabelField("Grid", EditorStyles.boldLabel);
|
||||||
settings.gridSnap = EditorGUILayout.Toggle("Snap", settings.gridSnap);
|
settings.gridSnap = EditorGUILayout.Toggle("Snap", settings.gridSnap);
|
||||||
@ -79,75 +100,74 @@ namespace XNodeEditor {
|
|||||||
settings.gridLineColor = EditorGUILayout.ColorField("Color", settings.gridLineColor);
|
settings.gridLineColor = EditorGUILayout.ColorField("Color", settings.gridLineColor);
|
||||||
settings.gridBgColor = EditorGUILayout.ColorField(" ", settings.gridBgColor);
|
settings.gridBgColor = EditorGUILayout.ColorField(" ", settings.gridBgColor);
|
||||||
if (GUI.changed) {
|
if (GUI.changed) {
|
||||||
SavePrefs();
|
SavePrefs(key, settings);
|
||||||
_gridTexture = NodeEditorResources.GenerateGridTexture(settings.gridLineColor, settings.gridBgColor);
|
|
||||||
_crossTexture = NodeEditorResources.GenerateCrossTexture(settings.gridLineColor);
|
|
||||||
NodeEditorWindow.RepaintAll();
|
NodeEditorWindow.RepaintAll();
|
||||||
}
|
}
|
||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void NodeSettingsGUI() {
|
private static void NodeSettingsGUI(string key, Settings settings) {
|
||||||
//Label
|
//Label
|
||||||
EditorGUILayout.LabelField("Node", EditorStyles.boldLabel);
|
EditorGUILayout.LabelField("Node", EditorStyles.boldLabel);
|
||||||
settings.highlightColor = EditorGUILayout.ColorField("Selection", settings.highlightColor);
|
settings.highlightColor = EditorGUILayout.ColorField("Selection", settings.highlightColor);
|
||||||
|
settings.noodleType = (NoodleType) EditorGUILayout.EnumPopup("Noodle type", (Enum) settings.noodleType);
|
||||||
if (GUI.changed) {
|
if (GUI.changed) {
|
||||||
SavePrefs();
|
SavePrefs(key, settings);
|
||||||
NodeEditorWindow.RepaintAll();
|
NodeEditorWindow.RepaintAll();
|
||||||
}
|
}
|
||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void TypeColorsGUI() {
|
private static void TypeColorsGUI(string key, Settings settings) {
|
||||||
//Label
|
//Label
|
||||||
EditorGUILayout.LabelField("Types", EditorStyles.boldLabel);
|
EditorGUILayout.LabelField("Types", EditorStyles.boldLabel);
|
||||||
|
|
||||||
//Display type colors. Save them if they are edited by the user
|
//Display type colors. Save them if they are edited by the user
|
||||||
List<string> keys = new List<string>(typeColors.Keys);
|
List<string> typeColorKeys = new List<string>(typeColors.Keys);
|
||||||
foreach (string key in keys) {
|
foreach (string typeColorKey in typeColorKeys) {
|
||||||
Color col = typeColors[key];
|
Color col = typeColors[typeColorKey];
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
col = EditorGUILayout.ColorField(key, col);
|
col = EditorGUILayout.ColorField(typeColorKey, col);
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
if (EditorGUI.EndChangeCheck()) {
|
if (EditorGUI.EndChangeCheck()) {
|
||||||
typeColors[key] = col;
|
typeColors[typeColorKey] = col;
|
||||||
if (settings.typeColors.ContainsKey(key)) settings.typeColors[key] = col;
|
if (settings.typeColors.ContainsKey(typeColorKey)) settings.typeColors[typeColorKey] = col;
|
||||||
else settings.typeColors.Add(key, col);
|
else settings.typeColors.Add(typeColorKey, col);
|
||||||
SavePrefs();
|
SavePrefs(typeColorKey, settings);
|
||||||
NodeEditorWindow.RepaintAll();
|
NodeEditorWindow.RepaintAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Load prefs if they exist. Create if they don't </summary>
|
||||||
private static Settings LoadPrefs() {
|
private static Settings LoadPrefs() {
|
||||||
// Remove obsolete editorprefs
|
// Create settings if it doesn't exist
|
||||||
if (EditorPrefs.HasKey("xnode_typecolors")) EditorPrefs.DeleteKey("xnode_typecolors");
|
if (!EditorPrefs.HasKey(lastKey)) {
|
||||||
if (EditorPrefs.HasKey("xnode_gridcolor0")) EditorPrefs.DeleteKey("xnode_gridcolor0");
|
if (lastEditor != null) EditorPrefs.SetString(lastKey, JsonUtility.ToJson(lastEditor.GetDefaultPreferences()));
|
||||||
if (EditorPrefs.HasKey("xnode_gridcolor1")) EditorPrefs.DeleteKey("xnode_gridcolor1");
|
else EditorPrefs.SetString(lastKey, JsonUtility.ToJson(new Settings()));
|
||||||
if (EditorPrefs.HasKey("xnode_gridsnap")) EditorPrefs.DeleteKey("xnode_gridcolor1");
|
}
|
||||||
|
return JsonUtility.FromJson<Settings>(EditorPrefs.GetString(lastKey));
|
||||||
if (!EditorPrefs.HasKey("xNode.Settings")) EditorPrefs.SetString("xNode.Settings", JsonUtility.ToJson(new Settings()));
|
|
||||||
return JsonUtility.FromJson<Settings>(EditorPrefs.GetString("xNode.Settings"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Delete all prefs </summary>
|
/// <summary> Delete all prefs </summary>
|
||||||
public static void ResetPrefs() {
|
public static void ResetPrefs() {
|
||||||
if (EditorPrefs.HasKey("xNode.Settings")) EditorPrefs.DeleteKey("xNode.Settings");
|
if (EditorPrefs.HasKey(lastKey)) EditorPrefs.DeleteKey(lastKey);
|
||||||
|
if (settings.ContainsKey(lastKey)) settings.Remove(lastKey);
|
||||||
settings = LoadPrefs();
|
|
||||||
typeColors = new Dictionary<string, Color>();
|
typeColors = new Dictionary<string, Color>();
|
||||||
_gridTexture = NodeEditorResources.GenerateGridTexture(settings.gridLineColor, settings.gridBgColor);
|
VerifyLoaded();
|
||||||
_crossTexture = NodeEditorResources.GenerateCrossTexture(settings.gridLineColor);
|
|
||||||
NodeEditorWindow.RepaintAll();
|
NodeEditorWindow.RepaintAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SavePrefs() {
|
/// <summary> Save preferences in EditorPrefs </summary>
|
||||||
EditorPrefs.SetString("xNode.Settings", JsonUtility.ToJson(settings));
|
private static void SavePrefs(string key, Settings settings) {
|
||||||
|
EditorPrefs.SetString(key, JsonUtility.ToJson(settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Check if we have loaded settings for given key. If not, load them </summary>
|
||||||
private static void VerifyLoaded() {
|
private static void VerifyLoaded() {
|
||||||
if (settings == null) settings = LoadPrefs();
|
if (!settings.ContainsKey(lastKey)) settings.Add(lastKey, LoadPrefs());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Return color based on type </summary>
|
/// <summary> Return color based on type </summary>
|
||||||
@ -156,7 +176,7 @@ namespace XNodeEditor {
|
|||||||
if (type == null) return Color.gray;
|
if (type == null) return Color.gray;
|
||||||
string typeName = type.PrettyName();
|
string typeName = type.PrettyName();
|
||||||
if (!typeColors.ContainsKey(typeName)) {
|
if (!typeColors.ContainsKey(typeName)) {
|
||||||
if (settings.typeColors.ContainsKey(typeName)) typeColors.Add(typeName, settings.typeColors[typeName]);
|
if (settings[lastKey].typeColors.ContainsKey(typeName)) typeColors.Add(typeName, settings[lastKey].typeColors[typeName]);
|
||||||
else {
|
else {
|
||||||
#if UNITY_5_4_OR_NEWER
|
#if UNITY_5_4_OR_NEWER
|
||||||
UnityEngine.Random.InitState(typeName.GetHashCode());
|
UnityEngine.Random.InitState(typeName.GetHashCode());
|
||||||
|
|||||||
@ -7,16 +7,21 @@ using UnityEngine;
|
|||||||
namespace XNodeEditor {
|
namespace XNodeEditor {
|
||||||
/// <summary> Base class to derive custom Node Graph editors from. Use this to override how graphs are drawn in the editor. </summary>
|
/// <summary> Base class to derive custom Node Graph editors from. Use this to override how graphs are drawn in the editor. </summary>
|
||||||
[CustomNodeGraphEditor(typeof(XNode.NodeGraph))]
|
[CustomNodeGraphEditor(typeof(XNode.NodeGraph))]
|
||||||
public class NodeGraphEditor : XNodeInternal.NodeEditorBase<NodeGraphEditor, NodeGraphEditor.CustomNodeGraphEditorAttribute, XNode.NodeGraph> {
|
public class NodeGraphEditor : XNodeEditor.Internal.NodeEditorBase<NodeGraphEditor, NodeGraphEditor.CustomNodeGraphEditorAttribute, XNode.NodeGraph> {
|
||||||
/// <summary> Custom node editors defined with [CustomNodeGraphEditor] </summary>
|
/// <summary> Custom node editors defined with [CustomNodeGraphEditor] </summary>
|
||||||
[NonSerialized] private static Dictionary<Type, NodeGraphEditor> editors;
|
[NonSerialized] private static Dictionary<Type, NodeGraphEditor> editors;
|
||||||
|
|
||||||
public virtual Texture2D GetGridTexture() {
|
public virtual Texture2D GetGridTexture() {
|
||||||
return NodeEditorPreferences.gridTexture;
|
return NodeEditorPreferences.GetSettings().gridTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Texture2D GetSecondaryGridTexture() {
|
public virtual Texture2D GetSecondaryGridTexture() {
|
||||||
return NodeEditorPreferences.crossTexture;
|
return NodeEditorPreferences.GetSettings().crossTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Return default settings for this graph type. This is the settings the user will load if no previous settings have been saved. </summary>
|
||||||
|
public virtual NodeEditorPreferences.Settings GetDefaultPreferences() {
|
||||||
|
return new NodeEditorPreferences.Settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Returns context menu path. Returns null if node is not available. </summary>
|
/// <summary> Returns context menu path. Returns null if node is not available. </summary>
|
||||||
@ -35,13 +40,15 @@ namespace XNodeEditor {
|
|||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
public class CustomNodeGraphEditorAttribute : Attribute,
|
public class CustomNodeGraphEditorAttribute : Attribute,
|
||||||
XNodeInternal.NodeEditorBase<NodeGraphEditor, NodeGraphEditor.CustomNodeGraphEditorAttribute, XNode.NodeGraph>.INodeEditorAttrib {
|
XNodeEditor.Internal.NodeEditorBase<NodeGraphEditor, NodeGraphEditor.CustomNodeGraphEditorAttribute, XNode.NodeGraph>.INodeEditorAttrib {
|
||||||
private Type inspectedType;
|
private Type inspectedType;
|
||||||
/// <summary> Tells a NodeEditor which Node type it is an editor for </summary>
|
public string editorPrefsKey;
|
||||||
|
/// <summary> Tells a NodeGraphEditor which Graph type it is an editor for </summary>
|
||||||
/// <param name="inspectedType">Type that this editor can edit</param>
|
/// <param name="inspectedType">Type that this editor can edit</param>
|
||||||
/// <param name="contextMenuName">Path to the node</param>
|
/// <param name="uniquePreferencesID">Define unique key for unique layout settings instance</param>
|
||||||
public CustomNodeGraphEditorAttribute(Type inspectedType) {
|
public CustomNodeGraphEditorAttribute(Type inspectedType, string editorPrefsKey = "xNode.Settings") {
|
||||||
this.inspectedType = inspectedType;
|
this.inspectedType = inspectedType;
|
||||||
|
this.editorPrefsKey = editorPrefsKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type GetInspectedType() {
|
public Type GetInspectedType() {
|
||||||
|
|||||||
@ -61,10 +61,15 @@ namespace XNode {
|
|||||||
[SerializeField] private NodePortDictionary ports = new NodePortDictionary();
|
[SerializeField] private NodePortDictionary ports = new NodePortDictionary();
|
||||||
|
|
||||||
protected void OnEnable() {
|
protected void OnEnable() {
|
||||||
NodeDataCache.UpdatePorts(this, ports);
|
UpdateStaticPorts();
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Update static ports to reflect class fields. This happens automatically on enable. </summary>
|
||||||
|
public void UpdateStaticPorts() {
|
||||||
|
NodeDataCache.UpdatePorts(this, ports);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Initialize node. Called on creation. </summary>
|
/// <summary> Initialize node. Called on creation. </summary>
|
||||||
protected virtual void Init() { name = GetType().Name; }
|
protected virtual void Init() { name = GetType().Name; }
|
||||||
|
|
||||||
@ -124,7 +129,8 @@ namespace XNode {
|
|||||||
/// <summary> Removes all instance ports from the node </summary>
|
/// <summary> Removes all instance ports from the node </summary>
|
||||||
[ContextMenu("Clear instance ports")]
|
[ContextMenu("Clear instance ports")]
|
||||||
public void ClearInstancePorts() {
|
public void ClearInstancePorts() {
|
||||||
foreach (NodePort port in InstancePorts) {
|
List<NodePort> instancePorts = new List<NodePort>(InstancePorts);
|
||||||
|
foreach (NodePort port in instancePorts) {
|
||||||
RemoveInstancePort(port);
|
RemoveInstancePort(port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,10 +202,6 @@ namespace XNode {
|
|||||||
foreach (NodePort port in Ports) port.ClearConnections();
|
foreach (NodePort port in Ports) port.ClearConnections();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode() {
|
|
||||||
return JsonUtility.ToJson(this).GetHashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Mark a serializable field as an input port. You can access this through <see cref="GetInputPort(string)"/> </summary>
|
/// <summary> Mark a serializable field as an input port. You can access this through <see cref="GetInputPort(string)"/> </summary>
|
||||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
|
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
|
||||||
public class InputAttribute : Attribute {
|
public class InputAttribute : Attribute {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user