Skip to content

Commit 168eb05

Browse files
๐Ÿงฉ Refactor(Blueprint): ้‡ๆž„่“ๅ›พ่Š‚็‚นๅค„็†้€ป่พ‘๏ผŒๆ”ฏๆŒๅ†…็ฝฎๅ‡ฝๆ•ฐ็š„้‡ๅ‘ฝๅๅ’Œ้ขœ่‰ฒๅˆ†็ฑป
1 parent 2c4135a commit 168eb05

4 files changed

Lines changed: 134 additions & 54 deletions

File tree

โ€ŽKitX Dashboard/ViewModels/BlueprintEditorViewModel.csโ€Ž

Lines changed: 111 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -538,15 +538,15 @@ private async Task RenameSelectedNodeAsync(BlueprintNodeVM nodeVm)
538538
: nodeVm.VarName;
539539
break;
540540

541-
case BlueprintNodeType.Get:
541+
case BlueprintNodeType.BuiltinFunction when nodeVm.BuiltinFunctionName == "Get":
542542
dialogTitle = ViewModelBase.TranslateTextWithSuffix("Blueprint", "RenameGetNode") ?? "Rename Get Node";
543543
dialogPrompt = ViewModelBase.TranslateTextWithSuffix("Blueprint", "RenameVariablePrompt") ?? "Enter new variable name:";
544544
currentName = nodeVm.DisplayTitle.StartsWith("Get:")
545545
? nodeVm.DisplayTitle["Get:".Length..].Trim()
546546
: nodeVm.DisplayTitle;
547547
break;
548548

549-
case BlueprintNodeType.Set:
549+
case BlueprintNodeType.BuiltinFunction when nodeVm.BuiltinFunctionName == "Set":
550550
dialogTitle = ViewModelBase.TranslateTextWithSuffix("Blueprint", "RenameSetNode") ?? "Rename Set Node";
551551
dialogPrompt = ViewModelBase.TranslateTextWithSuffix("Blueprint", "RenameVariablePrompt") ?? "Enter new variable name:";
552552
currentName = nodeVm.DisplayTitle.StartsWith("Set:")
@@ -578,12 +578,12 @@ private async Task RenameSelectedNodeAsync(BlueprintNodeVM nodeVm)
578578
PropagateVariableRename(oldVarName, newName);
579579
break;
580580

581-
case BlueprintNodeType.Get:
581+
case BlueprintNodeType.BuiltinFunction when nodeVm.BuiltinFunctionName == "Get":
582582
nodeVm.DisplayTitle = $"Get: {newName}";
583583
nodeVm.Metadata["VarName"] = newName;
584584
break;
585585

586-
case BlueprintNodeType.Set:
586+
case BlueprintNodeType.BuiltinFunction when nodeVm.BuiltinFunctionName == "Set":
587587
nodeVm.DisplayTitle = $"Set: {newName}";
588588
nodeVm.Metadata["VarName"] = newName;
589589
break;
@@ -601,10 +601,11 @@ private void PropagateVariableRename(string oldName, string newName)
601601
{
602602
foreach (var n in Nodes.OfType<BlueprintNodeVM>())
603603
{
604-
if (n.NodeType is not (BlueprintNodeType.Get or BlueprintNodeType.Set))
604+
if (n.NodeType != BlueprintNodeType.BuiltinFunction
605+
|| (n.BuiltinFunctionName != "Get" && n.BuiltinFunctionName != "Set"))
605606
continue;
606607

607-
var prefix = n.NodeType == BlueprintNodeType.Get ? "Get: " : "Set: ";
608+
var prefix = n.BuiltinFunctionName == "Get" ? "Get: " : "Set: ";
608609
var currentRef = n.DisplayTitle.StartsWith(prefix)
609610
? n.DisplayTitle[prefix.Length..].Trim()
610611
: "";
@@ -1009,8 +1010,27 @@ private BlueprintNodeVM ConvertBlueprintNodeToViewModel(BlueprintNode blueprintN
10091010

10101011
// Preserve BuiltinFunctionNode metadata for round-trip
10111012
if (blueprintNode is BuiltinFunctionNode bfNode && !string.IsNullOrEmpty(bfNode.FunctionName))
1013+
{
1014+
nodeVm.BuiltinFunctionName = bfNode.FunctionName;
10121015
nodeVm.Metadata["BuiltinFunctionName"] = bfNode.FunctionName;
10131016

1017+
// For Get/Set, build display title from VarName pin's default value
1018+
if (bfNode.FunctionName is "Get" or "Set")
1019+
{
1020+
var varPin = bfNode.InputPins.FirstOrDefault(p => p.Name == "VarName");
1021+
var varName = varPin?.DefaultValue;
1022+
if (!string.IsNullOrEmpty(varName))
1023+
{
1024+
nodeVm.DisplayTitle = $"{bfNode.FunctionName}: {varName}";
1025+
nodeVm.Title = nodeVm.DisplayTitle;
1026+
// Use function-specific colors
1027+
var (pc, lc) = BlueprintNodeVM.GetBuiltinFunctionColors(bfNode.FunctionName);
1028+
nodeVm.CategoryColor = pc;
1029+
nodeVm.CategoryColorLight = lc;
1030+
}
1031+
}
1032+
}
1033+
10141034
// Preserve PluginTriggerNode metadata for round-trip
10151035
if (blueprintNode is PluginTriggerNode ptNode)
10161036
{
@@ -1210,8 +1230,19 @@ private void BuildBlockScopesFromScopeBlocks(Blueprint blueprint)
12101230
/// </summary>
12111231
private BlueprintNode ConvertViewModelToBlueprintNode(BlueprintNodeVM nodeVm)
12121232
{
1213-
// Use NodeType from VM directly (more reliable than name-based inference)
1214-
var blueprintNode = _nodeRegistry.Create(nodeVm.NodeType);
1233+
// Use CreateBuiltinFunctionNode for builtin function nodes to get proper pins
1234+
BlueprintNode blueprintNode;
1235+
if (nodeVm.NodeType == BlueprintNodeType.BuiltinFunction
1236+
&& nodeVm.Metadata.TryGetValue("BuiltinFunctionName", out var funcName)
1237+
&& !string.IsNullOrEmpty(funcName)
1238+
&& funcName is "Get" or "Set" or "Print" or "Pause" or "Branch" or "Loop" or "Break" or "ToLoopCond")
1239+
{
1240+
blueprintNode = _nodeRegistry.CreateBuiltinFunctionNode(funcName);
1241+
}
1242+
else
1243+
{
1244+
blueprintNode = _nodeRegistry.Create(nodeVm.NodeType);
1245+
}
12151246

12161247
// Preserve original node ID so connections can reference it
12171248
blueprintNode.Id = nodeVm.BlueprintNodeId;
@@ -1230,14 +1261,6 @@ private BlueprintNode ConvertViewModelToBlueprintNode(BlueprintNodeVM nodeVm)
12301261
vNode.VarType = nodeVm.VarType;
12311262
}
12321263

1233-
// Special handling: BuiltinFunctionNode โ†’ restore FunctionName from Metadata
1234-
if (blueprintNode is BuiltinFunctionNode bfNode
1235-
&& nodeVm.Metadata.TryGetValue("BuiltinFunctionName", out var funcName)
1236-
&& !string.IsNullOrEmpty(funcName))
1237-
{
1238-
bfNode.FunctionName = funcName;
1239-
}
1240-
12411264
// Special handling: PluginTriggerNode โ†’ restore PluginName/TriggerName from Metadata
12421265
if (blueprintNode is PluginTriggerNode ptNode)
12431266
{
@@ -1331,21 +1354,19 @@ private void ApplyDisplayTitleToNode(BlueprintNode node, string title, Blueprint
13311354
case CallHelperNode helperNode when title.StartsWith("Helper:"):
13321355
helperNode.HelperFunctionName = title["Helper:".Length..].Trim();
13331356
break;
1334-
case GetNode getNode when title.StartsWith("Get:"):
1335-
getNode.VarName = title["Get:".Length..].Trim();
1336-
// Re-resolve pin type when VarName changes
1357+
case BuiltinFunctionNode bfn when title.StartsWith("Get:"):
1358+
bfn.Properties["VarName"] = title["Get:".Length..].Trim();
13371359
if (nodeVm != null)
13381360
{
1339-
var pinType = ResolveVariablePinType(getNode.VarName);
1361+
var pinType = ResolveVariablePinType(bfn.Properties["VarName"]);
13401362
UpdateNodeValuePinType(nodeVm, pinType);
13411363
}
13421364
break;
1343-
case SetNode setNode when title.StartsWith("Set:"):
1344-
setNode.VarName = title["Set:".Length..].Trim();
1345-
// Re-resolve pin type when VarName changes
1365+
case BuiltinFunctionNode bfn2 when title.StartsWith("Set:"):
1366+
bfn2.Properties["VarName"] = title["Set:".Length..].Trim();
13461367
if (nodeVm != null)
13471368
{
1348-
var pinType = ResolveVariablePinType(setNode.VarName);
1369+
var pinType = ResolveVariablePinType(bfn2.Properties["VarName"]);
13491370
UpdateNodeValuePinType(nodeVm, pinType);
13501371
}
13511372
break;
@@ -1435,7 +1456,8 @@ private void PropagateTypeToGetSetNodes(string varName, PinType pinType)
14351456

14361457
foreach (var node in Nodes.OfType<BlueprintNodeVM>())
14371458
{
1438-
if (node.NodeType is not (BlueprintNodeType.Get or BlueprintNodeType.Set)) continue;
1459+
if (node.NodeType != BlueprintNodeType.BuiltinFunction
1460+
|| (node.BuiltinFunctionName != "Get" && node.BuiltinFunctionName != "Set")) continue;
14391461

14401462
// Extract VarName from display title ("Get: myVar" or "Set: myVar")
14411463
var nodeVarName = node.DisplayTitle.Contains(':')
@@ -1456,7 +1478,7 @@ private void UpdateNodeValuePinType(BlueprintNodeVM node, PinType pinType)
14561478
{
14571479
// For GetNode: Value is an output connector
14581480
// For SetNode: Value is an input connector
1459-
var connectors = node.NodeType == BlueprintNodeType.Get
1481+
var connectors = node.BuiltinFunctionName == "Get"
14601482
? node.Output.OfType<BlueprintConnectorVM>()
14611483
: node.Input.OfType<BlueprintConnectorVM>();
14621484

@@ -1506,7 +1528,8 @@ private void ResolveAllGetSetPinTypes()
15061528
{
15071529
foreach (var node in Nodes.OfType<BlueprintNodeVM>())
15081530
{
1509-
if (node.NodeType is not (BlueprintNodeType.Get or BlueprintNodeType.Set)) continue;
1531+
if (node.NodeType != BlueprintNodeType.BuiltinFunction
1532+
|| (node.BuiltinFunctionName != "Get" && node.BuiltinFunctionName != "Set")) continue;
15101533

15111534
var varName = node.DisplayTitle.Contains(':')
15121535
? node.DisplayTitle[(node.DisplayTitle.IndexOf(':') + 1)..].Trim()
@@ -1620,34 +1643,80 @@ private void RefreshCounts()
16201643
[RelayCommand]
16211644
public void AddEntryNode() => AddNodeFromTemplate(BlueprintNodeType.Entry);
16221645

1646+
/// <summary>
1647+
/// Creates a builtin function node from the registry with proper descriptor and UI setup.
1648+
/// </summary>
1649+
private void AddBuiltinFunctionNode(string functionName)
1650+
{
1651+
var builtinNode = _nodeRegistry.CreateBuiltinFunctionNode(functionName);
1652+
var descriptor = builtinNode.GetDescriptor();
1653+
var title = $"{(functionName == "Get" ? "Get: " : functionName == "Set" ? "Set: " : "")}{functionName}";
1654+
var (primaryColor, lightColor) = BlueprintNodeVM.GetBuiltinFunctionColors(functionName);
1655+
1656+
var node = new BlueprintNodeVM
1657+
{
1658+
Location = new Avalonia.Point(100, 100),
1659+
BlueprintNodeId = Guid.NewGuid().ToString(),
1660+
NodeType = BlueprintNodeType.BuiltinFunction,
1661+
BuiltinFunctionName = functionName,
1662+
DisplayTitle = title,
1663+
CategoryColor = primaryColor,
1664+
CategoryColorLight = lightColor,
1665+
Title = title,
1666+
Name = functionName,
1667+
Input = new ObservableCollection<object>(),
1668+
Output = new ObservableCollection<object>()
1669+
};
1670+
1671+
foreach (var pinDesc in descriptor.InputPins)
1672+
{
1673+
var pinId = Guid.NewGuid().ToString();
1674+
node.Input.Add(new BlueprintConnectorVM
1675+
{
1676+
Title = pinDesc.Name,
1677+
Flow = ConnectorViewModelBase.ConnectorFlow.Input,
1678+
PinType = pinDesc.Type,
1679+
OriginalPinId = pinId
1680+
});
1681+
}
1682+
1683+
foreach (var pinDesc in descriptor.OutputPins)
1684+
{
1685+
var pinId = Guid.NewGuid().ToString();
1686+
node.Output.Add(new BlueprintConnectorVM
1687+
{
1688+
Title = pinDesc.Name,
1689+
Flow = ConnectorViewModelBase.ConnectorFlow.Output,
1690+
PinType = pinDesc.Type,
1691+
OriginalPinId = pinId
1692+
});
1693+
}
1694+
1695+
Nodes.Add(node);
1696+
RefreshCounts();
1697+
Log.Information("Added BuiltinFunction node: {FunctionName}", functionName);
1698+
}
1699+
16231700
[RelayCommand]
16241701
public void AddBranchNode()
16251702
{
1626-
AddNodeFromTemplate(BlueprintNodeType.Branch);
1703+
AddBuiltinFunctionNode("Branch");
16271704
var branchNode = Nodes.OfType<BlueprintNodeVM>().Last();
1628-
1629-
// Create True scope block
16301705
CreateScopeBlockForNode(branchNode, "True");
1631-
1632-
// Create False scope block
16331706
CreateScopeBlockForNode(branchNode, "False");
16341707
}
16351708

16361709
[RelayCommand]
16371710
public void AddLoopNode()
16381711
{
1639-
AddNodeFromTemplate(BlueprintNodeType.Loop);
1712+
AddBuiltinFunctionNode("Loop");
16401713
var loopNode = Nodes.OfType<BlueprintNodeVM>().Last();
1641-
1642-
// Create LoopBody scope block
16431714
CreateScopeBlockForNode(loopNode, "LoopBody");
1644-
1645-
// Create LoopEnd scope block
16461715
CreateScopeBlockForNode(loopNode, "LoopEnd");
16471716
}
16481717

16491718
[RelayCommand]
1650-
public void AddBreakNode() => AddNodeFromTemplate(BlueprintNodeType.Break);
1719+
public void AddBreakNode() => AddBuiltinFunctionNode("Break");
16511720

16521721
[RelayCommand]
16531722
public void AddConstNode()
@@ -1889,10 +1958,10 @@ private void AddHelperCallNode(HelperFunctionPaletteItem item)
18891958
}
18901959

18911960
[RelayCommand]
1892-
public void AddPrintNode() => AddNodeFromTemplate(BlueprintNodeType.Print);
1961+
public void AddPrintNode() => AddBuiltinFunctionNode("Print");
18931962

18941963
[RelayCommand]
1895-
public void AddPauseNode() => AddNodeFromTemplate(BlueprintNodeType.Pause);
1964+
public void AddPauseNode() => AddBuiltinFunctionNode("Pause");
18961965

18971966
// โ”€โ”€โ”€ Blueprint Commands โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
18981967

@@ -2270,8 +2339,8 @@ public async Task LoadBlueprintAsync(string filePath)
22702339
}
22712340
catch (Exception ex)
22722341
{
2273-
StatusText = $"Load error: {ex.Message}";
2274-
Log.Error(ex, "Blueprint load error");
2342+
Log.Error(ex, "Failed to load blueprint from {FilePath}", filePath);
2343+
StatusText = "Failed to load file";
22752344
}
22762345
}
22772346

โ€ŽKitX Dashboard/ViewModels/BlueprintNodeVM.csโ€Ž

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ public partial class BlueprintNodeVM : NodeViewModelBase
5858
/// <summary>Whether this node should show the VariableType selector (only Variable nodes)</summary>
5959
public bool ShowVarTypeSelector => NodeType == BlueprintNodeType.Variable;
6060

61+
/// <summary>
62+
/// Builtin function name, if this node is a BuiltinFunction node.
63+
/// Used for logic that previously checked specific BlueprintNodeType values.
64+
/// </summary>
65+
public string? BuiltinFunctionName { get; set; }
66+
6167
/// <summary>
6268
/// Variable type for Variable nodes. Bound to a ComboBox in the node body.
6369
/// Changing this propagates the type to all Get/Set nodes referencing this variable.
@@ -187,13 +193,18 @@ protected override void OnPropertyChanged(System.ComponentModel.PropertyChangedE
187193
public static (string Primary, string Light) GetCategoryColors(BlueprintNodeType type) => type switch
188194
{
189195
BlueprintNodeType.Entry or BlueprintNodeType.PluginTrigger => ("#4CAF50", "#2E7D32"), // Green
190-
BlueprintNodeType.Branch or BlueprintNodeType.Loop
191-
or BlueprintNodeType.Break => ("#FF9800", "#BF6E00"), // Orange
192-
BlueprintNodeType.Const or BlueprintNodeType.Get
193-
or BlueprintNodeType.Set => ("#2196F3", "#1565C0"), // Blue
194-
BlueprintNodeType.Variable => ("#009688", "#00796B"), // Teal
195-
BlueprintNodeType.Call or BlueprintNodeType.CallHelper
196-
or BlueprintNodeType.Print or BlueprintNodeType.Pause => ("#9C27B0", "#7B1FA2"), // Purple
197-
_ => ("#607D8B", "#455A64") // Gray fallback
196+
BlueprintNodeType.Const => ("#2196F3", "#1565C0"), // Blue
197+
BlueprintNodeType.Variable => ("#009688", "#00796B"), // Teal
198+
BlueprintNodeType.Call or BlueprintNodeType.CallHelper => ("#9C27B0", "#7B1FA2"), // Purple
199+
BlueprintNodeType.BuiltinFunction => ("#FF9800", "#BF6E00"), // Orange
200+
_ => ("#607D8B", "#455A64") // Gray fallback
201+
};
202+
203+
/// <summary>Returns (Primary, Light) hex color pair based on builtin function name</summary>
204+
public static (string Primary, string Light) GetBuiltinFunctionColors(string functionName) => functionName switch
205+
{
206+
"Print" or "Pause" => ("#9C27B0", "#7B1FA2"), // Purple - I/O
207+
"Get" or "Set" => ("#2196F3", "#1565C0"), // Blue - data
208+
_ => ("#FF9800", "#BF6E00") // Orange - control flow
198209
};
199210
}

โ€ŽKitX Dashboard/Views/BlueprintEditorWindow.axaml.csโ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ private void OnEditorContextRequested(object? sender, ContextRequestedEventArgs
140140
// Rename option for Const / Variable / Get / Set nodes
141141
if (nodeVm.NodeType is BlueprintNodeType.Const
142142
or BlueprintNodeType.Variable
143-
or BlueprintNodeType.Get
144-
or BlueprintNodeType.Set)
143+
|| (nodeVm.NodeType == BlueprintNodeType.BuiltinFunction
144+
&& nodeVm.BuiltinFunctionName is "Get" or "Set"))
145145
{
146146
nodePanel.Children.Add(CreateSeparator());
147147
nodePanel.Children.Add(CreateMenuButton("Rename", _viewModel.RenameSelectedNodeCommand, nodeVm));

โ€ŽKitX Dashboard/Views/WorkflowEditorWindow.axaml.csโ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,8 @@ private void OnEditorContextRequested(object? sender, ContextRequestedEventArgs
601601

602602
if (nodeVm.NodeType is BlueprintNodeType.Const
603603
or BlueprintNodeType.Variable
604-
or BlueprintNodeType.Get
605-
or BlueprintNodeType.Set)
604+
|| (nodeVm.NodeType == BlueprintNodeType.BuiltinFunction
605+
&& nodeVm.BuiltinFunctionName is "Get" or "Set"))
606606
{
607607
nodePanel.Children.Add(CreateSeparator());
608608
nodePanel.Children.Add(CreateMenuButton(

0 commit comments

Comments
ย (0)