implemente the knot node
This commit is contained in:
@@ -42,6 +42,9 @@ namespace Nodify.Calculator
|
||||
|
||||
// Dynamic ForEach node: adapt Current Item output based on list type
|
||||
if (!IsLoading) HandleForEachNodeConnected(c);
|
||||
|
||||
// Dynamic Knot node: adapt shape/color to match connected wire
|
||||
if (!IsLoading) HandleKnotNodeConnected(c);
|
||||
})
|
||||
.WhenRemoved(c =>
|
||||
{
|
||||
@@ -74,6 +77,9 @@ namespace Nodify.Calculator
|
||||
|
||||
// Dynamic ForEach node: reset Current Item output on disconnect
|
||||
HandleForEachNodeDisconnected(c);
|
||||
|
||||
// Dynamic Knot node: reset on disconnect
|
||||
HandleKnotNodeDisconnected(c);
|
||||
});
|
||||
|
||||
Operations.WhenAdded(x =>
|
||||
@@ -137,6 +143,12 @@ namespace Nodify.Calculator
|
||||
public PendingConnectionViewModel PendingConnection { get; set; } = new PendingConnectionViewModel();
|
||||
public OperationsMenuViewModel OperationsMenu { get; set; }
|
||||
|
||||
public void CreateKnotNodeAt(Point location)
|
||||
{
|
||||
var knot = new KnotOperationViewModel { Location = location };
|
||||
Operations.Add(knot);
|
||||
}
|
||||
|
||||
public INodifyCommand StartConnectionCommand { get; }
|
||||
public INodifyCommand CreateConnectionCommand { get; }
|
||||
public INodifyCommand DisconnectConnectorCommand { get; }
|
||||
@@ -152,6 +164,7 @@ namespace Nodify.Calculator
|
||||
internal bool CanCreateConnection(ConnectorViewModel source, ConnectorViewModel? target)
|
||||
=> target == null || (source != target &&
|
||||
(source.Shape == target.Shape ||
|
||||
source.IsKnotConnector || target.IsKnotConnector ||
|
||||
((source.IsCopyConnector || target.IsCopyConnector) && source.Shape != ConnectorShape.Triangle && target.Shape != ConnectorShape.Triangle)) &&
|
||||
!source.IsConnected &&
|
||||
!target.IsConnected &&
|
||||
@@ -714,6 +727,69 @@ namespace Nodify.Calculator
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleKnotNodeConnected(ConnectionViewModel c)
|
||||
{
|
||||
ConnectorViewModel knotConn = null;
|
||||
ConnectorViewModel sourceConn = null;
|
||||
|
||||
if (c.Input.IsKnotConnector)
|
||||
{
|
||||
knotConn = c.Input;
|
||||
sourceConn = c.Output;
|
||||
}
|
||||
else if (c.Output.IsKnotConnector)
|
||||
{
|
||||
knotConn = c.Output;
|
||||
sourceConn = c.Input;
|
||||
}
|
||||
|
||||
if (knotConn == null) return;
|
||||
|
||||
var knotOp = knotConn.Operation as KnotOperationViewModel;
|
||||
if (knotOp == null) return;
|
||||
|
||||
// Adapt both input and output connectors to match the connected wire's shape/color/type
|
||||
foreach (var conn in knotOp.Input.Concat(knotOp.Output))
|
||||
{
|
||||
if (conn.Shape != ConnectorShape.Triangle)
|
||||
{
|
||||
conn.Shape = sourceConn.Shape;
|
||||
conn.ConnectorColor = sourceConn.RawColor;
|
||||
conn.DataType = sourceConn.DataType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleKnotNodeDisconnected(ConnectionViewModel c)
|
||||
{
|
||||
ConnectorViewModel knotConn = null;
|
||||
|
||||
if (c.Input.IsKnotConnector)
|
||||
knotConn = c.Input;
|
||||
else if (c.Output.IsKnotConnector)
|
||||
knotConn = c.Output;
|
||||
|
||||
if (knotConn == null) return;
|
||||
|
||||
var knotOp = knotConn.Operation as KnotOperationViewModel;
|
||||
if (knotOp == null) return;
|
||||
|
||||
// Check if any connection still exists on the knot
|
||||
var stillConnected = Connections.Any(con =>
|
||||
(con.Input.IsKnotConnector && con.Input.Operation == knotOp) ||
|
||||
(con.Output.IsKnotConnector && con.Output.Operation == knotOp));
|
||||
|
||||
if (stillConnected) return;
|
||||
|
||||
// Reset to default
|
||||
foreach (var conn in knotOp.Input.Concat(knotOp.Output))
|
||||
{
|
||||
conn.Shape = ConnectorShape.Circle;
|
||||
conn.ConnectorColor = System.Drawing.Color.DodgerBlue;
|
||||
conn.DataType = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleForEachNodeDisconnected(ConnectionViewModel c)
|
||||
{
|
||||
ConnectorViewModel forEachListInput = null;
|
||||
|
||||
@@ -121,6 +121,16 @@ namespace Nodify.Calculator
|
||||
set => SetProperty(ref _isCopyConnector, value);
|
||||
}
|
||||
|
||||
private bool _isKnotConnector;
|
||||
/// <summary>
|
||||
/// When true, this connector belongs to a Knot/Reroute node and accepts any shape for connections.
|
||||
/// </summary>
|
||||
public bool IsKnotConnector
|
||||
{
|
||||
get => _isKnotConnector;
|
||||
set => SetProperty(ref _isKnotConnector, value);
|
||||
}
|
||||
|
||||
private bool _isTakeListConnector;
|
||||
/// <summary>
|
||||
/// When true, this connector belongs to a TAKE node and only accepts list/array types.
|
||||
|
||||
@@ -646,6 +646,20 @@
|
||||
</nodify:Node>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type local:KnotOperationViewModel}">
|
||||
<nodify:Node Input="{Binding Input}"
|
||||
Output="{Binding Output}"
|
||||
Background="#FF2A2A2A"
|
||||
BorderBrush="#FF666666"
|
||||
BorderThickness="1"
|
||||
Padding="0"
|
||||
ToolTip="Knot (Reroute) — Ctrl+Click to create">
|
||||
<Ellipse Width="8" Height="8"
|
||||
Fill="#FFAAAAAA"
|
||||
Margin="2" />
|
||||
</nodify:Node>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type local:OperationViewModel}">
|
||||
<nodify:Node Content="{Binding Title}"
|
||||
Input="{Binding Input}"
|
||||
|
||||
@@ -34,6 +34,26 @@ namespace Nodify.Calculator
|
||||
}
|
||||
}
|
||||
|
||||
public class KnotNodeHandler : InputElementState<NodifyEditor>
|
||||
{
|
||||
private static InputGesture CreateKnotGesture { get; } = new Interactivity.MouseGesture(MouseAction.LeftClick, ModifierKeys.Control);
|
||||
|
||||
public KnotNodeHandler(NodifyEditor element) : base(element)
|
||||
{
|
||||
ProcessHandledEvents = true;
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseButtonEventArgs e)
|
||||
{
|
||||
if (CreateKnotGesture.Matches(e.Source, e) && Element.DataContext is CalculatorViewModel calculator)
|
||||
{
|
||||
var location = Element.MouseLocation;
|
||||
calculator.CreateKnotNodeAt(location);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class EditorView : UserControl
|
||||
{
|
||||
public EditorView()
|
||||
@@ -44,6 +64,7 @@ namespace Nodify.Calculator
|
||||
static EditorView()
|
||||
{
|
||||
InputProcessor.Shared<NodifyEditor>.RegisterHandlerFactory(editor => new OperationsMenuHandler(editor));
|
||||
InputProcessor.Shared<NodifyEditor>.RegisterHandlerFactory(editor => new KnotNodeHandler(editor));
|
||||
}
|
||||
|
||||
private void OnDropNode(object sender, DragEventArgs e)
|
||||
|
||||
@@ -428,6 +428,20 @@ namespace Nodify.Calculator
|
||||
OnLogMe?.Invoke($"Auth node resolved. Base URL: {_authBaseUrl}, Auth Type: {_authType}");
|
||||
return;
|
||||
}
|
||||
// Knot/Reroute node: passthrough - forward input data to output
|
||||
if (op is KnotOperationViewModel)
|
||||
{
|
||||
var knotInputCon = connections.Where(c => c.Input.Operation == op && c.Input.Shape != ConnectorShape.Triangle).FirstOrDefault();
|
||||
if (knotInputCon != null)
|
||||
{
|
||||
var srcNodeId = knotInputCon.Output?.Operation?.NodeId;
|
||||
if (srcNodeId != null && outputs.TryGetValue(srcNodeId, out var srcVal))
|
||||
{
|
||||
outputs[op.NodeId] = srcVal;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (op is SystemOperationViewModel debugSysOp && debugSysOp.SystemOperationType == SystemOperations.DEBUG)
|
||||
{
|
||||
// Find the data input connection (non-triangle)
|
||||
|
||||
15
Examples/Nodify.Calculator/KnotOperationViewModel.cs
Normal file
15
Examples/Nodify.Calculator/KnotOperationViewModel.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Nodify.Calculator
|
||||
{
|
||||
public class KnotOperationViewModel : SystemOperationViewModel
|
||||
{
|
||||
public KnotOperationViewModel()
|
||||
{
|
||||
Title = "⬥";
|
||||
SystemOperationType = SystemOperations.KNOT;
|
||||
|
||||
// Single flow-through input and output (will adapt shape when connected)
|
||||
Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Circle, IsKnotConnector = true });
|
||||
Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Circle, IsKnotConnector = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,8 @@ namespace Nodify.Calculator
|
||||
DEBUG,
|
||||
NEW_OBJECT,
|
||||
FOREACH,
|
||||
ASSERT
|
||||
ASSERT,
|
||||
KNOT
|
||||
}
|
||||
|
||||
public class SystemOperationViewModel : OperationViewModel
|
||||
|
||||
Reference in New Issue
Block a user