Skip to content

Commit 024e6d8

Browse files
authored
Merge pull request #49 from VisualNodeDev/array-support
Array support
2 parents bd9af4f + af4f40f commit 024e6d8

41 files changed

Lines changed: 1798 additions & 820 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/dotnet.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- name: Setup .NET
2323
uses: actions/setup-dotnet@v4
2424
with:
25-
dotnet-version: 8.0.x
25+
dotnet-version: 9.0.x
2626

2727
- name: Restore .NET dependencies
2828
working-directory: ./src
@@ -48,7 +48,7 @@ jobs:
4848
- name: Setup .NET
4949
uses: actions/setup-dotnet@v4
5050
with:
51-
dotnet-version: 8.0.x
51+
dotnet-version: 9.0.x
5252

5353
- uses: actions/download-artifact@v4
5454
with:
@@ -68,7 +68,7 @@ jobs:
6868
- name: Setup .NET
6969
uses: actions/setup-dotnet@v4
7070
with:
71-
dotnet-version: 8.0.x
71+
dotnet-version: 9.0.x
7272

7373
- uses: actions/download-artifact@master
7474
with:

‎.gitignore‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@
2525
/src/NodeDev.Core.Types.Tests/bin
2626
/src/NodeDev.Core.Types.Tests/obj
2727
/src/NodeDev.Core.Types/bin
28-
/src/NodeDev.EndToEndTests/bin/Debug/net8.0
28+
/src/NodeDev.EndToEndTests/bin
2929
/src/NodeDev.EndToEndTests/obj
3030
/src/NodeDev.Blazor.Server/project_backup.json

‎src/NodeDev.Blazor/Components/GraphCanvas.razor.cs‎

Lines changed: 43 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
using System.Reactive.Linq;
1616
using NodeDev.Core.Class;
1717
using NodeDev.Blazor.Services;
18+
using NodeDev.Blazor.Services.GraphManager;
1819

1920
namespace NodeDev.Blazor.Components;
2021

21-
public partial class GraphCanvas : ComponentBase, IDisposable
22+
public partial class GraphCanvas : ComponentBase, IDisposable, IGraphCanvas
2223
{
2324
[Parameter, EditorRequired]
2425
public Graph Graph { get; set; } = null!;
@@ -29,6 +30,9 @@ public partial class GraphCanvas : ComponentBase, IDisposable
2930
[Inject]
3031
internal DebuggedPathService DebuggedPathService { get; set; } = null!;
3132

33+
private GraphManagerService? _GraphManagerService;
34+
private GraphManagerService GraphManagerService => _GraphManagerService ??= new GraphManagerService(this);
35+
3236
private int PopupX = 0;
3337
private int PopupY = 0;
3438
private Vector2 PopupNodePosition;
@@ -67,7 +71,6 @@ protected override void OnInitialized()
6771
Diagram.Links.Added += x => OnConnectionAdded(x, false);
6872
Diagram.Links.Removed += OnConnectionRemoved;
6973
Diagram.SelectionChanged += SelectionChanged;
70-
7174
}
7275

7376
#endregion
@@ -138,7 +141,7 @@ private void OnGraphChangedFromCore((Graph, bool) _)
138141

139142
#region UpdateConnectionType
140143

141-
private void UpdateConnectionType(Connection connection)
144+
public void UpdatePortColor(Connection connection)
142145
{
143146
var node = Diagram.Nodes.OfType<GraphNodeModel>().FirstOrDefault(x => x.Node == connection.Parent);
144147
if (node == null)
@@ -155,16 +158,6 @@ private void UpdateConnectionType(Connection connection)
155158

156159
#endregion
157160

158-
#region UpdateNodeBaseInfo
159-
160-
private void UpdateNodeBaseInfo(Node node)
161-
{
162-
var nodeModel = Diagram.Nodes.OfType<GraphNodeModel>().First(x => x.Node == node);
163-
nodeModel.UpdateNodeBaseInfo(node);
164-
}
165-
166-
#endregion
167-
168161
#region UpdateNodes
169162

170163
private void UpdateNodes(IEnumerable<Node> nodes)
@@ -239,7 +232,7 @@ private void OnConnectionUpdated(BaseLinkModel baseLinkModel, Anchor old, Anchor
239232
{
240233
DisableConnectionUpdate = true;
241234
var old = baseLinkModel.Source;
242-
baseLinkModel.SetSource(baseLinkModel.Target);
235+
baseLinkModel.SetSource(baseLinkModel.Target); // this is necessary as everything assumes that the source is an output and vice versa
243236
baseLinkModel.SetTarget(old);
244237
DisableConnectionUpdate = false;
245238

@@ -248,47 +241,7 @@ private void OnConnectionUpdated(BaseLinkModel baseLinkModel, Anchor old, Anchor
248241
destination = tmp;
249242
}
250243

251-
Graph.Connect(source.Connection, destination.Connection, false);
252-
253-
// we're plugging something something with a generic into something without a generic
254-
if (source.Connection.Type.HasUndefinedGenerics && !destination.Connection.Type.HasUndefinedGenerics)
255-
{
256-
if (source.Connection.Type.IsAssignableTo(destination.Connection.Type, out var newTypes) && newTypes.Count != 0)
257-
{
258-
PropagateNewGeneric(source.Connection.Parent, newTypes, false);
259-
}
260-
}
261-
else if (destination.Connection.Type.HasUndefinedGenerics && !source.Connection.Type.HasUndefinedGenerics)
262-
{
263-
if (source.Connection.Type.IsAssignableTo(destination.Connection.Type, out var newTypes) && newTypes.Count != 0)
264-
{
265-
PropagateNewGeneric(destination.Connection.Parent, newTypes, false);
266-
}
267-
}
268-
269-
// we have to remove the textbox ?
270-
if (destination.Connection.Connections.Count == 1 && destination.Connection.Type.AllowTextboxEdit)
271-
UpdateConnectionType(destination.Connection);
272-
273-
if (baseLinkModel is LinkModel link && link.Source.Model is GraphPortModel sourcePort && link.Target.Model is GraphPortModel targetPort)
274-
{
275-
link.Color = GetTypeShapeColor(sourcePort.Connection.Type, sourcePort.Connection.Parent.TypeFactory);
276-
// we have to disconnect the previously connected exec, since exec outputs can only have one connection
277-
if (source.Connection.Type.IsExec && source.Connection.Connections.Count > 1)
278-
{
279-
Diagram.Links.Remove(Diagram.Links.First(x => (x.Source.Model as GraphPortModel)?.Connection == source.Connection && (x.Target.Model as GraphPortModel)?.Connection != targetPort.Connection));
280-
Graph.Disconnect(source.Connection, source.Connection.Connections.First(x => x != targetPort.Connection), false);
281-
}
282-
else if (!destination.Connection.Type.IsExec && destination.Connection.Connections.Count > 1)
283-
{
284-
Diagram.Links.Remove(Diagram.Links.First(x => (x.Source.Model as GraphPortModel)?.Connection != source.Connection && (x.Target.Model as GraphPortModel)?.Connection == targetPort.Connection));
285-
Graph.Disconnect(destination.Connection, destination.Connection.Connections.First(x => x != sourcePort.Connection), false);
286-
}
287-
}
288-
289-
UpdateVerticesInConnection(source.Connection, destination.Connection, baseLinkModel);
290-
291-
Graph.RaiseGraphChanged(true);
244+
GraphManagerService.AddNewConnectionBetween(source.Connection, destination.Connection);
292245
});
293246
}
294247

@@ -318,6 +271,11 @@ public void OnConnectionAdded(BaseLinkModel baseLinkModel, bool force)
318271
}
319272
}
320273

274+
/// <summary>
275+
/// Return the output connection except for execs, in that case we return the input connection.
276+
/// This is because vertices are stored for the port, and execs conveniently only have one output connection while other types only have one input connection.
277+
/// </summary>
278+
/// <returns></returns>
321279
private Connection GetConnectionContainingVertices(Connection source, Connection destination)
322280
{
323281
if (source.Type.IsExec) // execs can only have one connection, therefor they always contains the vertex information
@@ -380,7 +338,7 @@ public void OnConnectionRemoved(BaseLinkModel baseLinkModel)
380338

381339
// We have to add back the textbox editor
382340
if (destination.Connections.Count == 0 && destination.Type.AllowTextboxEdit)
383-
UpdateConnectionType(destination);
341+
UpdatePortColor(destination);
384342

385343
UpdateVerticesInConnection(source, destination, baseLinkModel);
386344
}
@@ -433,11 +391,13 @@ private void OnNewNodeTypeSelected(NodeProvider.NodeSearchResult searchResult)
433391

434392
Diagram.Batch(() =>
435393
{
394+
CreateGraphNodeModel(node);
395+
436396
if (PopupNodeConnection != null && PopupNode != null)
437397
{
438398
// check if the source was an input or output and choose the proper destination based on that
439399
List<Connection> sources, destinations;
440-
bool isPopupNodeInput = PopupNode.Inputs.Contains(PopupNodeConnection);
400+
bool isPopupNodeInput = PopupNodeConnection.IsInput;
441401
if (isPopupNodeInput)
442402
{
443403
sources = PopupNode.Inputs;
@@ -453,43 +413,19 @@ private void OnNewNodeTypeSelected(NodeProvider.NodeSearchResult searchResult)
453413
if (PopupNodeConnection.Type is UndefinedGenericType) // can connect to anything except exec
454414
destination = destinations.FirstOrDefault(x => !x.Type.IsExec);
455415
else // can connect to anything that is assignable to the type
456-
destination = destinations.FirstOrDefault(x => PopupNodeConnection.Type.IsAssignableTo(x.Type, out _) || (x.Type is UndefinedGenericType && !PopupNodeConnection.Type.IsExec));
416+
destination = destinations.FirstOrDefault(x => PopupNodeConnection.Type.IsAssignableTo(x.Type, out _, out _) || (x.Type is UndefinedGenericType && !PopupNodeConnection.Type.IsExec));
457417

458418
// if we found a connection, connect them together
459419
if (destination != null)
460420
{
461-
Graph.Connect(PopupNodeConnection, destination, false);
462-
463-
if (destination.Connections.Count == 1 && destination.Type.AllowTextboxEdit)
464-
UpdateConnectionType(destination);
465-
if (PopupNodeConnection.Connections.Count == 1 && PopupNodeConnection.Type.AllowTextboxEdit)
466-
UpdateConnectionType(PopupNodeConnection);
467-
468421
var source = isPopupNodeInput ? destination : PopupNodeConnection;
469422
var target = isPopupNodeInput ? PopupNodeConnection : destination;
470423

471-
// check if we need to propagate some generic
472-
if (!destination.Type.IsExec && source.Type.IsAssignableTo(target.Type, out var changedGenerics))
473-
{
474-
PropagateNewGeneric(node, changedGenerics, false);
475-
PropagateNewGeneric(destination.Parent, changedGenerics, false);
476-
}
477-
else if (source.Type.IsExec && source.Connections.Count > 1) // check if we have to disconnect the previously connected exec
478-
{
479-
Diagram.Links.Remove(Diagram.Links.First(x => (x.Source.Model as GraphPortModel)?.Connection == source && (x.Target.Model as GraphPortModel)?.Connection != target));
480-
var toRemove = source.Connections.FirstOrDefault(x => x != target);
481-
if (toRemove != null)
482-
Graph.Disconnect(source, toRemove, false);
483-
}
424+
GraphManagerService.AddNewConnectionBetween(source, target);
484425
}
485426
}
486427

487428
CancelPopup();
488-
489-
CreateGraphNodeModel(node);
490-
AddNodeLinks(node, false);
491-
492-
UpdateNodes(Graph.Nodes.Values.ToList());
493429
});
494430

495431
}
@@ -513,9 +449,7 @@ private void OnNewOverloadSelected(Node.AlternateOverload overload)
513449
if (PopupNode == null)
514450
return;
515451

516-
PopupNode.SelectOverload(overload, out var newConnections, out var removedConnections);
517-
518-
Graph.MergedRemovedConnectionsWithNewConnections(newConnections, removedConnections);
452+
GraphManagerService.SelectNodeOverload(PopupNode, overload);
519453

520454
CancelPopup();
521455
}
@@ -525,9 +459,9 @@ private void OnNewOverloadSelected(Node.AlternateOverload overload)
525459
#region OnGenericTypeSelectionMenuAsked
526460

527461
private bool IsShowingGenericTypeSelection = false;
528-
private UndefinedGenericType? GenericTypeSelectionMenuGeneric;
462+
private string? GenericTypeSelectionMenuGeneric;
529463

530-
public void OnGenericTypeSelectionMenuAsked(GraphNodeModel nodeModel, UndefinedGenericType undefinedGenericType)
464+
public void OnGenericTypeSelectionMenuAsked(GraphNodeModel nodeModel, string undefinedGenericType)
531465
{
532466
PopupNode = nodeModel.Node;
533467
var p = Diagram.GetScreenPoint(nodeModel.Position.X, nodeModel.Position.Y) - Diagram.Container!.NorthWest;
@@ -544,42 +478,14 @@ private void OnGenericTypeSelected(TypeBase type)
544478
if (PopupNode == null || GenericTypeSelectionMenuGeneric == null)
545479
return;
546480

547-
PropagateNewGeneric(PopupNode, new Dictionary<UndefinedGenericType, TypeBase>() { [GenericTypeSelectionMenuGeneric] = type }, false);
481+
GraphManagerService.PropagateNewGeneric(PopupNode, new Dictionary<string, TypeBase>() { [GenericTypeSelectionMenuGeneric] = type }, false, null, overrideInitialTypes: true);
548482

549483
// Prefer updating the nodes directly instead of calling Graph.RaiseGraphChanged(true) to be sure it is called as soon as possible
550484
UpdateNodes(Graph.Nodes.Values.ToList());
551485

552486
CancelPopup();
553487
}
554488

555-
private void PropagateNewGeneric(Node node, IReadOnlyDictionary<UndefinedGenericType, TypeBase> changedGenerics, bool requireUIRefresh)
556-
{
557-
foreach (var port in node.InputsAndOutputs) // check if any of the ports have the generic we just solved
558-
{
559-
if (port.Type.GetUndefinedGenericTypes().Any(changedGenerics.ContainsKey))
560-
{
561-
var isPortInput = node.Inputs.Contains(port);
562-
563-
port.UpdateType(port.Type.ReplaceUndefinedGeneric(changedGenerics));
564-
565-
UpdateConnectionType(port);
566-
567-
// check if other connections had their own generics and if we just solved them
568-
foreach (var other in port.Connections.ToList())
569-
{
570-
var source = isPortInput ? other : port;
571-
var target = isPortInput ? port : other;
572-
if (source.Type.IsAssignableTo(target.Type, out var changedGenerics2) && changedGenerics2.Count != 0)
573-
PropagateNewGeneric(other.Parent, changedGenerics2, requireUIRefresh);
574-
else if ((changedGenerics2?.Count ?? 0) != 0)// damn, looks like changing the generic made it so we can't link to this connection anymore
575-
Graph.Disconnect(port, other, false); // no need to refresh UI here as it'll already be refresh at the end of this method
576-
}
577-
}
578-
}
579-
580-
Graph.RaiseGraphChanged(requireUIRefresh);
581-
}
582-
583489
#endregion
584490

585491
#region OnTextboxValueChanged
@@ -664,6 +570,26 @@ private void CancelPopup()
664570

665571
#endregion
666572

573+
#region RemoveLink
574+
575+
public void RemoveLinkFromGraphCanvas(Connection source, Connection destination)
576+
{
577+
Graph.Invoke(() =>
578+
{
579+
DisableConnectionUpdate = true;
580+
try
581+
{
582+
Diagram.Links.Remove(Diagram.Links.First(x => (x.Source.Model as GraphPortModel)?.Connection == source && (x.Target.Model as GraphPortModel)?.Connection == destination));
583+
}
584+
finally
585+
{
586+
DisableConnectionUpdate = false;
587+
}
588+
});
589+
}
590+
591+
#endregion
592+
667593
#region CreateGraphNodeModel
668594

669595
private void CreateGraphNodeModel(Node node)

‎src/NodeDev.Blazor/DiagramsModels/GraphNodeModel.cs‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,6 @@ public class GraphNodeModel : NodeModel
2424

2525
public GraphPortModel GetPort(Connection connection) => Ports.OfType<GraphPortModel>().First( x=> x.Connection == connection);
2626

27-
internal void UpdateNodeBaseInfo(Node node)
28-
{
29-
30-
}
31-
3227
internal void OnNodeExecuted(Connection exec)
3328
{
3429

‎src/NodeDev.Blazor/DiagramsModels/GraphNodeWidget.razor‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<span class="ml-1">&lt;</span>
1717
@foreach (var undefinedGeneric in undefinedGenerics)
1818
{
19-
<span class="ml-1 undefined-generic" @onclick="() => GraphCanvas.OnGenericTypeSelectionMenuAsked(Node, undefinedGeneric)">@(undefinedGeneric.Name + (undefinedGeneric == undefinedGenerics[^1] ? "" : ", "))</span>
19+
<span class="ml-1 undefined-generic" @onclick="() => GraphCanvas.OnGenericTypeSelectionMenuAsked(Node, undefinedGeneric)">@(undefinedGeneric + (undefinedGeneric == undefinedGenerics[^1] ? "" : ", "))</span>
2020
}
2121
<span class="ml-1">&gt;</span>
2222
}

‎src/NodeDev.Blazor/DiagramsModels/GraphPortModel.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ public override bool CanAttachTo(ILinkable other)
2929
if(Alignment == otherPort.Alignment) // can't plug input to input or output to output
3030
return false;
3131

32-
return Connection.Type.IsAssignableTo(otherPort.Connection.Type, out _);
32+
return Connection.Type.IsAssignableTo(otherPort.Connection.Type, out _, out _);
3333
}
3434
}

0 commit comments

Comments
 (0)