mirror of
https://github.com/Siccity/xNode.git
synced 2025-12-20 09:16:01 +08:00
Updated Node Editor Preferences window. Better separators. Added additional appearance options. Removed Rounding in GridToWindowPositionNoClipped() (and DrawGrid()) which was originally meant to fix UI Sharpness. But it did not have impact in my case and without it made panning feel much smoother.
291 lines
9.8 KiB
C#
291 lines
9.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using XNode;
|
|
using XNodeEditor.Internal;
|
|
#if ODIN_INSPECTOR
|
|
using Sirenix.OdinInspector.Editor;
|
|
using Sirenix.Utilities;
|
|
using Sirenix.Utilities.Editor;
|
|
#endif
|
|
|
|
#if UNITY_2019_1_OR_NEWER && USE_ADVANCED_GENERIC_MENU
|
|
using GenericMenu = XNodeEditor.AdvancedGenericMenu;
|
|
#endif
|
|
|
|
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(Node))]
|
|
public class NodeEditor : NodeEditorBase<NodeEditor, NodeEditor.CustomNodeEditorAttribute, Node>
|
|
{
|
|
/// <summary> Fires every whenever a node was modified through the editor </summary>
|
|
public static Action<Node> onUpdateNode;
|
|
public static readonly Dictionary<NodePort, Vector2> portPositions = new Dictionary<NodePort, Vector2>();
|
|
|
|
#if ODIN_INSPECTOR
|
|
protected internal static bool inNodeEditor = false;
|
|
#endif
|
|
|
|
public virtual void OnHeaderGUI()
|
|
{
|
|
GUILayout.Label(target.name, NodeEditorResources.styles.nodeHeaderLabel, GUILayout.Height(30));
|
|
}
|
|
|
|
/// <summary> Draws standard field editors for all public fields </summary>
|
|
public virtual void OnBodyGUI()
|
|
{
|
|
#if ODIN_INSPECTOR
|
|
inNodeEditor = true;
|
|
#endif
|
|
|
|
// Unity specifically requires this to save/update any serial object.
|
|
// serializedObject.Update(); must go at the start of an inspector gui, and
|
|
// serializedObject.ApplyModifiedProperties(); goes at the end.
|
|
serializedObject.Update();
|
|
string[] excludes = { "m_Script", "graph", "position", "ports" };
|
|
|
|
#if ODIN_INSPECTOR
|
|
try
|
|
{
|
|
#if ODIN_INSPECTOR_3
|
|
objectTree.BeginDraw(true);
|
|
#else
|
|
InspectorUtilities.BeginDrawPropertyTree(objectTree, true);
|
|
#endif
|
|
}
|
|
catch (ArgumentNullException)
|
|
{
|
|
#if ODIN_INSPECTOR_3
|
|
objectTree.EndDraw();
|
|
#else
|
|
InspectorUtilities.EndDrawPropertyTree(objectTree);
|
|
#endif
|
|
NodeEditor.DestroyEditor(this.target);
|
|
return;
|
|
}
|
|
|
|
GUIHelper.PushLabelWidth(84);
|
|
objectTree.Draw(true);
|
|
#if ODIN_INSPECTOR_3
|
|
objectTree.EndDraw();
|
|
#else
|
|
InspectorUtilities.EndDrawPropertyTree(objectTree);
|
|
#endif
|
|
GUIHelper.PopLabelWidth();
|
|
#else
|
|
|
|
// Iterate through serialized properties and draw them like the Inspector (But with ports)
|
|
SerializedProperty iterator = serializedObject.GetIterator();
|
|
bool enterChildren = true;
|
|
while (iterator.NextVisible(enterChildren))
|
|
{
|
|
enterChildren = false;
|
|
if (excludes.Contains(iterator.name))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
NodeEditorGUILayout.PropertyField(iterator);
|
|
}
|
|
#endif
|
|
|
|
// Iterate through dynamic ports and draw them in the order in which they are serialized
|
|
foreach (NodePort dynamicPort in target.DynamicPorts)
|
|
{
|
|
if (NodeEditorGUILayout.IsDynamicPortListPort(dynamicPort))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
NodeEditorGUILayout.PortField(dynamicPort);
|
|
}
|
|
|
|
serializedObject.ApplyModifiedProperties();
|
|
|
|
#if ODIN_INSPECTOR
|
|
// Call repaint so that the graph window elements respond properly to layout changes coming from Odin
|
|
if (GUIHelper.RepaintRequested)
|
|
{
|
|
GUIHelper.ClearRepaintRequest();
|
|
window.Repaint();
|
|
}
|
|
#endif
|
|
|
|
#if ODIN_INSPECTOR
|
|
inNodeEditor = false;
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called after rendering. Used for additional controls specific to a node.
|
|
/// </summary>
|
|
public virtual void OnControlsGUI() {}
|
|
|
|
public virtual int GetWidth()
|
|
{
|
|
Type type = target.GetType();
|
|
int width;
|
|
if (type.TryGetAttributeWidth(out width))
|
|
{
|
|
return width;
|
|
}
|
|
|
|
return 208;
|
|
}
|
|
|
|
/// <summary> Returns tint for target node </summary>
|
|
public virtual Color GetTint()
|
|
{
|
|
// Try get color from [NodeTint] attribute
|
|
Type type = target.GetType();
|
|
Color color;
|
|
if (type.TryGetAttributeTint(out color))
|
|
{
|
|
return color;
|
|
}
|
|
// Return default color (grey)
|
|
|
|
return NodeEditorPreferences.GetSettings().tintColor;
|
|
}
|
|
|
|
/// <summary> Returns header color for target node </summary>
|
|
public virtual Color GetHeaderColor()
|
|
{
|
|
// Try get color from [NodeColorHeader] attribute
|
|
Type type = target.GetType();
|
|
Color color;
|
|
if (type.TryGetAttributeHeader(out color))
|
|
{
|
|
return color;
|
|
}
|
|
// Return default color (grey)
|
|
|
|
return NodeEditorPreferences.GetSettings().bgHeaderColor;
|
|
}
|
|
|
|
/// <summary> Returns body color for target node </summary>
|
|
public virtual Color GetBodyColor()
|
|
{
|
|
// Try get color from [NodeColorBody] attribute
|
|
Type type = target.GetType();
|
|
Color color;
|
|
if (type.TryGetAttributeBody(out color))
|
|
{
|
|
return color;
|
|
}
|
|
// Return default color (grey)
|
|
|
|
return NodeEditorPreferences.GetSettings().bgBodyColor;
|
|
}
|
|
|
|
public virtual GUIStyle GetHeaderStyle()
|
|
{
|
|
return NodeEditorResources.styles.nodeHeader;
|
|
}
|
|
|
|
public virtual GUIStyle GetPortsStyle()
|
|
{
|
|
return NodeEditorResources.styles.nodePorts;
|
|
}
|
|
|
|
public virtual GUIStyle GetBodyStyle()
|
|
{
|
|
return NodeEditorResources.styles.nodeBody;
|
|
}
|
|
|
|
public virtual GUIStyle GetHeaderLabelStyle()
|
|
{
|
|
return NodeEditorResources.styles.nodeHeaderLabel;
|
|
}
|
|
|
|
public virtual GUIStyle GetBodyHighlightStyle()
|
|
{
|
|
return NodeEditorResources.styles.nodeHighlight;
|
|
}
|
|
|
|
/// <summary> Override to display custom node header tooltips </summary>
|
|
public virtual string GetHeaderTooltip()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
/// <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)
|
|
{
|
|
bool canRemove = true;
|
|
// Actions if only one node is selected
|
|
if (Selection.objects.Length == 1 && Selection.activeObject is Node)
|
|
{
|
|
Node node = Selection.activeObject as Node;
|
|
menu.AddItem(new GUIContent("Move To Top"), false, () => NodeEditorWindow.current.MoveNodeToTop(node));
|
|
menu.AddItem(new GUIContent("Rename"), false, NodeEditorWindow.current.RenameSelectedNode);
|
|
|
|
canRemove = NodeGraphEditor.GetEditor(node.graph, NodeEditorWindow.current).CanRemove(node);
|
|
}
|
|
|
|
// Add actions to any number of selected nodes
|
|
menu.AddItem(new GUIContent("Copy"), false, NodeEditorWindow.current.CopySelectedNodes);
|
|
menu.AddItem(new GUIContent("Duplicate"), false, NodeEditorWindow.current.DuplicateSelectedNodes);
|
|
|
|
if (canRemove)
|
|
{
|
|
menu.AddItem(new GUIContent("Remove"), false, NodeEditorWindow.current.RemoveSelectedNodes);
|
|
}
|
|
else
|
|
{
|
|
menu.AddItem(new GUIContent("Remove"), false, null);
|
|
}
|
|
|
|
// Custom sctions if only one node is selected
|
|
if (Selection.objects.Length == 1 && Selection.activeObject is Node)
|
|
{
|
|
Node node = Selection.activeObject as Node;
|
|
menu.AddCustomContextMenuItems(node);
|
|
}
|
|
}
|
|
|
|
/// <summary> Rename the node asset. This will trigger a reimport of the node. </summary>
|
|
public void Rename(string newName)
|
|
{
|
|
if (newName == null || newName.Trim() == "")
|
|
{
|
|
newName = NodeEditorUtilities.NodeDefaultName(target.GetType());
|
|
}
|
|
|
|
target.name = newName;
|
|
OnRename();
|
|
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target));
|
|
}
|
|
|
|
/// <summary> Called when entering into rename mode for this node. </summary>
|
|
public virtual void OnRenameActive() {}
|
|
|
|
/// <summary> Called after this node's name has changed. </summary>
|
|
public virtual void OnRename() {}
|
|
|
|
/// <summary> Called when exiting rename mode for this node. </summary>
|
|
public virtual void OnRenameDeactive() {}
|
|
|
|
[AttributeUsage(AttributeTargets.Class)]
|
|
public class CustomNodeEditorAttribute : Attribute,
|
|
INodeEditorAttrib
|
|
{
|
|
private readonly 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>
|
|
public CustomNodeEditorAttribute(Type inspectedType)
|
|
{
|
|
this.inspectedType = inspectedType;
|
|
}
|
|
|
|
public Type GetInspectedType()
|
|
{
|
|
return inspectedType;
|
|
}
|
|
}
|
|
}
|
|
} |