29#include "../system/system_utils.h"
30#include "../system/system_consts.h"
32#include <unordered_map>
33#include "../NodeGraphCore/GlobalTemplateBlackboard.h"
35#include "../third_party/imgui/imgui.h"
36#include "../third_party/imnodes/imnodes.h"
37#include "../json_helper.h"
38#include "../TaskSystem/TaskGraphLoader.h"
48#include <unordered_set>
57 TaskNodeDefinition& def)
64 ImGui::Selectable(def.NodeName.c_str(),
true,
66 ImGui::PopStyleColor(4);
114 if (ImGui::Checkbox(
"Breakpoint (F9)##vsbp_branch", &
hasBP))
131 TaskNodeDefinition& def)
138 ImGui::Selectable(def.NodeName.c_str(),
true,
140 ImGui::PopStyleColor(4);
215 ImGui::Selectable(def.
NodeName.c_str(),
true,
217 ImGui::PopStyleColor(4);
232 ImGui::SetNextItemWidth(-1.0f);
233 if (ImGui::BeginCombo(
"Switch On##switch_var_combo",
previewVar))
238 if (ImGui::Selectable(
var.displayLabel.c_str(), selected))
266 ImGui::SetItemDefaultFocus();
277 if (ImGui::Button(
"Edit Switch Cases",
ImVec2(150, 0)))
330 if (ImGui::Checkbox(
"Breakpoint (F9)##vsbp_switch", &
hasBP))
353 for (
const auto&
paramPair : def.Parameters)
363 ImGui::TextColored(
ImVec4(0.7f, 0.9f, 1.0f, 1.0f),
"Node Parameters:");
367 ImGui::TextDisabled(
"(no user parameters - add one below)");
382 ImGui::TextColored(
ImVec4(0.8f, 0.95f, 1.0f, 1.0f),
"%s",
paramName.c_str());
404 if (!
binding.LiteralValue.IsNone())
411 ImGui::SetNextItemWidth(-1.0f);
415 std::string strVal(
buf);
416 binding.LiteralValue = TaskValue(strVal);
433 BBVariableRegistry
bbReg;
435 const std::vector<VarSpec>
vars =
bbReg.GetAllVariables();
438 ImGui::SetNextItemWidth(-1.0f);
443 bool selected = (
var.name ==
binding.VariableName);
444 if (ImGui::Selectable(
var.displayLabel.c_str(), selected))
460 ImGui::SetItemDefaultFocus();
470 ImGui::SetNextItemWidth(-1.0f);
493 ImGui::TextColored(
ImVec4(0.7f, 0.9f, 1.0f, 1.0f),
"Add Parameter:");
496 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 80.0f);
499 if (ImGui::Button(
"Add",
ImVec2(70.0f, 0.0f)))
562 ImGui::TextDisabled(
"ForEach Loop Configuration");
566 static char nodeName[256] =
"";
568 sizeof(nodeName) - 1);
570 if (ImGui::InputText(
"##foreach_name", nodeName,
sizeof(nodeName)))
577 ImGui::TextDisabled(
"Loop Configuration");
581 ImGui::TextDisabled(
"Suggested List Variables:");
582 ImGui::BeginChild(
"##foreach_bb_list",
ImVec2(0, 100),
true);
590 ImGui::TextDisabled(
"%s (List)",
entry.Key.c_str());
595 ImGui::TextDisabled(
"(ForEach node specific parameters pending implementation)");
624 ImGui::TextDisabled(
"SubGraph File");
649 std::string currentPath =
pathBinding->LiteralValue.to_string();
662 ImGui::SetNextItemWidth(-80.0f);
665 if (
pathChanged || ImGui::IsItemDeactivatedAfterEdit())
719 SYSTEM_LOG <<
"[RenderSubGraphNodeProperties] Updated SubGraphPath for node "
732 if (ImGui::Button(
"Browse##subgraph_browse",
ImVec2(75, 0)))
793 SYSTEM_LOG <<
"[RenderSubGraphNodeProperties] Synchronized SubGraphPath to editor node: "
806 if (
nodePtr->SubGraphPath.empty())
808 ImGui::TextColored(
ImVec4(1.0f, 0.5f, 0.3f, 1.0f),
809 "⚠ SubGraph path is empty - set a valid .ats file");
813 ImGui::TextDisabled(
"Path: %s",
nodePtr->SubGraphPath.c_str());
825 ImGui::TextDisabled(
"Input Parameters");
829 if (!
nodePtr->InputParams.empty())
831 ImGui::BeginChild(
"##subgraph_params",
ImVec2(0, 200),
true);
836 for (
auto it =
nodePtr->InputParams.begin();
839 ImGui::PushID(
static_cast<int>(
paramIdx));
845 ImGui::TextColored(
ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
"%s",
paramName.c_str());
846 ImGui::SameLine(150.0f);
849 const char*
bindingTypes[] = {
"Literal",
"LocalVariable" };
852 ImGui::SetNextItemWidth(100.0f);
869 ImGui::SetNextItemWidth(120.0f);
885 ImGui::SetNextItemWidth(120.0f);
893 ImGui::SetNextItemWidth(120.0f);
894 if (ImGui::BeginCombo(
"##var_hint",
"(suggestions)"))
899 if (ImGui::Selectable(
bbEntry.Key.c_str()))
911 if (ImGui::Button(
"X##del_param",
ImVec2(25, 0)))
931 ImGui::TextDisabled(
"(no input parameters - check SubGraph file)");
937 if (ImGui::Button(
"+##add_param",
ImVec2(25, 0)))
956 ImGui::TextDisabled(
"Add Parameter");
966 ImGui::TextDisabled(
"Output Parameters (Return Values)");
970 if (!
nodePtr->OutputParams.empty())
972 ImGui::BeginChild(
"##subgraph_outputs",
ImVec2(0, 150),
true);
977 for (
auto it =
nodePtr->OutputParams.begin();
980 ImGui::PushID(
static_cast<int>(1000 +
outIdx));
983 std::string&
bbKey =
it->second;
986 ImGui::TextColored(
ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
"%s",
outputName.c_str());
987 ImGui::SameLine(150.0f);
995 ImGui::SetNextItemWidth(120.0f);
1004 ImGui::SetNextItemWidth(120.0f);
1005 if (ImGui::BeginCombo(
"##out_hint",
"(suggestions)"))
1010 if (ImGui::Selectable(
bbEntry.Key.c_str()))
1021 if (ImGui::Button(
"X##del_output",
ImVec2(25, 0)))
1041 ImGui::TextDisabled(
"(no output parameters - check SubGraph file)");
1055 ImGui::TextDisabled(
"Properties");
1059 ImGui::TextDisabled(
"(select a node)");
1064 VSEditorNode*
eNode =
nullptr;
1073 if (
eNode ==
nullptr)
1076 TaskNodeDefinition& def =
eNode->def;
1101 if (ImGui::IsItemActivated())
1106 if (ImGui::IsItemDeactivatedAfterEdit() &&
1111 std::unique_ptr<ICommand>(
new EditNodePropertyCommand(
1127 const std::string&
currentTask = def.AtomicTaskID;
1130 if (ImGui::IsItemActivated())
1136 if (ImGui::BeginCombo(
"TaskType##vstask",
previewLabel))
1144 for (
size_t ti = 0;
ti < tasks.size(); ++
ti)
1146 const TaskSpec&
spec = tasks[
ti];
1152 ImGui::TextDisabled(
"%s",
spec.category.c_str());
1156 std::string label =
" " +
spec.displayName +
"##" +
spec.id;
1157 if (ImGui::Selectable(label.c_str(), selected))
1159 const std::string
oldTaskID = def.AtomicTaskID;
1160 def.AtomicTaskID =
spec.id;
1162 def.NodeName =
spec.displayName;
1175 std::unique_ptr<ICommand>(
new EditNodePropertyCommand(
1184 ImGui::SetItemDefaultFocus();
1186 if (ImGui::IsItemHovered() && !
spec.description.empty())
1188 ImGui::BeginTooltip();
1189 ImGui::TextUnformatted(
spec.description.c_str());
1190 ImGui::EndTooltip();
1199 float delay = def.DelaySeconds;
1200 if (ImGui::InputFloat(
"Delay (s)##vsdelay", &
delay, 0.1f, 1.0f))
1202 def.DelaySeconds =
delay;
1213 if (ImGui::IsItemActivated())
1218 if (ImGui::IsItemDeactivatedAfterEdit() &&
1223 std::unique_ptr<ICommand>(
new EditNodePropertyCommand(
1245 const std::string
oldKey = def.BBKey;
1260 std::unique_ptr<ICommand>(
new EditNodePropertyCommand(
1288 const std::string
oldKey = def.BBKey;
1303 std::unique_ptr<ICommand>(
new EditNodePropertyCommand(
1352 TaskNodeDefinition*
tmplNode =
nullptr;
1366 BBVariableRegistry
bbReg;
1369 const std::string&
curVar = def.switchVariable;
1372 if (ImGui::BeginCombo(
"Switch Var##vsswitchvar",
previewVar))
1377 bool selected = (
v.name ==
curVar);
1378 if (ImGui::Selectable(
v.displayLabel.c_str(), selected))
1380 def.switchVariable =
v.name;
1382 tmplNode->switchVariable = def.switchVariable;
1386 ImGui::SetItemDefaultFocus();
1394 ImGui::Text(
"Cases: %zu", def.switchCases.size());
1395 if (ImGui::Button(
"Edit Cases##vseditswitch",
ImVec2(100, 0)))
1414 tmplNode->switchCases = def.switchCases;
1422 if (!def.switchCases.empty())
1425 ImGui::TextDisabled(
"Current Cases (read-only)");
1426 for (
size_t ci = 0;
ci < def.switchCases.size(); ++
ci)
1428 const std::string
pinLabel = def.switchCases[
ci].pinName
1429 +
" (val=" + def.switchCases[
ci].value +
")"
1430 + (def.switchCases[
ci].customLabel.empty() ?
"" :
" [" + def.switchCases[
ci].customLabel +
"]");
1431 ImGui::BulletText(
"%s",
pinLabel.c_str());
1449 if (ImGui::Checkbox(
"Breakpoint (F9)##vsbp", &
hasBP))
1469 if (ImGui::BeginTabItem(
"Properties"))
1472 ImGui::EndTabItem();
1476 if (ImGui::BeginTabItem(
"Nodes"))
1479 ImGui::EndTabItem();
1488 ImGui::TextDisabled(
"Node Properties");
1492 ImGui::TextDisabled(
"(select a node)");
1506 if (
eNode ==
nullptr)
1516 if (ImGui::InputText(
"Name##nodeprops_name",
nameBuf,
sizeof(
nameBuf)))
1549 ImGui::SetNextItemWidth(-1.0f);
1550 if (ImGui::BeginCombo(
"Task##nodeprops_task",
previewLabel))
1552 for (
const auto&
spec : tasks)
1555 if (ImGui::Selectable(
spec.displayName.c_str(), selected))
1572 ImGui::SetItemDefaultFocus();
1584 ImGui::TextColored(
ImVec4(0.7f, 0.9f, 1.0f, 1.0f),
"Parameters:");
1588 ImGui::PushID(
param.name.c_str());
1591 std::string label =
param.name +
" (" +
param.type +
")";
1602 ImGui::TextColored(
ImVec4(0.8f, 0.95f, 1.0f, 1.0f),
"%s",
param.name.c_str());
1606 ImGui::TextDisabled(
"(?)");
1609 if (ImGui::IsItemHovered() && !
param.description.empty())
1611 ImGui::BeginTooltip();
1612 ImGui::TextWrapped(
"%s",
param.description.c_str());
1614 ImGui::TextDisabled(
"Type: %s",
param.type.c_str());
1615 ImGui::TextDisabled(
"Default: %s",
param.defaultValue.c_str());
1616 ImGui::EndTooltip();
1620 if (!
param.description.empty())
1622 ImGui::TextDisabled(
"%s",
param.description.c_str());
1625 if (
param.type ==
"Bool")
1628 ImGui::SetNextItemWidth(-1.0f);
1629 if (ImGui::Checkbox((
"##" +
param.name +
"_input").c_str(), &value))
1647 else if (
param.type ==
"Int")
1650 try { value = std::stoi(
currentValue); }
catch (...) {}
1651 ImGui::SetNextItemWidth(-1.0f);
1652 if (ImGui::InputInt((
"##" +
param.name +
"_input").c_str(), &value))
1670 else if (
param.type ==
"Float")
1673 try { value = std::stof(
currentValue); }
catch (...) {}
1674 ImGui::SetNextItemWidth(-1.0f);
1675 if (ImGui::InputFloat((
"##" +
param.name +
"_input").c_str(), &value, 0.1f))
1693 else if (
param.type ==
"String")
1695 static char buffer[512] = {0};
1699 ImGui::SetNextItemWidth(-1.0f);
1700 if (ImGui::InputText((
"##" +
param.name +
"_input").c_str(),
buffer,
sizeof(
buffer)))
1730 if (ImGui::InputFloat(
"Delay (s)##nodeprops_delay", &
delay, 0.1f, 1.0f))
1757 ImGui::TextColored(
ImVec4(1.0f, 0.85f, 0.0f, 1.0f),
"%s Blackboard Value", nodeType);
1763 const std::vector<VarSpec>
allVars =
bbReg.GetAllVariables();
1767 ImGui::SetNextItemWidth(-1.0f);
1768 if (ImGui::BeginCombo(
"Blackboard Variable##bbkey_combo",
previewLabel))
1772 bool selected = (
var.name == def.
BBKey);
1773 if (ImGui::Selectable(
var.displayLabel.c_str(), selected))
1801 ImGui::SetItemDefaultFocus();
1810 ImGui::TextColored(
ImVec4(0.7f, 0.9f, 1.0f, 1.0f),
"Parameters:");
1819 ImGui::TextColored(
ImVec4(1.0f, 0.85f, 0.0f, 1.0f),
"Math Operation");
1823 static const char*
operators[] = {
"+",
"-",
"*",
"/",
"%",
"^" };
1828 for (
int i = 0;
i < 6; ++
i)
1838 ImGui::SetNextItemWidth(-1.0f);
1855 ImGui::TextColored(
ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
"Operation:");
1877 ImGui::TextColored(
ImVec4(0.4f, 1.0f, 0.5f, 1.0f),
1887 ImGui::TextColored(
ImVec4(0.7f, 0.9f, 1.0f, 1.0f),
"Custom Parameters:");
1919 ImGui::TextDisabled(
"Control flow node");
1924 ImGui::TextDisabled(
"(type-specific properties)");
1972 if (ImGui::Checkbox(
"Breakpoint (F9)##nodeprops_bp", &
hasBP))
1982 ImGui::TextColored(
ImVec4(0.4f, 0.8f, 0.4f, 1.0f),
"Drag nodes to the graph to add them");
1987 ImGui::SetNextItemWidth(-1.0f);
1995 const char* description;
2034 {
"Flow Control", 1 },
2036 {
"Blackboard", 3 },
2037 {
"Math & Logic", 4 },
2040 const int numCategories =
sizeof(categories) /
sizeof(categories[0]);
2067 ImGui::PushFont(ImGui::GetIO().
Fonts->Fonts[0]);
2092 ImGui::PopStyleVar();
2103 if (
nodeInfo.category != category.categoryIndex)
2111 ImGui::Indent(10.0f);
2112 bool selected =
false;
2123 ImGui::Text(
"Node: %s",
nodeInfo.name);
2124 ImGui::EndDragDropSource();
2130 ImGui::SetTooltip(
"%s",
nodeInfo.description);
2133 ImGui::Unindent(10.0f);
2135 ImGui::PopStyleVar();
2144 ImGui::TextWrapped(
"Tip: Drag & drop nodes onto the graph canvas");
2145 ImGui::PopStyleColor();
UI-side registry of available atomic tasks with display metadata.
Wrapper around the graph blackboard entries for dropdown editors.
Registry of available condition types for Branch/While node dropdowns.
Runtime debug controller for ATS Visual Scripting (Phase 5).
ComponentTypeID GetComponentTypeID_Static()
Defines MathOpOperand — operand references for MathOp nodes.
Hardcoded lists of math and comparison operators for dropdown editors.
ImNodes-based graph editor for ATS Visual Script graphs (Phase 5).
static AtomicTaskUIRegistry & Get()
Returns the singleton instance.
std::vector< TaskSpec > GetSortedForUI() const
Returns all tasks sorted by category then displayName, suitable for building a dropdown or combo box.
const TaskSpec * GetTaskSpec(const std::string &id) const
Returns the TaskSpec for the given id, or nullptr if not found.
Non-singleton registry populated from the active TaskGraphTemplate.
void LoadFromTemplate(const TaskGraphTemplate &tmpl)
Rebuilds the registry from the blackboard entries of a template.
void ToggleBreakpoint(int graphID, int nodeID, const std::string &graphName="", const std::string &nodeName="")
Toggles the breakpoint at (graphID, nodeID).
static DebugController & Get()
Returns the singleton instance (Meyers pattern).
bool HasBreakpoint(int graphID, int nodeID) const
Returns true if an enabled breakpoint exists at (graphID, nodeID).
Records a property edit on a single node for undo/redo.
std::vector< TaskNodeDefinition > Nodes
All graph nodes.
std::string Name
Friendly name of this template (e.g. "PatrolBehaviour")
std::vector< BlackboardEntry > Blackboard
Local blackboard declared in this graph.
C++14-compliant type-safe value container for task parameters.
void PushCommand(std::unique_ptr< ICommand > cmd, TaskGraphTemplate &graph)
Executes the command on graph, then pushes it onto the undo stack.
std::unique_ptr< DynamicDataPinManager > m_pinManager
Dynamic pin manager shared across all Branch nodes in this panel.
UndoRedoStack m_undoStack
Undo/Redo command stack for reversible graph editing operations.
void RenderForEachNodeProperties()
void RenderSwitchNodeProperties(VSEditorNode &eNode, TaskNodeDefinition &def)
Renders the Properties panel content for a selected Switch node (Phase 1).
std::unique_ptr< VariablePropertyPanel > m_variablePanel
Properties-panel sub-widget for the selected Variable node (data pure).
TaskGraphTemplate m_template
The template currently being edited.
void RenderAvailableNodesList()
Phase 31 — Nodes list tab in Part A (available nodes for dragging to canvas)
void RenderNodePropertiesPanelContent()
Phase 31 — Content of Properties tab in Part A.
std::unique_ptr< MathOpPropertyPanel > m_mathOpPanel
Properties-panel sub-widget for the selected MathOp node.
std::unique_ptr< SwitchCaseEditorModal > m_switchCaseModal
Phase 26 — Switch Case Editor Modal.
int m_condPanelNodeID
ID of the node currently loaded into m_conditionsPanel (-1 = none).
std::unique_ptr< NodeConditionsPanel > m_conditionsPanel
Properties-panel sub-widget for the selected Branch node.
std::unique_ptr< SubGraphFilePickerModal > m_subGraphModal
Phase 26 — SubGraph File Picker Modal.
std::vector< SwitchCaseDefinition > m_propEditSwitchCases
Per-case label edit buffers.
void RenderNodePropertiesPanel()
Part A: Node Properties panel (top-left of right panel)
void RenderMathOpNodeProperties(VSEditorNode &eNode, TaskNodeDefinition &def)
Renders the Properties panel content for a selected MathOp node.
void RenderBranchNodeProperties(VSEditorNode &eNode, TaskNodeDefinition &def)
Renders the Properties panel content for a selected Branch (or While) node.
std::unique_ptr< SetBBValuePropertyPanel > m_setBBPanel
Properties-panel sub-widget for the selected SetBBValue node.
std::string m_propEditOldTaskID
void RenderVerificationPanel()
Renders the verification results panel (Phase 21-B).
int m_propEditNodeIDOnFocus
Node ID that was selected when RenderProperties() last entered focus.
void RenderSubGraphNodeProperties()
void RenderNodeDataParameters(TaskNodeDefinition &def)
Renders node parameters for data nodes (GetBBValue, SetBBValue, MathOp).
std::vector< VSEditorNode > m_editorNodes
Editor nodes (mirrors m_template.Nodes + position/selection state)
int m_selectedNodeID
Currently selected node (for properties panel)
ConditionPresetRegistry m_presetRegistry
Global registry of ConditionPreset objects.
std::string m_propEditOldName
Snapshot values captured at focus time for each editable field.
< Provides AssetID and INVALID_ASSET_ID
@ Int
32-bit signed integer
@ List
std::vector<TaskValue> (used by ForEach node)
ParameterBindingType
Describes how a parameter value is provided to a task node.
@ MathOperator
Math operator symbol (+, -, *, /, %) (from OperatorRegistry)
@ ConditionID
ID of a condition type (from ConditionRegistry)
@ AtomicTaskID
ID of an atomic task (from AtomicTaskUIRegistry)
@ SubGraphPath
File path to a sub-graph .ats file.
@ LocalVariable
Value is read from the local blackboard at runtime.
@ Literal
Value is embedded directly in the template.
@ ComparisonOp
Comparison operator (==, !=, <, <=, >, >=) (from OperatorRegistry)
TaskNodeType
Identifies the role of a node in the task graph.
@ Selector
Executes children in order; stops on first success.
@ AtomicTask
Leaf node that executes a single atomic task.
@ While
Conditional loop (Loop / Completed exec outputs)
@ Sequence
Executes children in order; stops on first failure.
@ SubGraph
Sub-graph call (SubTask)
@ DoOnce
Single-fire execution (reset via Reset pin)
@ Delay
Timer (Completed exec output after N seconds)
@ Parallel
Executes all children simultaneously.
@ GetBBValue
Data node – reads a Blackboard key.
@ MathOp
Data node – arithmetic operation (+, -, *, /)
@ SetBBValue
Data node – writes a Blackboard key.
@ ForEach
Iterate over BB list (Loop Body / Completed exec outputs)
@ Switch
Multi-branch on value (N exec outputs)
@ EntryPoint
Unique entry node for VS graphs (replaces Root)
@ Branch
If/Else conditional (Then / Else exec outputs)
@ VSSequence
Execute N outputs in order ("VS" prefix avoids collision with BT Sequence=1)
Single entry in the graph's declared blackboard schema (local or global).
@ Variable
References a blackboard variable by name.
@ Const
Literal constant value.
@ Pin
External data-input pin on the owning node.
std::string variableName
Blackboard key (mode == Variable), e.g. "mMoveSpeed".
std::string constValue
Literal string (mode == Const), e.g. "5.0".
MathOpOperand leftOperand
Left-hand side operand (A)
std::string mathOperator
Arithmetic operator: "+", "-", "*", "/", "%", "^".
MathOpOperand rightOperand
Right-hand side operand (B)
Describes how a single parameter value is supplied to a task node.
ParameterBindingType Type
Binding mode.
static PropertyValue FromFloat(float f)
static PropertyValue FromString(const std::string &s)
Describes a single case branch on a Switch node.
Full description of a single node in the task graph.
MathOpRef mathOpRef
For MathOp: complete operand configuration (left operand, operator, right operand).
std::vector< NodeConditionRef > conditionRefs
Multi-condition refs to global presets (Phase 24)
std::string BBKey
For GetBBValue/SetBBValue: BB key (scope:key)
std::string AtomicTaskID
Atomic task type identifier (used when Type == AtomicTask)
std::string switchVariable
For Switch: BB key of the variable to switch on.
TaskNodeType Type
Node role.
std::vector< ConditionRef > conditionOperandRefs
Parallel to conditions[]: each entry stores the OperandRef->DynamicDataPin UUID mapping for the corre...
std::vector< SwitchCaseDefinition > switchCases
For Switch: structured case definitions.
std::string NodeName
Human-readable name.
std::unordered_map< std::string, ParameterBinding > Parameters
Named parameter bindings passed to the atomic task.
std::vector< DynamicDataPin > dynamicPins
Dynamic data-input pins for Pin-mode operands (Phase 24)
std::vector< std::string > DynamicExecOutputPins
For VSSequence: dynamically-added exec-out pins beyond the default "Out".
float DelaySeconds
For Delay: duration in seconds.
Display metadata for a single atomic task type.
Editor-side representation of a node in the VS graph canvas.