Major changes in the flow of code, implemented modularization of the code for maintainability
Some checks failed
Build / build (push) Has been cancelled
Some checks failed
Build / build (push) Has been cancelled
This commit is contained in:
145
Examples/Nodify.Calculator/NodeHandlers/BasicSystemHandlers.cs
Normal file
145
Examples/Nodify.Calculator/NodeHandlers/BasicSystemHandlers.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
using Nodify.Calculator.Models;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Nodify.Calculator.NodeHandlers
|
||||
{
|
||||
// ─── BEGIN / END ───
|
||||
public class BeginEndHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System
|
||||
&& (info.sysOp == SystemOperations.BEGIN || info.sysOp == SystemOperations.END);
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System"
|
||||
&& (data.SystemOp == nameof(SystemOperations.BEGIN) || data.SystemOp == nameof(SystemOperations.END));
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new SystemOperationViewModel
|
||||
{
|
||||
Title = info.Title,
|
||||
SystemOperationType = info.sysOp
|
||||
};
|
||||
if (info.sysOp == SystemOperations.BEGIN)
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", IsInput = false, Shape = ConnectorShape.Triangle, ConnectorColor = Color.DarkRed });
|
||||
else
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, ConnectorColor = Color.DarkRed });
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var sysOp = data.SystemOp == nameof(SystemOperations.BEGIN) ? SystemOperations.BEGIN : SystemOperations.END;
|
||||
var info = new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = sysOp };
|
||||
return Create(info);
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
if (vm is SystemOperationViewModel sys)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = sys.SystemOperationType.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── COPY ───
|
||||
public class CopyHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System && info.sysOp == SystemOperations.COPY;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.COPY);
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new SystemOperationViewModel
|
||||
{
|
||||
Title = info.Title ?? "COPY",
|
||||
SystemOperationType = SystemOperations.COPY
|
||||
};
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Circle, ConnectorColor = Color.White, IsCopyConnector = true });
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var op = Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.COPY });
|
||||
|
||||
// Restore adapted input connector
|
||||
if (data.InputConnectors.Count > 0 && data.InputConnectors[0].Shape != "Circle")
|
||||
{
|
||||
var saved = data.InputConnectors[0];
|
||||
if (op.Input.Count > 0)
|
||||
{
|
||||
var inp = op.Input[0];
|
||||
inp.Shape = NodeHandlerRegistry.ParseShape(saved.Shape);
|
||||
inp.ConnectorColor = Color.FromArgb(saved.ColorArgb);
|
||||
inp.DataType = saved.DataType;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore output connectors
|
||||
foreach (var sc in data.OutputConnectors)
|
||||
op.Output.Add(NodeHandlerRegistry.DeserializeConnector(sc, false));
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = nameof(SystemOperations.COPY);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── SPLIT ───
|
||||
public class SplitHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System && info.sysOp == SystemOperations.SPLIT;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.SPLIT);
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new SystemOperationViewModel
|
||||
{
|
||||
Title = info.Title ?? "Split",
|
||||
SystemOperationType = SystemOperations.SPLIT
|
||||
};
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Square, ConnectorColor = Color.MediumPurple });
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var op = (SystemOperationViewModel)Create(new OperationInfoViewModel { Title = "Split", Type = OperationType.System, sysOp = SystemOperations.SPLIT });
|
||||
|
||||
// Restore dynamic outputs from saved data
|
||||
foreach (var sc in data.OutputConnectors)
|
||||
{
|
||||
if (sc.Shape == "Triangle") continue;
|
||||
op.Output.Add(NodeHandlerRegistry.DeserializeConnector(sc, false));
|
||||
}
|
||||
op.Title = data.Title;
|
||||
return op;
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = nameof(SystemOperations.SPLIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
170
Examples/Nodify.Calculator/NodeHandlers/FlowNodeHandlers.cs
Normal file
170
Examples/Nodify.Calculator/NodeHandlers/FlowNodeHandlers.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using Nodify.Calculator.Models;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace Nodify.Calculator.NodeHandlers
|
||||
{
|
||||
// ─── DEBUG ───
|
||||
public class DebugHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System && info.sysOp == SystemOperations.DEBUG;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.DEBUG);
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new SystemOperationViewModel
|
||||
{
|
||||
Title = info.Title ?? "Debug",
|
||||
SystemOperationType = SystemOperations.DEBUG
|
||||
};
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||
op.Input.Add(new ConnectorViewModel { Title = "Value", ConnectorColor = Color.LimeGreen });
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
=> Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.DEBUG });
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = nameof(SystemOperations.DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── AUTH ───
|
||||
public class AuthHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System && info.sysOp == SystemOperations.AUTH;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.AUTH);
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new AuthOperationViewModel();
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||
// Data inputs
|
||||
var labels = new[] { "Base URL", "Auth Type", "Token", "API Key", "Username", "Password" };
|
||||
foreach (var label in labels)
|
||||
op.Input.Add(new ConnectorViewModel { Title = label, ConnectorColor = Color.Orange });
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var op = new AuthOperationViewModel
|
||||
{
|
||||
BaseUrl = data.AuthBaseUrl ?? string.Empty,
|
||||
AuthType = !string.IsNullOrEmpty(data.AuthType) ? data.AuthType : "Bearer Token"
|
||||
};
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||
|
||||
// Restore data inputs from saved connectors (skip triangles)
|
||||
foreach (var ic in data.InputConnectors)
|
||||
{
|
||||
if (ic.Shape == "Triangle") continue;
|
||||
op.Input.Add(NodeHandlerRegistry.DeserializeConnector(ic, true));
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = nameof(SystemOperations.AUTH);
|
||||
if (vm is AuthOperationViewModel auth)
|
||||
{
|
||||
data.AuthBaseUrl = auth.BaseUrl ?? string.Empty;
|
||||
data.AuthType = auth.AuthType ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── TAKE ───
|
||||
public class TakeHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System && info.sysOp == SystemOperations.TAKE;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.TAKE);
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new TakeOperationViewModel
|
||||
{
|
||||
Title = info.Title ?? "TAKE",
|
||||
SystemOperationType = SystemOperations.TAKE
|
||||
};
|
||||
op.Input.Add(new ConnectorViewModel
|
||||
{
|
||||
Title = "List",
|
||||
Shape = ConnectorShape.Circle,
|
||||
ConnectorColor = Color.White,
|
||||
IsCopyConnector = true,
|
||||
IsTakeListConnector = true
|
||||
});
|
||||
var nthConnector = new ConnectorViewModel
|
||||
{
|
||||
Title = "Nth",
|
||||
Shape = ConnectorShape.Circle,
|
||||
ConnectorColor = ConnectorViewModel.GetColorForType("int"),
|
||||
DataType = "int"
|
||||
};
|
||||
op.NthConnector = nthConnector;
|
||||
op.Input.Add(nthConnector);
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var op = (TakeOperationViewModel)Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.TAKE });
|
||||
op.NthIndex = data.NthIndex;
|
||||
op.IsRandom = data.IsRandom;
|
||||
|
||||
// Restore adapted list input
|
||||
var savedListInp = data.InputConnectors.FirstOrDefault(c => c.IsTakeListConnector);
|
||||
if (savedListInp != null)
|
||||
{
|
||||
var listInp = op.Input.FirstOrDefault(i => i.IsTakeListConnector);
|
||||
if (listInp != null)
|
||||
{
|
||||
listInp.Shape = NodeHandlerRegistry.ParseShape(savedListInp.Shape);
|
||||
listInp.ConnectorColor = Color.FromArgb(savedListInp.ColorArgb);
|
||||
listInp.DataType = savedListInp.DataType;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore outputs
|
||||
foreach (var sc in data.OutputConnectors)
|
||||
op.Output.Add(NodeHandlerRegistry.DeserializeConnector(sc, false));
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = nameof(SystemOperations.TAKE);
|
||||
if (vm is TakeOperationViewModel take)
|
||||
{
|
||||
data.NthIndex = take.NthIndex;
|
||||
data.IsRandom = take.IsRandom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
209
Examples/Nodify.Calculator/NodeHandlers/GetSetHandlers.cs
Normal file
209
Examples/Nodify.Calculator/NodeHandlers/GetSetHandlers.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
using Nodify.Calculator.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Nodify.Calculator.NodeHandlers
|
||||
{
|
||||
// ─── GET/SET for simple variables (IsSimpleVariable = true) ───
|
||||
public class GetSetVariableHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System
|
||||
&& info.sysOp == SystemOperations.GET_SET
|
||||
&& info.IsSimpleVariable;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System"
|
||||
&& data.SystemOp == nameof(SystemOperations.GET_SET)
|
||||
&& data.IsSimpleVariable;
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var varType = (info.VariableType ?? "").ToLower();
|
||||
var varColor = ConnectorViewModel.GetColorForType(varType);
|
||||
var varLabel = $"{info.Title} {info.ClassName} ({info.VariableType})";
|
||||
|
||||
var op = new SystemOperationViewModel
|
||||
{
|
||||
Title = varLabel,
|
||||
SystemOperationType = SystemOperations.GET_SET,
|
||||
IsSimpleVariable = true,
|
||||
VariableType = info.VariableType ?? string.Empty,
|
||||
ClassName = info.ClassName ?? string.Empty
|
||||
};
|
||||
|
||||
if (info.Title == "GET")
|
||||
{
|
||||
op.Output.Add(new ConnectorViewModel
|
||||
{
|
||||
Title = "Value",
|
||||
IsInput = false,
|
||||
Shape = ConnectorShape.Circle,
|
||||
ConnectorColor = varColor,
|
||||
DataType = varType
|
||||
});
|
||||
}
|
||||
else // SET
|
||||
{
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||
op.Input.Add(new ConnectorViewModel
|
||||
{
|
||||
Title = "Value",
|
||||
Shape = ConnectorShape.Circle,
|
||||
ConnectorColor = varColor,
|
||||
DataType = varType
|
||||
});
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var savedTitle = data.Title ?? "";
|
||||
var prefix = savedTitle.StartsWith("SET ") ? "SET" : "GET";
|
||||
var info = new OperationInfoViewModel
|
||||
{
|
||||
Title = prefix,
|
||||
Type = OperationType.System,
|
||||
sysOp = SystemOperations.GET_SET,
|
||||
IsSimpleVariable = true,
|
||||
VariableType = data.VariableType ?? string.Empty,
|
||||
ClassName = data.ClassName ?? string.Empty
|
||||
};
|
||||
return Create(info);
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = nameof(SystemOperations.GET_SET);
|
||||
if (vm is SystemOperationViewModel sys)
|
||||
{
|
||||
data.ClassName = sys.ClassName ?? string.Empty;
|
||||
data.IsSimpleVariable = true;
|
||||
data.VariableType = sys.VariableType ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── GET/SET for model types (IsModelNode = true, IsSimpleVariable = false) ───
|
||||
public class GetSetModelHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System
|
||||
&& info.sysOp == SystemOperations.GET_SET
|
||||
&& info.IsModelNode
|
||||
&& !info.IsSimpleVariable;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System"
|
||||
&& data.SystemOp == nameof(SystemOperations.GET_SET)
|
||||
&& !data.IsSimpleVariable
|
||||
&& !string.IsNullOrEmpty(data.ClassName);
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new SystemOperationViewModel
|
||||
{
|
||||
Title = $"{info.Title} {info.ClassName}",
|
||||
SystemOperationType = SystemOperations.GET_SET,
|
||||
IsSimpleVariable = false,
|
||||
ClassName = info.ClassName ?? string.Empty
|
||||
};
|
||||
|
||||
if (info.Title == "GET")
|
||||
{
|
||||
// GET model: output a Square connector for the model
|
||||
op.Output.Add(new ConnectorViewModel
|
||||
{
|
||||
Title = info.ClassName ?? "",
|
||||
IsInput = false,
|
||||
Shape = ConnectorShape.Square,
|
||||
ConnectorColor = Color.MediumPurple,
|
||||
DataType = info.ClassName ?? "object"
|
||||
});
|
||||
}
|
||||
else // SET
|
||||
{
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||
|
||||
// Try to read class properties for detailed connectors
|
||||
var customModelDir = Path.Combine(ProjectManager.ProjectDirectory, "CustomModels");
|
||||
Directory.CreateDirectory(customModelDir);
|
||||
var filePath = Path.Combine(customModelDir, info.ClassName + ".cs");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
var fileContent = File.ReadAllText(filePath);
|
||||
var properties = OperationFactory.GetPropertiesFromClassPublic(fileContent);
|
||||
|
||||
// Square input for the class object
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Square, ConnectorColor = Color.MediumPurple });
|
||||
|
||||
// Circle output per property, colored by type
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var propColor = ConnectorViewModel.GetColorForType(property.Type);
|
||||
op.Output.Add(new ConnectorViewModel
|
||||
{
|
||||
Title = $"{property.Name} ({property.Type})",
|
||||
IsInput = false,
|
||||
Shape = ConnectorShape.Circle,
|
||||
ConnectorColor = propColor,
|
||||
DataType = property.Type.ToLower()
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: generic square I/O
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Square, ConnectorColor = Color.MediumPurple });
|
||||
op.Output.Add(new ConnectorViewModel
|
||||
{
|
||||
Title = info.ClassName ?? "",
|
||||
IsInput = false,
|
||||
Shape = ConnectorShape.Square,
|
||||
ConnectorColor = Color.MediumPurple,
|
||||
DataType = info.ClassName ?? "object"
|
||||
});
|
||||
}
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var savedTitle = data.Title ?? "";
|
||||
var prefix = savedTitle.StartsWith("SET ") ? "SET" : "GET";
|
||||
var info = new OperationInfoViewModel
|
||||
{
|
||||
Title = prefix,
|
||||
Type = OperationType.System,
|
||||
sysOp = SystemOperations.GET_SET,
|
||||
IsModelNode = true,
|
||||
IsSimpleVariable = false,
|
||||
ClassName = data.ClassName ?? string.Empty
|
||||
};
|
||||
return Create(info);
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = nameof(SystemOperations.GET_SET);
|
||||
if (vm is SystemOperationViewModel sys)
|
||||
{
|
||||
data.ClassName = sys.ClassName ?? string.Empty;
|
||||
data.IsSimpleVariable = false;
|
||||
data.VariableType = sys.VariableType ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
45
Examples/Nodify.Calculator/NodeHandlers/INodeHandler.cs
Normal file
45
Examples/Nodify.Calculator/NodeHandlers/INodeHandler.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Nodify.Calculator.Models;
|
||||
|
||||
namespace Nodify.Calculator.NodeHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Each node type implements this interface to encapsulate its own
|
||||
/// creation, save and load logic — eliminating giant switch/if chains.
|
||||
/// </summary>
|
||||
public interface INodeHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// The NodeType discriminator stored in <see cref="NodeData.NodeType"/> (e.g. "System", "API", "Function").
|
||||
/// </summary>
|
||||
string NodeTypeKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this handler can create a node from the given <see cref="OperationInfoViewModel"/>.
|
||||
/// Used when building a node from the toolbox / left-panel.
|
||||
/// </summary>
|
||||
bool CanCreate(OperationInfoViewModel info);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this handler can restore a node from the given <see cref="NodeData"/>.
|
||||
/// Used when loading a saved graph.
|
||||
/// </summary>
|
||||
bool CanRestore(NodeData data);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the <see cref="OperationViewModel"/> from toolbox info.
|
||||
/// </summary>
|
||||
OperationViewModel Create(OperationInfoViewModel info);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the <see cref="OperationViewModel"/> from saved <see cref="NodeData"/>.
|
||||
/// The base properties (NodeId, Location) are set by the caller.
|
||||
/// </summary>
|
||||
OperationViewModel Restore(NodeData data);
|
||||
|
||||
/// <summary>
|
||||
/// Writes ViewModel-specific properties into <see cref="NodeData"/> during save.
|
||||
/// Common properties (NodeId, Title, Location, Connectors) are handled by the caller.
|
||||
/// </summary>
|
||||
void Save(OperationViewModel vm, NodeData data);
|
||||
}
|
||||
}
|
||||
133
Examples/Nodify.Calculator/NodeHandlers/NodeHandlerRegistry.cs
Normal file
133
Examples/Nodify.Calculator/NodeHandlers/NodeHandlerRegistry.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using Nodify.Calculator.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace Nodify.Calculator.NodeHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Registry that discovers and dispatches to the correct <see cref="INodeHandler"/>.
|
||||
/// Replaces all the switch/if chains in OperationFactory and GraphSerializer.
|
||||
/// </summary>
|
||||
public static class NodeHandlerRegistry
|
||||
{
|
||||
private static readonly List<INodeHandler> _handlers = new();
|
||||
private static bool _initialized;
|
||||
|
||||
public static IReadOnlyList<INodeHandler> Handlers
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureInitialized();
|
||||
return _handlers;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureInitialized()
|
||||
{
|
||||
if (_initialized) return;
|
||||
_initialized = true;
|
||||
|
||||
// Register all handlers — order matters for CanCreate/CanRestore matching.
|
||||
// More specific handlers first (e.g. TakeHandler before generic SystemHandler).
|
||||
_handlers.Add(new KnotHandler());
|
||||
_handlers.Add(new FunctionHandler());
|
||||
_handlers.Add(new AuthHandler());
|
||||
_handlers.Add(new TakeHandler());
|
||||
_handlers.Add(new ForEachHandler());
|
||||
_handlers.Add(new AssertHandler());
|
||||
_handlers.Add(new DebugHandler());
|
||||
_handlers.Add(new NewObjectHandler());
|
||||
_handlers.Add(new CopyHandler());
|
||||
_handlers.Add(new SplitHandler());
|
||||
_handlers.Add(new GetSetVariableHandler());
|
||||
_handlers.Add(new GetSetModelHandler());
|
||||
_handlers.Add(new BeginEndHandler());
|
||||
_handlers.Add(new GenericSystemHandler());
|
||||
_handlers.Add(new ApiHandler());
|
||||
_handlers.Add(new ExpandoHandler());
|
||||
_handlers.Add(new NormalHandler());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the handler that can create a node from toolbox info.
|
||||
/// </summary>
|
||||
public static INodeHandler? FindForCreate(OperationInfoViewModel info)
|
||||
{
|
||||
EnsureInitialized();
|
||||
return _handlers.FirstOrDefault(h => h.CanCreate(info));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the handler that can restore a node from saved data.
|
||||
/// </summary>
|
||||
public static INodeHandler? FindForRestore(NodeData data)
|
||||
{
|
||||
EnsureInitialized();
|
||||
return _handlers.FirstOrDefault(h => h.CanRestore(data));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the handler that can save a given ViewModel.
|
||||
/// </summary>
|
||||
public static INodeHandler? FindForSave(OperationViewModel vm)
|
||||
{
|
||||
EnsureInitialized();
|
||||
// Build a temporary info to test CanCreate? No — instead match by VM type.
|
||||
// We use a simple type check cascade, but kept in one place.
|
||||
return vm switch
|
||||
{
|
||||
KnotOperationViewModel => _handlers.OfType<KnotHandler>().FirstOrDefault(),
|
||||
FunctionOperationViewModel => _handlers.OfType<FunctionHandler>().FirstOrDefault(),
|
||||
AuthOperationViewModel => _handlers.OfType<AuthHandler>().FirstOrDefault(),
|
||||
TakeOperationViewModel => _handlers.OfType<TakeHandler>().FirstOrDefault(),
|
||||
ForEachOperationViewModel => _handlers.OfType<ForEachHandler>().FirstOrDefault(),
|
||||
AssertOperationViewModel => _handlers.OfType<AssertHandler>().FirstOrDefault(),
|
||||
APIOperationViewModel => _handlers.OfType<ApiHandler>().FirstOrDefault(),
|
||||
ExpandoOperationViewModel => _handlers.OfType<ExpandoHandler>().FirstOrDefault(),
|
||||
CalculatorOperationViewModel => _handlers.OfType<NormalHandler>().FirstOrDefault(),
|
||||
SystemOperationViewModel sys => FindSystemSaveHandler(sys),
|
||||
_ => _handlers.OfType<NormalHandler>().FirstOrDefault()
|
||||
};
|
||||
}
|
||||
|
||||
private static INodeHandler? FindSystemSaveHandler(SystemOperationViewModel sys)
|
||||
{
|
||||
return sys.SystemOperationType switch
|
||||
{
|
||||
SystemOperations.COPY => _handlers.OfType<CopyHandler>().FirstOrDefault(),
|
||||
SystemOperations.SPLIT => _handlers.OfType<SplitHandler>().FirstOrDefault(),
|
||||
SystemOperations.DEBUG => _handlers.OfType<DebugHandler>().FirstOrDefault(),
|
||||
SystemOperations.NEW_OBJECT => _handlers.OfType<NewObjectHandler>().FirstOrDefault(),
|
||||
SystemOperations.BEGIN => _handlers.OfType<BeginEndHandler>().FirstOrDefault(),
|
||||
SystemOperations.END => _handlers.OfType<BeginEndHandler>().FirstOrDefault(),
|
||||
SystemOperations.GET_SET when sys.IsSimpleVariable => _handlers.OfType<GetSetVariableHandler>().FirstOrDefault(),
|
||||
SystemOperations.GET_SET => _handlers.OfType<GetSetModelHandler>().FirstOrDefault(),
|
||||
_ => _handlers.OfType<GenericSystemHandler>().FirstOrDefault()
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Shared helpers used by multiple handlers ───
|
||||
|
||||
public static ConnectorViewModel DeserializeConnector(ConnectorData cd, bool isInput)
|
||||
{
|
||||
return new ConnectorViewModel
|
||||
{
|
||||
Title = cd.Title,
|
||||
Shape = ParseShape(cd.Shape),
|
||||
ConnectorColor = Color.FromArgb(cd.ColorArgb),
|
||||
DataType = cd.DataType,
|
||||
IsCopyConnector = cd.IsCopyConnector,
|
||||
IsTakeListConnector = cd.IsTakeListConnector,
|
||||
IsKnotConnector = cd.IsKnotConnector,
|
||||
IsInput = isInput
|
||||
};
|
||||
}
|
||||
|
||||
public static ConnectorShape ParseShape(string shape)
|
||||
{
|
||||
return Enum.TryParse<ConnectorShape>(shape, out var s) ? s : ConnectorShape.Circle;
|
||||
}
|
||||
}
|
||||
}
|
||||
293
Examples/Nodify.Calculator/NodeHandlers/OtherNodeHandlers.cs
Normal file
293
Examples/Nodify.Calculator/NodeHandlers/OtherNodeHandlers.cs
Normal file
@@ -0,0 +1,293 @@
|
||||
using Nodify.Calculator.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace Nodify.Calculator.NodeHandlers
|
||||
{
|
||||
// ─── FUNCTION ───
|
||||
public class FunctionHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "Function";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System && info.sysOp == SystemOperations.FUNCTION;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "Function";
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new FunctionOperationViewModel
|
||||
{
|
||||
Title = info.Title,
|
||||
FunctionName = info.Title ?? "Function"
|
||||
};
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||
op.ConfigureParameters(info.FunctionInputs, info.FunctionOutputs);
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var info = new OperationInfoViewModel
|
||||
{
|
||||
Title = data.FunctionName,
|
||||
Type = OperationType.System,
|
||||
sysOp = SystemOperations.FUNCTION,
|
||||
IsFunction = true
|
||||
};
|
||||
foreach (var inp in data.FunctionInputs)
|
||||
info.FunctionInputs.Add(new FunctionParameterInfo { Name = inp.Name, Type = inp.Type });
|
||||
foreach (var outp in data.FunctionOutputs)
|
||||
info.FunctionOutputs.Add(new FunctionParameterInfo { Name = outp.Name, Type = outp.Type });
|
||||
return Create(info);
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "Function";
|
||||
if (vm is FunctionOperationViewModel func)
|
||||
{
|
||||
data.FunctionName = func.FunctionName;
|
||||
foreach (var p in func.InputParameters)
|
||||
data.FunctionInputs.Add(new FunctionParamData { Name = p.Name, Type = p.Type });
|
||||
foreach (var p in func.OutputParameters)
|
||||
data.FunctionOutputs.Add(new FunctionParamData { Name = p.Name, Type = p.Type });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── API ───
|
||||
public class ApiHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "API";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.API;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "API";
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new APIOperationViewModel
|
||||
{
|
||||
Title = info.Title,
|
||||
OperationType = (info.OPType ?? "GET").ToUpper(),
|
||||
ResponseModelClassName = info.ResponseModelClassName ?? string.Empty
|
||||
};
|
||||
|
||||
// Flow connectors
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||
|
||||
// Response output
|
||||
if (!string.IsNullOrEmpty(info.ResponseModelClassName))
|
||||
{
|
||||
var rc = info.ResponseModelClassName;
|
||||
bool isList = rc.StartsWith("List<") && rc.EndsWith(">");
|
||||
op.Output.Add(new ConnectorViewModel
|
||||
{
|
||||
Title = rc,
|
||||
IsInput = false,
|
||||
Shape = isList ? ConnectorShape.Grid : ConnectorShape.Square,
|
||||
ConnectorColor = isList ? Color.MediumSpringGreen : Color.MediumPurple,
|
||||
DataType = rc
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
op.Output.Add(new ConnectorViewModel
|
||||
{
|
||||
Title = "Response",
|
||||
IsInput = false,
|
||||
Shape = ConnectorShape.Circle,
|
||||
ConnectorColor = Color.LimeGreen,
|
||||
DataType = "object"
|
||||
});
|
||||
}
|
||||
|
||||
// Data inputs
|
||||
foreach (var label in info.Input)
|
||||
{
|
||||
op.Input.Add(new ConnectorViewModel { Title = label, ConnectorColor = Color.LimeGreen });
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var info = new OperationInfoViewModel
|
||||
{
|
||||
Title = data.Title,
|
||||
OPType = data.OPType?.ToLower() ?? "get",
|
||||
Type = OperationType.API,
|
||||
ResponseModelClassName = data.ResponseModelClassName ?? string.Empty
|
||||
};
|
||||
foreach (var ic in data.InputConnectors)
|
||||
{
|
||||
if (ic.Shape != "Triangle")
|
||||
info.Input.Add(ic.Title);
|
||||
}
|
||||
return Create(info);
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "API";
|
||||
if (vm is APIOperationViewModel api)
|
||||
{
|
||||
data.OPType = api.OperationType;
|
||||
data.ResponseModelClassName = api.ResponseModelClassName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── EXPANDO ───
|
||||
public class ExpandoHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "Expando";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.Expando;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "Expando";
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new ExpandoOperationViewModel
|
||||
{
|
||||
MaxInput = info.MaxInput,
|
||||
MinInput = info.MinInput,
|
||||
Title = info.Title,
|
||||
Operation = info.Operation
|
||||
};
|
||||
op.Output.Add(new ConnectorViewModel { ConnectorColor = Color.DodgerBlue });
|
||||
foreach (var label in info.Input)
|
||||
op.Input.Add(new ConnectorViewModel { Title = label, ConnectorColor = Color.DodgerBlue });
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var info = new OperationInfoViewModel
|
||||
{
|
||||
Title = data.Title,
|
||||
Type = OperationType.Expando
|
||||
};
|
||||
foreach (var ic in data.InputConnectors)
|
||||
info.Input.Add(ic.Title);
|
||||
return Create(info);
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "Expando";
|
||||
}
|
||||
}
|
||||
|
||||
// ─── NORMAL (default fallback) ───
|
||||
public class NormalHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "Normal";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.Normal
|
||||
|| info.Type == OperationType.Calculator
|
||||
|| info.Type == OperationType.Expression
|
||||
|| info.Type == OperationType.Group
|
||||
|| info.Type == OperationType.Graph;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "Normal" || data.NodeType == "Calculator";
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
// Delegate to old factory for Expression/Calculator/Group/Graph — these are rarely saved
|
||||
return OperationFactory.GetOperation(info);
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var info = new OperationInfoViewModel
|
||||
{
|
||||
Title = data.Title,
|
||||
Type = data.NodeType == "Calculator" ? OperationType.Calculator : OperationType.Normal
|
||||
};
|
||||
foreach (var ic in data.InputConnectors)
|
||||
info.Input.Add(ic.Title);
|
||||
info.Output.Add("");
|
||||
return OperationFactory.GetOperation(info);
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = vm is CalculatorOperationViewModel ? "Calculator" : "Normal";
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Catch-all for system nodes that don't have a specific handler ───
|
||||
public class GenericSystemHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System";
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
// Fallback: flow node with generic connectors
|
||||
var op = new SystemOperationViewModel
|
||||
{
|
||||
Title = info.Title,
|
||||
SystemOperationType = info.sysOp
|
||||
};
|
||||
if (info.IsFlowNode)
|
||||
{
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||
}
|
||||
foreach (var label in info.Input)
|
||||
op.Input.Add(new ConnectorViewModel { Title = label, ConnectorColor = Color.Cyan });
|
||||
foreach (var label in info.Output)
|
||||
op.Output.Add(new ConnectorViewModel { Title = label, IsInput = false, ConnectorColor = Color.Cyan });
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
if (!System.Enum.TryParse<SystemOperations>(data.SystemOp, out var sysOp))
|
||||
return Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System });
|
||||
|
||||
var info = new OperationInfoViewModel
|
||||
{
|
||||
Title = data.Title,
|
||||
Type = OperationType.System,
|
||||
sysOp = sysOp,
|
||||
IsFlowNode = true
|
||||
};
|
||||
foreach (var ic in data.InputConnectors)
|
||||
{
|
||||
if (ic.Shape != "Triangle") info.Input.Add(ic.Title);
|
||||
}
|
||||
foreach (var oc in data.OutputConnectors)
|
||||
{
|
||||
if (oc.Shape != "Triangle") info.Output.Add(oc.Title);
|
||||
}
|
||||
return Create(info);
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
if (vm is SystemOperationViewModel sys)
|
||||
data.SystemOp = sys.SystemOperationType.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
using Nodify.Calculator.Models;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace Nodify.Calculator.NodeHandlers
|
||||
{
|
||||
// ─── FOREACH ───
|
||||
public class ForEachHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System && info.sysOp == SystemOperations.FOREACH;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.FOREACH);
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new ForEachOperationViewModel { Title = info.Title ?? "ForEach" };
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||
op.Input.Add(new ConnectorViewModel { Title = "List", Shape = ConnectorShape.Grid, ConnectorColor = Color.MediumSpringGreen });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "Loop Body", IsInput = false, Shape = ConnectorShape.Triangle, ConnectorColor = Color.MediumSpringGreen });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "Current Item", IsInput = false, Shape = ConnectorShape.Circle, ConnectorColor = Color.MediumSpringGreen, DataType = "object" });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "Index", IsInput = false, Shape = ConnectorShape.Circle, ConnectorColor = Color.LightSkyBlue, DataType = "int" });
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
=> Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.FOREACH });
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = nameof(SystemOperations.FOREACH);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── ASSERT ───
|
||||
public class AssertHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System && info.sysOp == SystemOperations.ASSERT;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.ASSERT);
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new AssertOperationViewModel { Title = info.Title ?? "Assert" };
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||
op.Input.Add(new ConnectorViewModel { Title = "Actual", ConnectorColor = Color.Gold, Shape = ConnectorShape.Circle });
|
||||
op.Input.Add(new ConnectorViewModel { Title = "Expected", ConnectorColor = Color.Gold, Shape = ConnectorShape.Circle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "Result", IsInput = false, Shape = ConnectorShape.Circle, ConnectorColor = Color.Gold, DataType = "bool" });
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
=> Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.ASSERT });
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = nameof(SystemOperations.ASSERT);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── NEW_OBJECT ───
|
||||
public class NewObjectHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System && info.sysOp == SystemOperations.NEW_OBJECT;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.NEW_OBJECT);
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
{
|
||||
var op = new SystemOperationViewModel
|
||||
{
|
||||
Title = info.Title ?? "New Object",
|
||||
SystemOperationType = SystemOperations.NEW_OBJECT
|
||||
};
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Square, ConnectorColor = Color.MediumPurple });
|
||||
op.Output.Add(new ConnectorViewModel { Title = "Object", IsInput = false, Shape = ConnectorShape.Square, ConnectorColor = Color.MediumPurple, DataType = "object" });
|
||||
return op;
|
||||
}
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var op = (SystemOperationViewModel)Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.NEW_OBJECT });
|
||||
|
||||
// Restore dynamic property inputs (keep triangle + square, replace the rest)
|
||||
var dynamicInputs = op.Input.Where(i => i.Shape != ConnectorShape.Triangle && i.Shape != ConnectorShape.Square).ToList();
|
||||
foreach (var d in dynamicInputs) op.Input.Remove(d);
|
||||
|
||||
foreach (var ic in data.InputConnectors)
|
||||
{
|
||||
if (ic.Shape == "Triangle" || ic.Shape == "Square") continue;
|
||||
op.Input.Add(NodeHandlerRegistry.DeserializeConnector(ic, true));
|
||||
}
|
||||
|
||||
// Restore output connector metadata (Square model output)
|
||||
var savedModelOutput = data.OutputConnectors.FirstOrDefault(o => o.Shape == "Square");
|
||||
var modelOutput = op.Output.FirstOrDefault(o => o.Shape == ConnectorShape.Square);
|
||||
if (savedModelOutput != null && modelOutput != null)
|
||||
{
|
||||
modelOutput.Title = savedModelOutput.Title;
|
||||
modelOutput.DataType = savedModelOutput.DataType;
|
||||
modelOutput.ConnectorColor = Color.FromArgb(savedModelOutput.ColorArgb);
|
||||
}
|
||||
|
||||
op.Title = data.Title;
|
||||
return op;
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = nameof(SystemOperations.NEW_OBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── KNOT ───
|
||||
public class KnotHandler : INodeHandler
|
||||
{
|
||||
public string NodeTypeKey => "System";
|
||||
|
||||
public bool CanCreate(OperationInfoViewModel info)
|
||||
=> info.Type == OperationType.System && info.sysOp == SystemOperations.KNOT;
|
||||
|
||||
public bool CanRestore(NodeData data)
|
||||
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.KNOT);
|
||||
|
||||
public OperationViewModel Create(OperationInfoViewModel info)
|
||||
=> new KnotOperationViewModel();
|
||||
|
||||
public OperationViewModel Restore(NodeData data)
|
||||
{
|
||||
var op = new KnotOperationViewModel();
|
||||
op.Input.Clear();
|
||||
op.Output.Clear();
|
||||
foreach (var ic in data.InputConnectors)
|
||||
{
|
||||
var conn = NodeHandlerRegistry.DeserializeConnector(ic, true);
|
||||
conn.IsKnotConnector = true;
|
||||
op.Input.Add(conn);
|
||||
}
|
||||
foreach (var oc in data.OutputConnectors)
|
||||
{
|
||||
var conn = NodeHandlerRegistry.DeserializeConnector(oc, false);
|
||||
conn.IsKnotConnector = true;
|
||||
op.Output.Add(conn);
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
public void Save(OperationViewModel vm, NodeData data)
|
||||
{
|
||||
data.NodeType = "System";
|
||||
data.SystemOp = nameof(SystemOperations.KNOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user