Added RelayNodeView;

Chnaged GraphView to multiple files for better organization;
This commit is contained in:
Misaki
2024-11-05 22:46:42 +09:00
parent c853994bf5
commit 02ae77f17a
25 changed files with 863 additions and 620 deletions

View File

@@ -1,441 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace Misaki.GraphView.Editor
{
public class GraphView : UnityEditor.Experimental.GraphView.GraphView
{
private readonly Dictionary<string, Node> _nodeViewsMap = new();
private readonly Dictionary<Edge, SlotConnection> _slotConnections = new();
private readonly GraphBlackboardView _blackboardView;
private readonly GraphInspectorView _graphInspectorView;
private readonly GraphViewConfig _graphViewConfig;
private GraphObject _graphObject => _graphViewConfig.graphObject;
public EditorWindow EditorWindow { get; }
public GraphViewConfig GraphViewConfig => _graphViewConfig;
public GraphView(EditorWindow editorWindow, GraphViewConfig graphViewConfig)
{
EditorWindow = editorWindow;
_graphViewConfig = graphViewConfig;
var gridBackground = new GridBackground { name = "gridBackground" };
Add(gridBackground);
gridBackground.SendToBack();
var minimapConfig = _graphViewConfig.miniMapConfig;
if (minimapConfig is { enable: true })
{
var minimap = new MiniMap()
{
anchored = true
};
minimap.SetPosition(minimapConfig.position);
Add(minimap);
}
_blackboardView = new GraphBlackboardView(_graphObject, this, _graphViewConfig.serializedObject, _graphViewConfig.exposedPropertyTypeManager);
_blackboardView.OnPropertySelected += ChangeInspectorView;
foreach (var property in _graphObject.ExposedProperties)
{
_blackboardView.AddProperty(property);
}
_graphInspectorView = new GraphInspectorView();
Add(_blackboardView);
Add(_graphInspectorView);
this.StretchToParentSize();
this.AddManipulator(new ContentDragger());
this.AddManipulator(new SelectionDragger());
this.AddManipulator(new RectangleSelector());
this.AddManipulator(new ClickSelector());
var zoomConfig = _graphViewConfig.zoomConfig;
var zoomer = new ContentZoomer();
if (zoomConfig !=null)
{
zoomer.minScale = zoomConfig.minScale;
zoomer.maxScale = zoomConfig.maxScale;
zoomer.scaleStep = zoomConfig.scaleStep;
}
this.AddManipulator(zoomer);
InitializeAssetElements();
graphViewChanged += OnGraphViewChanged;
RegisterCallback<DragPerformEvent>(OnDragPerform);
RegisterCallbackOnce<GeometryChangedEvent>(_ => _graphInspectorView?.DockToParent(layout, DockingPosition.Right, false));
}
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
base.BuildContextualMenu(evt);
var mousePosition = (evt.currentTarget as VisualElement).ChangeCoordinatesTo(contentViewContainer, evt.localMousePosition);
if (selection.Count == 0)
{
evt.menu.InsertAction(1, "Create Sticky Note", e =>
{
var stickyNote = new StickyNoteData
{
title = "Sticky Note",
contents = "Contents",
theme = StickyNoteTheme.Classic,
fontSize = StickyNoteFontSize.Medium,
position = new Rect(mousePosition, new Vector2(200, 200))
};
AddStickyNote(stickyNote);
}, DropdownMenuAction.AlwaysEnabled);
}
}
private void InitializeAssetElements()
{
var searchProvider = ScriptableObject.CreateInstance<NodeSearchProvider>();
searchProvider.SetOwner(this);
nodeCreationRequest = context =>
{
SearchWindow.Open(new SearchWindowContext(context.screenMousePosition), searchProvider);
};
foreach (var node in _graphObject.Nodes)
{
AddNodeView(node);
}
foreach (var noteData in _graphObject.StickyNotes)
{
AddStickyNoteView(noteData);
}
foreach (var connection in _graphObject.Connections)
{
AddConnectionView(connection);
}
}
private GraphViewChange OnGraphViewChanged(GraphViewChange graphViewChange)
{
if (graphViewChange.elementsToRemove != null)
{
var removedElements = graphViewChange.elementsToRemove;
Undo.RecordObject(_graphObject, "Remove elements");
for (var i = removedElements.Count - 1; i >= 0; i--)
{
if (removedElements[i] is Node { userData: ExecutableNode node })
{
RemoveNode(node);
}
if (removedElements[i] is StickyNote {userData : StickyNoteData stickyNote})
{
RemoveStickyNote(stickyNote);
}
if (removedElements[i] is Edge edge)
{
if (_slotConnections.Remove(edge, out var connection))
{
var inputNode = _graphObject.GetNode(connection.InputSlotData.nodeID);
var outputNode = _graphObject.GetNode(connection.OutputSlotData.nodeID);
if (inputNode is ISlotContainer inputSlotContainer && outputNode is ISlotContainer outputSlotContainer)
{
var inputSlot = inputSlotContainer.GetSlot(connection.InputSlotData.slotIndex, connection.InputSlotData.direction);
var outputSlot = outputSlotContainer.GetSlot(connection.OutputSlotData.slotIndex, connection.OutputSlotData.direction);
inputSlot.Unlink(outputSlot);
}
RemoveConnection(connection);
}
}
}
}
// if (graphViewChange.movedElements != null)
// {
// var movedElements = graphViewChange.movedElements;
// Undo.RecordObject(_graphObject, $"Move {movedElements.FirstOrDefault()?.GetType().Name}");
//
// foreach (var element in graphViewChange.movedElements)
// {
// element.SetPosition(element.GetPosition());
// }
// }
if (graphViewChange.edgesToCreate != null)
{
var createdEdges = graphViewChange.edgesToCreate;
Undo.RecordObject(_graphObject, $"Connect {createdEdges.FirstOrDefault()?.GetType().Name}");
foreach (var edge in createdEdges)
if (edge.input.userData is Slot inputSlot && edge.output.userData is Slot outputSlot)
{
var connection = new SlotConnection(inputSlot.slotData, outputSlot.slotData);
_slotConnections.Add(edge, connection);
outputSlot.Link(inputSlot);
AddConnection(connection);
}
}
_graphObject.SetGraphTransform(viewTransform);
_graphViewConfig.serializedObject.Update();
EditorUtility.SetDirty(_graphObject);
return graphViewChange;
}
public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
{
var compatiblePorts = new List<Port>();
foreach (var port in ports)
{
if (startPort == port || startPort.node == port.node || startPort.direction == port.direction)
{
continue;
}
if (startPort.portType != port.portType &&
_graphObject.ValueConverterManager != null &&
!_graphObject.ValueConverterManager.CanConvert(startPort.portType, port.portType))
{
continue;
}
compatiblePorts.Add(port);
}
return compatiblePorts;
}
private void OnDragPerform(DragPerformEvent evt)
{
var data = DragAndDrop.GetGenericData("DragSelection");
if (data is List<ISelectable> selectables)
{
var propertyViews = selectables.OfType<BlackboardPropertyView>().ToArray();
if (propertyViews.Length <= 0)
{
return;
}
var position = (evt.currentTarget as VisualElement).ChangeCoordinatesTo(contentViewContainer, evt.localMousePosition);
foreach (var view in propertyViews)
{
if (view.userData is not ExposedProperty property)
{
continue;
}
var baseNode = new PropertyInput(property)
{
position = new Rect(position, Vector2.zero)
};
AddNode(baseNode);
}
}
}
public void AddNode(ExecutableNode executableNode)
{
Undo.RecordObject(_graphObject, $"Add {executableNode.GetType().Name}");
_graphObject.AddNode(executableNode);
AddNodeView(executableNode);
EditorUtility.SetDirty(_graphObject);
}
private void AddNodeView(DataNode node)
{
var nodeView = CreateNodeView(node);
if (nodeView == null)
{
return;
}
nodeView.SetPosition(node.position);
if (nodeView is IInspectable inspectable)
{
inspectable.OnItemSelected += ChangeInspectorView;
}
AddElement(nodeView);
_nodeViewsMap.Add(node.Id, nodeView);
}
protected virtual Node CreateNodeView(DataNode node)
{
var types = TypeCache.GetTypesWithAttribute<CustomInspectorAttribute>();
var type = types.FirstOrDefault(t =>
t.GetCustomAttribute<CustomInspectorAttribute>().InspectorType == node.GetType());
if (node is PropertyInput propertyInputNode)
{
return PropertyInputNodeView.Create(propertyInputNode, _graphViewConfig.portColorManager);
}
else if (node is ExecutableNode executableNode)
{
type ??= typeof(ExecutableNodeView);
return Activator.CreateInstance(type, executableNode, _graphViewConfig.serializedObject, _graphViewConfig.portColorManager, _graphObject.Logger) as ExecutableNodeView;
}
return null;
}
private void RemoveNode(ExecutableNode executableNode)
{
Undo.RecordObject(_graphObject, $"Remove {executableNode.GetType().Name}");
_graphObject.RemoveNode(executableNode);
RemoveNodeView(executableNode);
EditorUtility.SetDirty(_graphObject);
}
private void RemoveNodeView(ExecutableNode executableNode)
{
if (_nodeViewsMap.Remove(executableNode.Id, out var nodeView))
{
RemoveElement(nodeView);
if (nodeView is IInspectable inspectable)
{
inspectable.OnItemSelected -= ChangeInspectorView;
}
}
}
public void AddStickyNote(StickyNoteData stickyNote)
{
Undo.RecordObject(_graphObject, $"Add {stickyNote.title}");
_graphObject.AddStickyNote(stickyNote);
AddStickyNoteView(stickyNote);
}
private void AddStickyNoteView(StickyNoteData stickyNote)
{
var stickyNoteView = new StickyNoteView(stickyNote);
stickyNoteView.SetPosition(stickyNote.position);
AddElement(stickyNoteView);
}
public void RemoveStickyNote(StickyNoteData stickyNote)
{
Undo.RecordObject(_graphObject, $"Remove {stickyNote.title}");
_graphObject.RemoveStickyNote(stickyNote);
RemoveStickyNoteView(stickyNote);
}
private void RemoveStickyNoteView(StickyNoteData stickyNote)
{
// var stickyNoteView = GetStickyNoteView(stickyNote);
// if (stickyNoteView != null)
// {
// RemoveElement(stickyNoteView);
// }
}
public void AddConnection(SlotConnection connection)
{
Undo.RecordObject(_graphObject, $"Add {connection.GetType().Name}");
_graphObject.AddConnection(connection);
EditorUtility.SetDirty(_graphObject);
}
private void RemoveConnection(SlotConnection connection)
{
Undo.RecordObject(_graphObject, $"Remove {connection.GetType().Name}");
_graphObject.RemoveConnection(connection);
EditorUtility.SetDirty(_graphObject);
}
private void AddConnectionView(SlotConnection connection)
{
var inputSlotData = connection.InputSlotData;
var outputSlotData = connection.OutputSlotData;
if (!_nodeViewsMap.TryGetValue(inputSlotData.nodeID, out var inputNodeView) ||
!_nodeViewsMap.TryGetValue(outputSlotData.nodeID, out var outputNodeView))
{
return;
}
if (inputNodeView is not IPortContainer inputPortContainer || outputNodeView is not IPortContainer outputPortContainer)
{
return;
}
var inputPort = inputPortContainer.InputPorts[inputSlotData.slotIndex];
var outputPort = outputPortContainer.OutputPorts[outputSlotData.slotIndex];
var edge = inputPort.ConnectTo(outputPort);
AddElement(edge);
_slotConnections.Add(edge, connection);
}
public void ToggleBlackboardViewVisibility()
{
if (_blackboardView == null)
{
return;
}
_blackboardView.style.visibility = _blackboardView.style.visibility == Visibility.Hidden
? Visibility.Visible
: Visibility.Hidden;
}
private void ChangeInspectorView(IInspectable inspectable)
{
if (_graphInspectorView == null)
{
return;
}
_graphInspectorView.OnNodeSelectionChanged(inspectable);
}
public void ToggleInspectorViewVisibility()
{
if (_graphInspectorView == null)
{
return;
}
_graphInspectorView.style.visibility = _graphInspectorView.style.visibility == Visibility.Hidden
? Visibility.Visible
: Visibility.Hidden;
}
}
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 66c6b56270850cc458f01ab2bbd9429e

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e691d14381aaee54fb5214d0fcc9cfd4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,197 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace Misaki.GraphView.Editor
{
public partial class GraphView : UnityEditor.Experimental.GraphView.GraphView
{
private readonly Dictionary<string, Node> _nodeViewsMap = new();
private readonly Dictionary<Edge, SlotConnection> _slotConnections = new();
private readonly GraphBlackboardView _blackboardView;
private readonly GraphInspectorView _graphInspectorView;
private readonly GraphViewConfig _graphViewConfig;
private GraphObject _graphObject => _graphViewConfig.graphObject;
public EditorWindow EditorWindow
{
get;
}
public GraphViewConfig GraphViewConfig => _graphViewConfig;
public GraphView(EditorWindow editorWindow, GraphViewConfig graphViewConfig)
{
EditorWindow = editorWindow;
_graphViewConfig = graphViewConfig;
var gridBackground = new GridBackground { name = "gridBackground" };
Add(gridBackground);
gridBackground.SendToBack();
var minimapConfig = _graphViewConfig.miniMapConfig;
if (minimapConfig is { enable: true })
{
var minimap = new MiniMap()
{
anchored = true
};
minimap.SetPosition(minimapConfig.position);
Add(minimap);
}
_blackboardView = new GraphBlackboardView(_graphObject, this, _graphViewConfig.serializedObject, _graphViewConfig.exposedPropertyTypeManager);
_blackboardView.OnPropertySelected += ChangeInspectorView;
foreach (var property in _graphObject.ExposedProperties)
{
_blackboardView.AddProperty(property);
}
_graphInspectorView = new GraphInspectorView();
Add(_blackboardView);
Add(_graphInspectorView);
this.StretchToParentSize();
this.AddManipulator(new ContentDragger());
this.AddManipulator(new SelectionDragger());
this.AddManipulator(new RectangleSelector());
this.AddManipulator(new ClickSelector());
var zoomConfig = _graphViewConfig.zoomConfig;
var zoomer = new ContentZoomer();
if (zoomConfig != null)
{
zoomer.minScale = zoomConfig.minScale;
zoomer.maxScale = zoomConfig.maxScale;
zoomer.scaleStep = zoomConfig.scaleStep;
}
this.AddManipulator(zoomer);
InitializeAssetElements();
graphViewChanged += OnGraphViewChanged;
RegisterCallback<DragPerformEvent>(OnDragPerform);
RegisterCallbackOnce<GeometryChangedEvent>(_ => _graphInspectorView?.DockToParent(layout, DockingPosition.Right, false));
}
private void InitializeAssetElements()
{
var searchProvider = ScriptableObject.CreateInstance<NodeSearchProvider>();
searchProvider.SetOwner(this);
nodeCreationRequest = context =>
{
SearchWindow.Open(new SearchWindowContext(context.screenMousePosition), searchProvider);
};
foreach (var node in _graphObject.Nodes)
{
AddNodeView(node);
}
foreach (var noteData in _graphObject.StickyNotes)
{
AddStickyNoteView(noteData);
}
foreach (var connection in _graphObject.Connections)
{
AddConnectionView(connection);
}
}
public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
{
var compatiblePorts = new List<Port>();
foreach (var port in ports)
{
if (startPort == port || startPort.node == port.node || startPort.direction == port.direction)
{
continue;
}
if (startPort.portType != port.portType &&
_graphObject.ValueConverterManager != null &&
!_graphObject.ValueConverterManager.CanConvert(startPort.portType, port.portType))
{
continue;
}
compatiblePorts.Add(port);
}
return compatiblePorts;
}
private void OnDragPerform(DragPerformEvent evt)
{
var data = DragAndDrop.GetGenericData("DragSelection");
if (data is List<ISelectable> selectables)
{
var propertyViews = selectables.OfType<BlackboardPropertyView>().ToArray();
if (propertyViews.Length <= 0)
{
return;
}
var position = (evt.currentTarget as VisualElement).ChangeCoordinatesTo(contentViewContainer, evt.localMousePosition);
foreach (var view in propertyViews)
{
if (view.userData is not ExposedProperty property)
{
continue;
}
var baseNode = new PropertyInput(property)
{
position = new Rect(position, Vector2.zero)
};
AddNode(baseNode);
}
}
}
public void ToggleBlackboardViewVisibility()
{
if (_blackboardView == null)
{
return;
}
_blackboardView.style.visibility = _blackboardView.style.visibility == Visibility.Hidden
? Visibility.Visible
: Visibility.Hidden;
}
private void ChangeInspectorView(IInspectable inspectable)
{
if (_graphInspectorView == null)
{
return;
}
_graphInspectorView.OnNodeSelectionChanged(inspectable);
}
public void ToggleInspectorViewVisibility()
{
if (_graphInspectorView == null)
{
return;
}
_graphInspectorView.style.visibility = _graphInspectorView.style.visibility == Visibility.Hidden
? Visibility.Visible
: Visibility.Hidden;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 85dea80825e410d4093cc4d10f33931b

View File

@@ -0,0 +1,45 @@
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace Misaki.GraphView.Editor
{
public partial class GraphView
{
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
base.BuildContextualMenu(evt);
var mousePosition = (evt.currentTarget as VisualElement).ChangeCoordinatesTo(contentViewContainer, evt.localMousePosition);
if (evt.target is GraphView)
{
evt.menu.InsertAction(1, "Create Sticky Note", e =>
{
var stickyNote = new StickyNoteData
{
title = "Sticky Note",
contents = "Contents",
theme = StickyNoteTheme.Classic,
fontSize = StickyNoteFontSize.Medium,
position = new Rect(mousePosition, new Vector2(200, 200))
};
AddStickyNote(stickyNote);
}, DropdownMenuAction.AlwaysEnabled);
}
if (evt.target is Edge)
{
evt.menu.AppendAction("Create Relay Node", e =>
{
var relayNode = new RelayNode
{
position = new Rect(mousePosition, Vector2.zero)
};
AddRelayNode(relayNode);
}, DropdownMenuAction.AlwaysEnabled);
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d8daa8d0ebadc4a40872f6613533e4bd

View File

@@ -0,0 +1,84 @@
using System.Linq;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
namespace Misaki.GraphView.Editor
{
public partial class GraphView
{
private GraphViewChange OnGraphViewChanged(GraphViewChange graphViewChange)
{
if (graphViewChange.elementsToRemove != null)
{
var removedElements = graphViewChange.elementsToRemove;
Undo.RecordObject(_graphObject, "Remove elements");
for (var i = removedElements.Count - 1; i >= 0; i--)
{
if (removedElements[i] is Node { userData: DataNode node })
{
RemoveNode(node);
}
if (removedElements[i] is StickyNote { userData: StickyNoteData stickyNote })
{
RemoveStickyNote(stickyNote);
}
if (removedElements[i] is Edge edge)
{
if (_slotConnections.Remove(edge, out var connection))
{
var inputNode = _graphObject.GetNode(connection.InputSlotData.nodeID);
var outputNode = _graphObject.GetNode(connection.OutputSlotData.nodeID);
if (inputNode is ISlotContainer inputSlotContainer && outputNode is ISlotContainer outputSlotContainer)
{
var inputSlot = inputSlotContainer.GetSlot(connection.InputSlotData.slotIndex, connection.InputSlotData.direction);
var outputSlot = outputSlotContainer.GetSlot(connection.OutputSlotData.slotIndex, connection.OutputSlotData.direction);
inputSlot.Unlink(outputSlot);
}
RemoveConnection(connection);
}
}
}
}
// if (graphViewChange.movedElements != null)
// {
// var movedElements = graphViewChange.movedElements;
// Undo.RecordObject(_graphObject, $"Move {movedElements.FirstOrDefault()?.GetType().Name}");
//
// foreach (var element in graphViewChange.movedElements)
// {
// element.SetPosition(element.GetPosition());
// }
// }
if (graphViewChange.edgesToCreate != null)
{
var createdEdges = graphViewChange.edgesToCreate;
Undo.RecordObject(_graphObject, $"Connect {createdEdges.FirstOrDefault()?.GetType().Name}");
foreach (var edge in createdEdges)
if (edge.input.userData is Slot inputSlot && edge.output.userData is Slot outputSlot)
{
var connection = new SlotConnection(inputSlot.slotData, outputSlot.slotData);
_slotConnections.Add(edge, connection);
outputSlot.Link(inputSlot);
AddConnection(connection);
}
}
_graphObject.SetGraphTransform(viewTransform);
_graphViewConfig.serializedObject.Update();
EditorUtility.SetDirty(_graphObject);
return graphViewChange;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c31e6279987ed0f449f1b23a385eb4be

View File

@@ -0,0 +1,176 @@
using System;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
namespace Misaki.GraphView.Editor
{
public partial class GraphView
{
public void AddNode(ExecutableNode executableNode)
{
Undo.RecordObject(_graphObject, $"Add {executableNode.GetType().Name}");
_graphObject.AddNode(executableNode);
AddNodeView(executableNode);
EditorUtility.SetDirty(_graphObject);
}
private void AddNodeView(DataNode node)
{
var nodeView = CreateNodeView(node);
if (nodeView == null)
{
return;
}
nodeView.SetPosition(node.position);
if (nodeView is IInspectable inspectable)
{
inspectable.OnItemSelected += ChangeInspectorView;
}
AddElement(nodeView);
_nodeViewsMap.Add(node.Id, nodeView);
}
protected virtual Node CreateNodeView(DataNode node)
{
var types = TypeCache.GetTypesWithAttribute<CustomInspectorAttribute>();
var type = types.FirstOrDefault(t =>
t.GetCustomAttribute<CustomInspectorAttribute>().InspectorType == node.GetType());
if (node is PropertyInput propertyInputNode)
{
return PropertyInputNodeView.Create(propertyInputNode, _graphViewConfig.portColorManager);
}
else if (node is ExecutableNode executableNode)
{
type ??= typeof(ExecutableNodeView);
return Activator.CreateInstance(type, executableNode, _graphViewConfig.serializedObject, _graphViewConfig.portColorManager, _graphObject.Logger) as ExecutableNodeView;
}
return null;
}
private void RemoveNode(DataNode dataNode)
{
Undo.RecordObject(_graphObject, $"Remove {dataNode.GetType().Name}");
_graphObject.RemoveNode(dataNode);
RemoveNodeView(dataNode);
EditorUtility.SetDirty(_graphObject);
}
private void RemoveNodeView(DataNode dataNode)
{
if (_nodeViewsMap.Remove(dataNode.Id, out var nodeView))
{
RemoveElement(nodeView);
if (nodeView is IInspectable inspectable)
{
inspectable.OnItemSelected -= ChangeInspectorView;
}
}
}
public void AddStickyNote(StickyNoteData stickyNote)
{
Undo.RecordObject(_graphObject, $"Add {stickyNote.title}");
_graphObject.AddStickyNote(stickyNote);
AddStickyNoteView(stickyNote);
EditorUtility.SetDirty(_graphObject);
}
private void AddStickyNoteView(StickyNoteData stickyNote)
{
var stickyNoteView = new StickyNoteView(stickyNote);
stickyNoteView.SetPosition(stickyNote.position);
AddElement(stickyNoteView);
}
public void RemoveStickyNote(StickyNoteData stickyNote)
{
Undo.RecordObject(_graphObject, $"Remove {stickyNote.title}");
_graphObject.RemoveStickyNote(stickyNote);
RemoveStickyNoteView(stickyNote);
}
private void RemoveStickyNoteView(StickyNoteData stickyNote)
{
// var stickyNoteView = GetStickyNoteView(stickyNote);
// if (stickyNoteView != null)
// {
// RemoveElement(stickyNoteView);
// }
}
public void AddConnection(SlotConnection connection)
{
Undo.RecordObject(_graphObject, $"Add {connection.GetType().Name}");
_graphObject.AddConnection(connection);
EditorUtility.SetDirty(_graphObject);
}
private void RemoveConnection(SlotConnection connection)
{
Undo.RecordObject(_graphObject, $"Remove {connection.GetType().Name}");
_graphObject.RemoveConnection(connection);
EditorUtility.SetDirty(_graphObject);
}
private void AddConnectionView(SlotConnection connection)
{
var inputSlotData = connection.InputSlotData;
var outputSlotData = connection.OutputSlotData;
if (!_nodeViewsMap.TryGetValue(inputSlotData.nodeID, out var inputNodeView) ||
!_nodeViewsMap.TryGetValue(outputSlotData.nodeID, out var outputNodeView))
{
return;
}
if (inputNodeView is not IPortContainer inputPortContainer || outputNodeView is not IPortContainer outputPortContainer)
{
return;
}
var inputPort = inputPortContainer.GetPort(inputSlotData.slotIndex, Direction.Input);
var outputPort = outputPortContainer.GetPort(outputSlotData.slotIndex, Direction.Output);
var edge = inputPort.ConnectTo(outputPort);
AddElement(edge);
_slotConnections.Add(edge, connection);
}
public void AddRelayNode(RelayNode relayNode)
{
Undo.RecordObject(_graphObject, $"Add {relayNode.GetType().Name}");
_graphObject.AddNode(relayNode);
AddRelayNodeView(relayNode);
EditorUtility.SetDirty(_graphObject);
}
private void AddRelayNodeView(RelayNode relayNode)
{
var relayNodeView = new RelayNodeView(relayNode, _graphViewConfig.portColorManager);
relayNodeView.SetPosition(relayNode.position);
AddElement(relayNodeView);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d01a10830ebed08498c09668ee5d0c74

View File

@@ -15,19 +15,19 @@ namespace Misaki.GraphView.Editor
private readonly ExecutableNode _dataNode;
private readonly Type _nodeType;
private readonly NodeInfoAttribute _nodeInfo;
private readonly List<Port> _inputPorts = new ();
private readonly List<Port> _outputPorts = new ();
private readonly List<Port> _inputPorts = new();
private readonly List<Port> _outputPorts = new();
private readonly IPortColorManager _portColorManager;
private readonly SerializedObject _serializedObject;
private readonly VisualElement _logContainer = new();
public List<Port> InputPorts => _inputPorts;
public List<Port> OutputPorts => _outputPorts;
public Action<IInspectable> OnItemSelected { get; set; }
public Action<IInspectable> OnItemSelected
{
get; set;
}
public string InspectorName => _nodeInfo.Name ?? _nodeType.Name;
@@ -37,19 +37,19 @@ namespace Misaki.GraphView.Editor
{
return;
}
_dataNode = dataNode;
_portColorManager = portColorManager;
_serializedObject = serializedObject;
userData = dataNode;
_nodeType = dataNode.GetType();
_nodeInfo = _nodeType.GetCustomAttribute<NodeInfoAttribute>();
name = _nodeInfo.Name ?? _nodeType.Name;
title = _nodeInfo.Name ?? _nodeType.Name;
// Add the category as a class to the node so that we can style the node based on the category
var depths = _nodeInfo.Category.Split('/').ToList();
depths.Add(_nodeInfo.Name);
@@ -57,13 +57,13 @@ namespace Misaki.GraphView.Editor
{
AddToClassList(depth.ToLower().Replace(" ", "-"));
}
var inputs = _nodeType.GetProperty(nameof(ExecutableNode.Inputs));
if (inputs != null)
{
var inputSlots = (IList<Slot>)inputs.GetValue(_dataNode);
if (inputSlots == null || inputSlots.Count == 0)
{
inputContainer.style.display = DisplayStyle.None;
@@ -94,7 +94,7 @@ namespace Misaki.GraphView.Editor
}
}
}
_logContainer.style.position = Position.Absolute;
_logContainer.style.top = 8;
Add(_logContainer);
@@ -107,15 +107,15 @@ namespace Misaki.GraphView.Editor
}
}
private void CreateLogElement(ExecutableNode node, string message, LogType type)
private void CreateLogElement(DataNode node, string message, LogType type)
{
if (node.Id != _dataNode.Id)
{
return;
}
_logContainer.style.left = layout.width;
var logIcon = new Image()
{
image = type switch
@@ -129,12 +129,12 @@ namespace Misaki.GraphView.Editor
{
width = 24,
height = 24,
borderBottomLeftRadius = 4,
borderTopRightRadius = 4,
borderTopLeftRadius = 4,
borderBottomRightRadius = 4,
flexDirection = FlexDirection.Row,
alignItems = Align.Center,
paddingBottom = 1,
@@ -150,7 +150,7 @@ namespace Misaki.GraphView.Editor
}
}
};
_logContainer.Add(logIcon);
}
@@ -205,20 +205,30 @@ namespace Misaki.GraphView.Editor
base.OnSelected();
OnItemSelected?.Invoke(this);
}
public override void OnUnselected()
{
base.OnUnselected();
OnItemSelected?.Invoke(null);
}
public Port GetPort(int index, Direction direction)
{
return direction switch
{
Direction.Input => _inputPorts[index],
Direction.Output => _outputPorts[index],
_ => null
};
}
/// <summary>
/// Displays the inspector for the node.
/// </summary>
public virtual VisualElement CreateInspector()
{
var root = new VisualElement();
if (_serializedObject.targetObject is not GraphObject graphObject)
{
return root;
@@ -239,7 +249,7 @@ namespace Misaki.GraphView.Editor
foreach (var field in fields)
{
var serializedProperty = _serializedObject.FindProperty("_nodes")?.GetArrayElementAtIndex(i)?.FindPropertyRelative(field.Name);
if (serializedProperty == null)
{
continue;
@@ -249,7 +259,7 @@ namespace Misaki.GraphView.Editor
{
continue;
}
var propertyName = field.GetCustomAttribute<InspectorInputAttribute>().Name ?? ObjectNames.NicifyVariableName(field.Name);
if (field.GetCustomAttribute<NodeInputAttribute>() is not null)
@@ -263,16 +273,16 @@ namespace Misaki.GraphView.Editor
}
}
}
var inputField = new PropertyField(serializedProperty, propertyName);
inputField.Bind(_serializedObject);
root.Add(inputField);
}
return root;
}
protected VisualElement CreateFieldForConnectedSlot(Slot slot, string propertyName)
{
var root = new VisualElement()
@@ -288,7 +298,7 @@ namespace Misaki.GraphView.Editor
marginRight = 3
}
};
var label = new Label(propertyName)
{
style =
@@ -297,7 +307,7 @@ namespace Misaki.GraphView.Editor
}
};
label.AddToClassList("unity-base-field__label");
var value = new Label($"Connected to {ObjectNames.NicifyVariableName(slot.LinkedSlotData[0].slotName)}");
value.AddToClassList("unity-base-field__input");

View File

@@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEditor.Experimental.GraphView;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
@@ -9,54 +6,49 @@ namespace Misaki.GraphView.Editor
{
public class PropertyInputNodeView : TokenNode, IPortContainer
{
private readonly List<Port> _outputPorts = new List<Port>();
private readonly Port _outputPort;
private readonly PropertyInput _data;
//private readonly ExposedPropertyEditor _editor;
public PropertyInput Data => _data;
public List<Port> InputPorts => null;
public List<Port> OutputPorts => _outputPorts;
public PropertyInputNodeView(PropertyInput data, Port output) : base(null, output)
{
_data = data;
//_editor = editor;
_outputPort = output;
name = data.Property.propertyName;
title = data.Property.propertyName;
userData = data;
this.Q<VisualElement>("top").style.minHeight = 24;
_outputPorts.Add(output);
}
public static PropertyInputNodeView Create(PropertyInput data, IPortColorManager portColorManager)
{
if (data == null)
{
return null;
}
var outputSlot = data.GetSlot(0, SlotDirection.Output);
var outputPort = CreateOutputPort(data.Property, outputSlot, portColorManager);
var nodeView = new PropertyInputNodeView(data, outputPort);
return nodeView;
}
private static Port CreateOutputPort(ExposedProperty property, Slot slot, IPortColorManager portColorManager)
{
if (property == null)
{
return null;
}
var portType = property.GetValueType();
var port = Port.Create<Edge>(Orientation.Horizontal, Direction.Output, Port.Capacity.Single, portType);
port.portName = string.Empty;
if (portColorManager != null && portColorManager.TryGetColor(portType, out var portColor))
{
@@ -64,7 +56,7 @@ namespace Misaki.GraphView.Editor
}
port.portType = portType;
port.userData = slot;
return port;
}
@@ -75,5 +67,10 @@ namespace Misaki.GraphView.Editor
base.SetPosition(newPos);
_data.position = newPos;
}
public Port GetPort(int index, Direction direction)
{
return _outputPort;
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using UnityEditor.Experimental.GraphView;
namespace Misaki.GraphView.Editor
{
public class RelayNodeView : Node, IPortContainer
{
private RelayNode _dataNode;
private IPortColorManager _portColorManager;
private readonly Port _inputPort;
private readonly Port _outputPort;
public RelayNodeView(RelayNode dataNode, IPortColorManager portColorManager)
{
_dataNode = dataNode;
_portColorManager = portColorManager;
_inputPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Input, Port.Capacity.Single, typeof(object));
_outputPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Output, Port.Capacity.Multi, typeof(object));
_inputPort.portName = string.Empty;
_outputPort.portName = string.Empty;
SetPortsTypeAndColor(typeof(object));
inputContainer.Add(_inputPort);
outputContainer.Add(_outputPort);
}
private void SetPortsTypeAndColor(Type portType)
{
_inputPort.portType = portType;
_outputPort.portType = portType;
if (_portColorManager != null)
{
if (_portColorManager.TryGetColor(portType, out var portColor))
{
_inputPort.portColor = portColor;
_outputPort.portColor = portColor;
}
}
}
public Port GetPort(int index, Direction direction)
{
return direction == Direction.Input ? _inputPort : _outputPort;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ba1646416a4d47148947945befe2b938