# 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: 1. **Get Active Container**: Obtain a pointer to the current `RootContainer` from the `App` instance. 2. **Spawn Nodes**: Create the necessary nodes. For example, to use a `Log` block, you need to spawn the `Log` block itself and also any parameter nodes that will provide its inputs (like the file path). 3. **Configure Parameter Nodes**: Set the values for the parameter nodes you've created. 4. **Connect Nodes**: Find the corresponding input and output pins on the nodes and create a `Link` to connect them. 5. **Set Positions (Optional)**: If you plan to save the graph for visual inspection, set the node positions using `ed::SetNodePosition()`. 6. **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. ```cpp #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](./blocks.md).