3.3 KiB
Creating Blocks Programmatically
This guide provides a concise overview of how to add and configure block nodes programmatically in a command-line or testing environment. This is essential for creating automated unit tests. We assume a working App instance is available, as set up in headless mode (see main.cpp).
Process Overview
Creating and connecting a block involves several steps:
- Get Active Container: Obtain a pointer to the current
RootContainerfrom theAppinstance. - Spawn Nodes: Create the necessary nodes. For example, to use a
Logblock, you need to spawn theLogblock itself and also any parameter nodes that will provide its inputs (like the file path). - Configure Parameter Nodes: Set the values for the parameter nodes you've created.
- Connect Nodes: Find the corresponding input and output pins on the nodes and create a
Linkto connect them. - Set Positions (Optional): If you plan to save the graph for visual inspection, set the node positions using
ed::SetNodePosition(). - Save Graph: Persist the changes by calling
App::SaveGraph(), passing the container and a file path.
Example: Creating and Connecting a Log Block
The following function demonstrates adding a "Log" block, providing its required "FilePath" input via a "String" parameter node, connecting them, and saving the graph.
#include "app.h"
#include "containers/root_container.h"
#include "blocks/parameter_node.h" // Required for ParameterInstance
// Assumes 'app' is an initialized App instance
void AddAndConnectLogBlock(App& app, const std::string& logFilePath, const std::string& savePath)
{
// 1. Get container
RootContainer* container = app.GetActiveRootContainer();
if (!container)
return;
// 2. Spawn the log block and a parameter node for the file path
Node* logNode = app.SpawnBlockNode("Log", -1);
Node* pathNode = app.SpawnParameterNode(PinType::String, -1);
if (!logNode || !pathNode)
return;
// 3. Configure the parameter node's value
pathNode->StringValue = logFilePath;
if (pathNode->ParameterInstance) {
pathNode->ParameterInstance->SetString(logFilePath.c_str());
}
// 4. Connect the nodes
// The String parameter node has one output.
Pin* pathOutputPin = &pathNode->Outputs[0];
// The Log block's 'FilePath' is its first non-flow input pin.
// Input[0] is 'Execute' (flow), Input[1] is 'FilePath'.
Pin* logInputPin = nullptr;
if (logNode->Inputs.size() > 1) {
logInputPin = &logNode->Inputs[1];
}
if (pathOutputPin && logInputPin)
{
Link newLink(app.GetNextLinkId(), pathOutputPin->ID, logInputPin->ID);
container->AddLink(newLink);
}
// 5. Set positions (optional, requires an editor context)
ed::SetNodePosition(logNode->ID, ImVec2(200.0f, 100.0f));
ed::SetNodePosition(pathNode->ID, ImVec2(0.0f, 100.0f));
// 6. Save the updated graph
app.SaveGraph(savePath, container);
}
This more detailed example provides a solid foundation for scripting graph creation for unit tests, ensuring that blocks are not only created but also correctly configured and connected.
Block Reference
For a complete list of available blocks and their parameters, see the Block Reference.