summaryrefslogtreecommitdiffstats
path: root/Scripts/Fold/Editor/FoldGraphView.cs
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2026-01-12 19:31:54 -0800
committeryum <yum.food.vr@gmail.com>2026-01-12 19:31:54 -0800
commit6d86c9663bab3ec1ef95ba455dfa7281415b7f44 (patch)
treecda255c2dfd0ef2c96334fb7ecf2182d4950086e /Scripts/Fold/Editor/FoldGraphView.cs
parentcbc299f489d6bdc38cce30d74040c54197efe125 (diff)
Fold: move from visual programming to fluent builder
Diffstat (limited to 'Scripts/Fold/Editor/FoldGraphView.cs')
-rw-r--r--Scripts/Fold/Editor/FoldGraphView.cs623
1 files changed, 0 insertions, 623 deletions
diff --git a/Scripts/Fold/Editor/FoldGraphView.cs b/Scripts/Fold/Editor/FoldGraphView.cs
deleted file mode 100644
index e01bf4f..0000000
--- a/Scripts/Fold/Editor/FoldGraphView.cs
+++ /dev/null
@@ -1,623 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using UnityEditor;
-using UnityEditor.Experimental.GraphView;
-using UnityEditor.UIElements;
-using UnityEngine;
-using UnityEngine.UIElements;
-using SearchWindow = UnityEditor.Experimental.GraphView.SearchWindow;
-
-public interface IFoldNode
-{
- FoldNodeSerialized Serialize();
- IFoldNode GetPreviousFold();
-}
-
-public abstract class FoldNodeView : Node
-{
- public FoldNodeData Data { get; private set; }
- protected FoldGraphView graphView;
- readonly Dictionary<string, Port> ports = new();
-
- public virtual void Initialize(FoldGraphView view, FoldNodeData data)
- {
- graphView = view;
- Data = data;
- title = data.Title;
- viewDataKey = data.guid;
- SetPosition(new Rect(data.position, Vector2.zero));
-
- RegisterCallback<MouseDownEvent>(evt =>
- {
- if (!evt.shiftKey) return;
- if (!graphView.selection.Contains(this))
- graphView.AddToSelection(this);
- evt.StopImmediatePropagation();
- evt.PreventDefault();
- }, TrickleDown.TrickleDown);
- }
-
- public override void SetPosition(Rect newPos)
- {
- base.SetPosition(newPos);
- if (Data != null)
- {
- graphView.RecordUndo("Move Node");
- Data.position = newPos.position;
- graphView.MarkDirty();
- }
- }
-
- protected Port AddPort(Direction direction, Port.Capacity capacity, string name, Type type)
- {
- var port = InstantiatePort(Orientation.Horizontal, direction, capacity, type);
- port.portName = name;
- ports[name] = port;
- graphView.BindEdgeConnector(port);
- (direction == Direction.Input ? inputContainer : outputContainer).Add(port);
- return port;
- }
-
- public Port GetPort(string name) => ports.TryGetValue(name, out var p) ? p : null;
-}
-
-public class ValueNodeView : FoldNodeView
-{
- object GetValue() => Data switch
- {
- FloatValueNodeData f => f.value,
- VectorValueNodeData v => v.value,
- GameObjectNodeData g => g.output,
- _ => null
- };
-
- public T GetTypedValue<T>() => GetValue() is T v ? v : default;
-
- public override void Initialize(FoldGraphView view, FoldNodeData data)
- {
- base.Initialize(view, data);
- var portType = data switch
- {
- FloatValueNodeData => typeof(float),
- VectorValueNodeData => typeof(Vector4),
- GameObjectNodeData => typeof(GameObject),
- _ => typeof(object)
- };
- AddPort(Direction.Output, Port.Capacity.Multi, "Out", portType);
-
- VisualElement field = data switch
- {
- FloatValueNodeData f => CreateFloatField(f),
- VectorValueNodeData v => CreateVectorField(v),
- GameObjectNodeData g => CreateObjectField(g),
- _ => null
- };
- if (field != null) extensionContainer.Add(field);
- RefreshExpandedState();
- }
-
- FloatField CreateFloatField(FloatValueNodeData d)
- {
- var f = new FloatField("Value") { value = d.value };
- f.RegisterValueChangedCallback(e => { graphView.RecordUndo("Edit Float"); d.value = e.newValue; graphView.MarkDirty(); });
- return f;
- }
-
- Vector4Field CreateVectorField(VectorValueNodeData d)
- {
- var f = new Vector4Field("Value") { value = d.value };
- f.RegisterValueChangedCallback(e => { graphView.RecordUndo("Edit Vector"); d.value = e.newValue; graphView.MarkDirty(); });
- return f;
- }
-
- ObjectField CreateObjectField(GameObjectNodeData d)
- {
- var f = new ObjectField("Object") { allowSceneObjects = true, objectType = typeof(GameObject), value = d.output };
- f.RegisterValueChangedCallback(e => { graphView.RecordUndo("Edit GameObject"); d.output = e.newValue as GameObject; graphView.MarkDirty(); });
- return f;
- }
-}
-
-public class OperationNodeView : FoldNodeView, IFoldNode
-{
- Port foldInputPort;
-
- public override void Initialize(FoldGraphView view, FoldNodeData data)
- {
- base.Initialize(view, data);
- foldInputPort = AddPort(Direction.Input, Port.Capacity.Single, "Input", typeof(IFoldNode));
- AddPort(Direction.Output, Port.Capacity.Single, "Out", typeof(IFoldNode));
-
- foreach (var (name, type) in ((FoldOperationData)data).GetInputPorts())
- AddPort(Direction.Input, Port.Capacity.Single, name, type);
- }
-
- public IFoldNode GetPreviousFold() => foldInputPort.connections.FirstOrDefault()?.output?.node as IFoldNode;
- public FoldNodeSerialized Serialize() => ((FoldOperationData)Data).Serialize(graphView);
-}
-
-public class KeyframeNodeView : FoldNodeView
-{
- Port gameObjectPort, foldPort;
-
- public override void Initialize(FoldGraphView view, FoldNodeData data)
- {
- base.Initialize(view, data);
- gameObjectPort = AddPort(Direction.Input, Port.Capacity.Single, "GameObject", typeof(GameObject));
- foldPort = AddPort(Direction.Input, Port.Capacity.Single, "Fold Data", typeof(IFoldNode));
- extensionContainer.Add(new Button(OnGenerateClick) { text = "Generate Keyframe" });
- RefreshExpandedState();
- }
-
- void OnGenerateClick()
- {
- var goEdge = gameObjectPort.connections.FirstOrDefault();
- var go = (goEdge?.output?.node as ValueNodeView)?.GetTypedValue<GameObject>();
- if (go == null) { graphView.ShowNotification("GameObject input missing or empty."); return; }
-
- var renderer = go.GetComponent<MeshRenderer>();
- if (renderer == null) { graphView.ShowNotification("GameObject must have a MeshRenderer component."); return; }
-
- var foldNode = foldPort.connections.FirstOrDefault()?.output?.node as IFoldNode;
- if (foldNode == null) { graphView.ShowNotification("Fold input not connected."); return; }
-
- var stack = new Stack<IFoldNode>();
- for (var cur = foldNode; cur != null; cur = cur.GetPreviousFold())
- stack.Push(cur);
-
- Undo.RecordObject(renderer, "Generate Keyframe");
- var mat = renderer.material;
-
- for (int i = 0; i < 16; i++)
- {
- var prefix = $"_Vertex_Deformation_Slot_{i}_";
- var node = stack.Count > 0 ? stack.Pop() : null;
- var s = node?.Serialize();
- bool on = s != null;
-
- mat.SetFloat(prefix + "Enabled", on ? 1f : 0f);
- mat.SetInt(prefix + "Opcode", on ? s.opcode : 0);
- mat.SetFloat(prefix + "Float_0", on ? s.float0 : 0f);
- mat.SetFloat(prefix + "Float_1", on ? s.float1 : 0f);
- mat.SetFloat(prefix + "Float_2", on ? s.float2 : 0f);
- mat.SetFloat(prefix + "Float_3", on ? s.float3 : 0f);
- mat.SetVector(prefix + "Vector_0", on ? s.vec0 : Vector4.zero);
- mat.SetVector(prefix + "Vector_1", on ? s.vec1 : Vector4.zero);
- mat.SetVector(prefix + "Vector_2", on ? s.vec2 : Vector4.zero);
- mat.SetVector(prefix + "Vector_3", on ? s.vec3 : Vector4.zero);
- }
- EditorUtility.SetDirty(renderer);
- }
-}
-
-public class FoldGraphView : GraphView
-{
- static readonly (string label, Type dataType)[] AllNodeOptions =
- {
- ("Fold/Axis Align", typeof(AxisAlignNodeData)),
- ("Fold/Plane to Tube", typeof(PlaneToTubeNodeData)),
- ("Fold/Point Align", typeof(PointAlignNodeData)),
- ("Fold/Tube to Plane", typeof(TubeToPlaneNodeData)),
- ("Value/Float", typeof(FloatValueNodeData)),
- ("Value/Vector", typeof(VectorValueNodeData)),
- ("Value/GameObject", typeof(GameObjectNodeData)),
- ("Output/Keyframe", typeof(KeyframeNodeData)),
- };
-
- readonly FoldWindow window;
- public readonly FoldGraph graphAsset;
- readonly Dictionary<string, FoldNodeView> nodeLookup = new();
- readonly FoldEdgeConnectorListener edgeConnectorListener;
- bool suppressGraphChanges;
- readonly HashSet<string> pendingAutoComplete = new();
-
- void WithGraphChangesSuppressed(Action action)
- {
- var previous = suppressGraphChanges;
- suppressGraphChanges = true;
- try { action(); }
- finally { suppressGraphChanges = previous; }
- }
-
- public FoldGraphView(FoldWindow owner, FoldGraph graph)
- {
- window = owner;
- graphAsset = graph;
- edgeConnectorListener = new FoldEdgeConnectorListener(this);
-
- style.flexGrow = 1;
- this.AddManipulator(new ContentZoomer());
- this.AddManipulator(new ContentDragger());
- this.AddManipulator(new SelectionDragger());
- this.AddManipulator(new RectangleSelector());
-
- var grid = new GridBackground();
- Insert(0, grid);
- grid.StretchToParentSize();
-
- graphViewChanged = OnGraphViewChanged;
- nodeCreationRequest = ctx => ShowSearchWindow(null, ctx.screenMousePosition);
- RegisterCallback<KeyDownEvent>(OnKeyDown);
- RegisterCallback<ContextualMenuPopulateEvent>(evt => { evt.menu.ClearItems(); evt.StopImmediatePropagation(); evt.PreventDefault(); ShowSearchWindow(null, evt.mousePosition); });
- Undo.undoRedoPerformed += OnUndoRedo;
-
- Reload();
- }
-
- public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter) =>
- ports.Where(p => p.node != startPort.node && p.direction != startPort.direction &&
- (startPort.portType == null || p.portType == null || startPort.portType.IsAssignableFrom(p.portType) || p.portType.IsAssignableFrom(startPort.portType))).ToList();
-
- internal void BindEdgeConnector(Port port) => port.AddManipulator(new EdgeConnector<Edge>(edgeConnectorListener));
-
- GraphViewChange OnGraphViewChanged(GraphViewChange change)
- {
- if (suppressGraphChanges) return change;
- change.elementsToRemove?.ForEach(e => { if (e is Edge edge) RemoveEdgeData(edge); else if (e is FoldNodeView node) RemoveNode(node); });
- change.edgesToCreate?.ForEach(AddEdgeData);
- return change;
- }
-
- void RemoveNode(FoldNodeView node)
- {
- RecordUndo("Delete Node");
- graphAsset.nodes.Remove(node.Data);
- graphAsset.edges.RemoveAll(e => e.inputNodeGuid == node.Data.guid || e.outputNodeGuid == node.Data.guid);
- nodeLookup.Remove(node.Data.guid);
- MarkDirty();
- }
-
- internal void AddEdgeData(Edge edge)
- {
- if (edge.input?.node is not FoldNodeView inp || edge.output?.node is not FoldNodeView outp) return;
- RecordUndo("Add Edge");
- graphAsset.edges.Add(new FoldEdge { inputNodeGuid = inp.Data.guid, inputPortName = edge.input.portName, outputNodeGuid = outp.Data.guid, outputPortName = edge.output.portName });
- MarkDirty();
- }
-
- void RemoveEdgeData(Edge edge)
- {
- if (edge.input?.node is not FoldNodeView inp || edge.output?.node is not FoldNodeView outp) return;
- RecordUndo("Remove Edge");
- graphAsset.edges.RemoveAll(e => e.inputNodeGuid == inp.Data.guid && e.outputNodeGuid == outp.Data.guid && e.inputPortName == edge.input.portName && e.outputPortName == edge.output.portName);
- MarkDirty();
- }
-
- public void Reload() => WithGraphChangesSuppressed(() =>
- {
- nodeLookup.Clear();
- DeleteElements(graphElements.Where(e => e is Node or Edge).ToList());
-
- foreach (var d in graphAsset.nodes) { var n = CreateNode(d); nodeLookup[d.guid] = n; AddElement(n); }
- foreach (var e in graphAsset.edges)
- {
- if (nodeLookup.TryGetValue(e.outputNodeGuid, out var o) && nodeLookup.TryGetValue(e.inputNodeGuid, out var i))
- if (o.GetPort(e.outputPortName) is { } op && i.GetPort(e.inputPortName) is { } ip)
- AddElement(op.ConnectTo(ip));
- }
- });
-
- void OnKeyDown(KeyDownEvent evt)
- {
- if (evt.keyCode == KeyCode.D && (evt.commandKey || evt.ctrlKey)) { evt.StopImmediatePropagation(); DuplicateSelectedNodes(); }
- }
-
- void DuplicateSelectedNodes()
- {
- var sel = selection.OfType<FoldNodeView>().ToList();
- if (sel.Count == 0) return;
-
- RecordUndo("Duplicate Nodes");
-
- var map = new Dictionary<string, FoldNodeView>();
- WithGraphChangesSuppressed(() =>
- {
- foreach (var orig in sel)
- {
- var clone = (FoldNodeData)Activator.CreateInstance(orig.Data.GetType());
- JsonUtility.FromJsonOverwrite(JsonUtility.ToJson(orig.Data), clone);
- clone.guid = Guid.NewGuid().ToString();
- clone.position += new Vector2(30f, 30f);
- graphAsset.nodes.Add(clone);
- var v = CreateNode(clone);
- map[orig.Data.guid] = v;
- nodeLookup[clone.guid] = v;
- AddElement(v);
- }
-
- foreach (var e in graphAsset.edges.Where(e => map.ContainsKey(e.outputNodeGuid) && map.ContainsKey(e.inputNodeGuid)))
- if (map[e.outputNodeGuid].GetPort(e.outputPortName) is { } op && map[e.inputNodeGuid].GetPort(e.inputPortName) is { } ip)
- { var edge = op.ConnectTo(ip); AddElement(edge); AddEdgeData(edge); }
- });
-
- ClearSelection();
- foreach (var n in map.Values) AddToSelection(n);
- MarkDirty();
- }
-
- FoldNodeView CreateNode(FoldNodeData data)
- {
- FoldNodeView view = data switch
- {
- FloatValueNodeData or VectorValueNodeData or GameObjectNodeData => new ValueNodeView(),
- FoldOperationData => new OperationNodeView(),
- KeyframeNodeData => new KeyframeNodeView(),
- _ => throw new ArgumentOutOfRangeException(nameof(data))
- };
- view.Initialize(this, data);
- return view;
- }
-
- internal FoldNodeView CreateNode(Type dataType, Vector2 position, bool autoComplete = false)
- {
- if (!suppressGraphChanges) RecordUndo("Create Node");
- var data = (FoldNodeData)Activator.CreateInstance(dataType);
- data.position = position;
- graphAsset.nodes.Add(data);
- var view = CreateNode(data);
- nodeLookup[data.guid] = view;
- AddElement(view);
- view.RefreshExpandedState();
- view.RefreshPorts();
- if (autoComplete) RegisterGeometryOnce(view, () => AutoCreateSingleOptionNodes(view));
- MarkDirty();
- return view;
- }
-
- public void MarkDirty() => EditorUtility.SetDirty(graphAsset);
- public void ShowNotification(string msg) => window.ShowNotification(msg);
- public void ShowNodeCreationMenuFromPort(Port port, Vector2 pos) => ShowSearchWindow(port, pos);
- public void Dispose() => Undo.undoRedoPerformed -= OnUndoRedo;
- void OnUndoRedo() => Reload();
- internal void RecordUndo(string label) { if (!suppressGraphChanges) Undo.RegisterCompleteObjectUndo(graphAsset, label); }
-
- public FoldNodeView CreateNodeAndConnect(Port startPort, Type dataType, Vector2 pos)
- {
- RecordUndo("Create Node");
- FoldNodeView view = null;
- WithGraphChangesSuppressed(() =>
- {
- view = CreateNode(dataType, pos);
-
- // If dragging from input port, offset so the new node's right-center is at cursor once layout is computed
- if (startPort.direction == Direction.Input)
- RegisterGeometryOnce(view, () =>
- {
- var size = view.layout.size;
- view.SetPosition(new Rect(pos - new Vector2(size.x, size.y / 2), size));
- });
-
- var compat = GetCompatiblePorts(startPort, null).FirstOrDefault(p => p.node == view);
- if (compat != null)
- {
- var (o, i) = startPort.direction == Direction.Output ? (startPort, compat) : (compat, startPort);
- var edge = o.ConnectTo(i);
- AddElement(edge);
- AddEdgeData(edge);
- }
- });
- RegisterGeometryOnce(view, () => AutoCreateSingleOptionNodes(view));
- MarkDirty();
- return view;
- }
-
- internal IEnumerable<(string label, Type dataType)> GetNodeOptions(Port port)
- {
- if (port == null) return AllNodeOptions;
- var t = port.portType;
- bool @out = port.direction == Direction.Output;
- return AllNodeOptions.Where(o =>
- (t == typeof(float) || t == typeof(Vector4)) ? (@out ? typeof(FoldOperationData).IsAssignableFrom(o.dataType) : (t == typeof(float) ? o.dataType == typeof(FloatValueNodeData) : o.dataType == typeof(VectorValueNodeData))) :
- t == typeof(GameObject) ? (@out ? o.dataType == typeof(KeyframeNodeData) : o.dataType == typeof(GameObjectNodeData)) :
- typeof(IFoldNode).IsAssignableFrom(t) && (typeof(FoldOperationData).IsAssignableFrom(o.dataType) || (@out && o.dataType == typeof(KeyframeNodeData))));
- }
-
- public T GetInputValue<T>(string guid, string port, T fallback) =>
- nodeLookup.TryGetValue(guid, out var n) && n.GetPort(port)?.connections.FirstOrDefault()?.output?.node is ValueNodeView v ? v.GetTypedValue<T>() : fallback;
-
- void ShowSearchWindow(Port port, Vector2 pos)
- {
- var p = ScriptableObject.CreateInstance<FoldSearchProvider>();
- p.Initialize(this, port, pos);
- if (p.HasEntries()) SearchWindow.Open(new SearchWindowContext(GUIUtility.GUIToScreenPoint(pos)), p);
- }
-
- void AutoCreateSingleOptionNodes(FoldNodeView node)
- {
- if (node == null) return;
- pendingAutoComplete.Remove(node.Data.guid);
- var debug = new List<string>();
- var targetRect = EstimateNodeRect(node);
- if (targetRect.size == Vector2.zero)
- {
- if (pendingAutoComplete.Add(node.Data.guid))
- RegisterGeometryOnce(node, () => AutoCreateSingleOptionNodes(node));
- Debug.Log("Fold AutoComplete: defer (no size); layout=" + node.layout.size + " resolved=(" + node.resolvedStyle.width + "," + node.resolvedStyle.height + ")");
- return;
- }
-
- var ports = node.inputContainer.Children().OfType<Port>()
- .Where(p => !p.connections.Any())
- .Select((p, i) => (port: p, index: i))
- .ToList();
-
- var candidates = ports
- .Select(p => (p.port, p.index, options: GetNodeOptions(p.port).ToList()))
- .Where(p => p.options.Count == 1)
- .ToList();
-
- if (candidates.Count == 0) return;
-
- var created = new List<FoldNodeView>();
- var horizontalSpacing = targetRect.width + GetHorizontalMargins(node);
- var verticalSpacing = targetRect.height;
- var occupied = new List<Rect> { targetRect };
-
- RecordUndo("Auto-complete Ports");
- WithGraphChangesSuppressed(() =>
- {
- foreach (var (port, index, options) in candidates)
- {
- var dataType = options[0].dataType;
- var targetPos = targetRect.position;
- var desired = new Vector2(
- targetPos.x - horizontalSpacing,
- targetPos.y + (index - (candidates.Count - 1) * 0.5f) * verticalSpacing);
-
- var rect = FindFreePosition(new Rect(desired, targetRect.size), occupied, debug);
- if (rect == Rect.zero)
- {
- debug.Add($"fail place idx={index} type={dataType.Name} desired={desired}");
- continue;
- }
-
- var newNode = CreateNode(dataType, rect.position);
- created.Add(newNode);
-
- var compat = GetCompatiblePorts(port, null).FirstOrDefault(p => p.node == newNode);
- if (compat != null)
- {
- var (o, i) = port.direction == Direction.Output ? (port, compat) : (compat, port);
- var edge = o.ConnectTo(i);
- AddElement(edge);
- AddEdgeData(edge);
- }
- }
- });
-
- foreach (var child in created)
- AutoCreateSingleOptionNodes(child);
-
- Debug.Log($"Fold AutoComplete: node='{node.title}' size={targetRect.size} spacing=({horizontalSpacing},{verticalSpacing}) candidates={candidates.Count} created={created.Count} notes=[{string.Join("; ", debug)}]");
- MarkDirty();
- }
-
- Rect FindFreePosition(Rect desired, List<Rect> occupied, List<string> debug)
- {
- if (desired.size == Vector2.zero) return Rect.zero;
-
- Rect rect = desired;
- int safety = 0;
- while ((occupied?.Any(o => RectsOverlap(o, rect)) == true || OverlapsExisting(rect)) && safety++ < 50)
- rect.position += new Vector2(0f, rect.height);
- if (safety >= 50)
- {
- debug?.Add($"exceeded iterations({safety}) starting={desired.position}");
- return Rect.zero;
- }
- occupied?.Add(rect);
- return rect;
- }
-
- bool OverlapsExisting(Rect rect)
- {
- return nodeLookup.Values.Any(n =>
- {
- var existing = EstimateNodeRect(n);
- return existing.size != Vector2.zero && RectsOverlap(existing, rect);
- });
- }
-
- static Rect EstimateNodeRect(FoldNodeView node)
- {
- var size = node.layout.size;
- if (float.IsNaN(size.x) || float.IsNaN(size.y))
- size = Vector2.zero;
- if (size == Vector2.zero)
- {
- var rs = node.resolvedStyle;
- size = new Vector2(float.IsNaN(rs.width) ? 0f : rs.width, float.IsNaN(rs.height) ? 0f : rs.height);
- }
- if (float.IsNaN(size.x) || float.IsNaN(size.y))
- size = Vector2.zero;
- return size == Vector2.zero ? Rect.zero : new Rect(node.GetPosition().position, size);
- }
-
- static float GetHorizontalMargins(FoldNodeView node)
- {
- var rs = node.resolvedStyle;
- float left = float.IsNaN(rs.marginLeft) ? 0f : rs.marginLeft;
- float right = float.IsNaN(rs.marginRight) ? 0f : rs.marginRight;
- return left + right;
- }
-
- static bool RectsOverlap(Rect a, Rect b) =>
- a.xMin < b.xMax && a.xMax > b.xMin && a.yMin < b.yMax && a.yMax > b.yMin;
-
- static void RegisterGeometryOnce(VisualElement element, Action action)
- {
- bool TryInvoke()
- {
- var size = element.layout.size;
- if (float.IsNaN(size.x) || float.IsNaN(size.y) || size == Vector2.zero)
- {
- var rs = element.resolvedStyle;
- size = new Vector2(float.IsNaN(rs.width) ? 0f : rs.width, float.IsNaN(rs.height) ? 0f : rs.height);
- }
-
- if (size == Vector2.zero) return false;
- action?.Invoke();
- return true;
- };
-
- if (TryInvoke()) return;
-
- EventCallback<GeometryChangedEvent> handler = null;
- handler = evt =>
- {
- if (TryInvoke())
- element.UnregisterCallback<GeometryChangedEvent>(handler);
- };
- element.RegisterCallback<GeometryChangedEvent>(handler);
- }
-}
-
-class FoldEdgeConnectorListener : IEdgeConnectorListener
-{
- readonly FoldGraphView graphView;
- public FoldEdgeConnectorListener(FoldGraphView gv) => graphView = gv;
-
- public void OnDropOutsidePort(Edge edge, Vector2 pos) => graphView.ShowNodeCreationMenuFromPort(edge.output ?? edge.input, pos);
-
- public void OnDrop(GraphView gv, Edge edge)
- {
- if (edge.input == null || edge.output == null) return;
- edge.input.Connect(edge);
- edge.output.Connect(edge);
- gv.AddElement(edge);
- graphView?.AddEdgeData(edge);
- }
-}
-
-class FoldSearchProvider : ScriptableObject, ISearchWindowProvider
-{
- FoldGraphView graphView;
- Port startPort;
- Vector2 worldPosition;
- List<(string label, Type dataType)> options;
-
- public void Initialize(FoldGraphView gv, Port port, Vector2 pos) { graphView = gv; startPort = port; worldPosition = pos; options = gv.GetNodeOptions(port).ToList(); }
- public bool HasEntries() => options?.Count > 0;
-
- public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext ctx)
- {
- var entries = new List<SearchTreeEntry> { new SearchTreeGroupEntry(new GUIContent("Create Node"), 0) };
- foreach (var grp in options.GroupBy(o => o.label.Split('/')[0]).OrderBy(g => g.Key))
- {
- entries.Add(new SearchTreeGroupEntry(new GUIContent(grp.Key), 1));
- foreach (var opt in grp)
- entries.Add(new SearchTreeEntry(new GUIContent(opt.label.Split('/')[1])) { level = 2, userData = opt.dataType });
- }
- return entries;
- }
-
- public bool OnSelectEntry(SearchTreeEntry entry, SearchWindowContext ctx)
- {
- if (entry.userData is not Type dataType) return false;
- var pos = graphView.contentViewContainer.WorldToLocal(worldPosition);
- if (startPort != null) graphView.CreateNodeAndConnect(startPort, dataType, pos);
- else graphView.CreateNode(dataType, pos, true);
- return true;
- }
-}