### Configure Installation Paths (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Sets up installation directories using `GNUInstallDirs` and defines the configuration directory path. This prepares the build system for installing the library and its associated files. ```cmake include(GNUInstallDirs) set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/QtNodes) ``` -------------------------------- ### Build Examples and Documentation (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Conditionally includes the 'examples' and 'docs' subdirectories for building if the respective build flags (`BUILD_EXAMPLES`, `BUILD_DOCS`) are enabled. This allows for selective building of project components. ```cmake if(BUILD_EXAMPLES) add_subdirectory(examples) endif() if(BUILD_DOCS) add_subdirectory(docs) endif() ``` -------------------------------- ### Install QtNodes Headers (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Installs the public header files of the QtNodes library to the system's include directory. This makes the library's API available to other projects that link against it. ```cmake install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) ``` -------------------------------- ### Clone and Build QtNodes on Linux Source: https://github.com/paceholder/nodeeditor/blob/master/README.rst This sequence of commands outlines the process for cloning the QtNodes repository and building it on a Linux system using CMake and Make. It includes creating a build directory, configuring the build with CMake, compiling the library, and installing it. ```bash git clone git@github.com:paceholder/nodeeditor.git cd nodeeditor mkdir build cd build cmake .. make -j && make install ``` -------------------------------- ### CMake Policies and Project Setup for QtNodesLibrary Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Sets the minimum CMake version, applies specific policies for compatibility, and initializes the C++ project named QtNodesLibrary. It also configures module paths and disables in-source builds. ```cmake cmake_minimum_required(VERSION 3.11) cmake_policy(SET CMP0072 NEW) # new in 3.11. The NEW behavior for this policy is to set OpenGL_GL_PREFERENCE to GLVND. cmake_policy(SET CMP0068 NEW) # new in 3.9. The NEW behavior of this policy is to ignore the RPATH settings for install_name on macOS. project(QtNodesLibrary CXX) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) set(CMAKE_DISABLE_SOURCE_CHANGES ON) set(OpenGL_GL_PREFERENCE LEGACY) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Enable AUTOMOC globally for all targets (needed for examples with Q_OBJECT) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) ``` -------------------------------- ### Generate and Install QtNodes Package Configuration File (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Generates the `QtNodesConfig.cmake` file from a template and installs it. This file is essential for CMake's `find_package` mechanism to locate and configure the QtNodes library when used in other projects. ```cmake include(CMakePackageConfigHelpers) configure_package_config_file(${CMAKE_CURRENT_LIST_DIR}/cmake/QtNodesConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/QtNodesConfig.cmake INSTALL_DESTINATION ${INSTALL_CONFIGDIR} ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/QtNodesConfig.cmake DESTINATION ${INSTALL_CONFIGDIR} ) ``` -------------------------------- ### Install QtNodes CMake Export Files (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Installs the CMake export file (`QtNodesTargets.cmake`) which allows other CMake projects to find and use the installed QtNodes library. It defines targets and configurations for imported targets. ```cmake install(EXPORT QtNodesTargets FILE QtNodesTargets.cmake NAMESPACE QtNodes:: DESTINATION ${INSTALL_CONFIGDIR} ) ``` -------------------------------- ### Install QtNodes Library Artifacts (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Installs the QtNodes library targets (runtime, library, archive) to their respective installation directories. It also creates an export set named `QtNodesTargets` for integration with other CMake projects. ```cmake install(TARGETS QtNodes EXPORT QtNodesTargets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) ``` -------------------------------- ### Connection Serialization Example (JSON) Source: https://github.com/paceholder/nodeeditor/blob/master/docs/features.md Shows the simple JSON structure for a serialized connection, containing the input and output port indices and the node IDs of the connected nodes. This is used for saving and loading connection data. ```json { "inPortIndex" : 0, "intNodeId" : 1, "outNodeId" : 0, "outPortIndex" : 0 } ``` -------------------------------- ### Configure QtNodes Include Directories (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Sets the include directories for the QtNodes library, distinguishing between build-time and install-time, and public/private visibility. This ensures proper header file resolution during compilation and after installation. ```cmake target_include_directories(QtNodes PUBLIC $ $ PRIVATE $ $ ) ``` -------------------------------- ### Configure CMake with vcpkg Toolchain Source: https://github.com/paceholder/nodeeditor/blob/master/README.rst This example shows how to configure CMake to use the vcpkg package manager. The -DCMAKE_TOOLCHAIN_FILE flag points to the vcpkg toolchain file, ensuring that dependencies are managed and resolved through vcpkg. This is essential for projects relying on vcpkg for dependency management. ```cmake cmake .. -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/scripts/buildsystems/vcpkg.cmake ``` -------------------------------- ### CMake Build Options for QtNodesLibrary Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Defines boolean options to control the build process, including enabling tests, examples, documentation, shared libraries, debug postfixes, and Qt6 usage. Default values are set based on whether it's a root project. ```cmake get_directory_property(_has_parent PARENT_DIRECTORY) if(_has_parent) set(is_root_project OFF) else() set(is_root_project ON) endif() set(QT_NODES_DEVELOPER_DEFAULTS "${is_root_project}" CACHE BOOL "Turns on default settings for development of QtNodes") option(BUILD_TESTING "Build tests" "${QT_NODES_DEVELOPER_DEFAULTS}") option(BUILD_EXAMPLES "Build Examples" "${QT_NODES_DEVELOPER_DEFAULTS}") option(BUILD_DOCS "Build Documentation" "${QT_NODES_DEVELOPER_DEFAULTS}") option(BUILD_SHARED_LIBS "Build as shared library" ON) option(BUILD_DEBUG_POSTFIX_D "Append d suffix to debug libraries" OFF) option(QT_NODES_FORCE_TEST_COLOR "Force colorized unit test output" OFF) option(USE_QT6 "Build with Qt6 (Enabled by default)" ON) ``` -------------------------------- ### NodeEditor Vertical Layout Example (Text) Source: https://github.com/paceholder/nodeeditor/blob/master/docs/features.md Illustrates the visual layout of nodes when using the vertical mode in NodeEditor. This representation shows port and node caption placements. ```text -------o-------------o------- | PortCaption PortCaption | | | | Node Caption | | | | | | PortCaption | --------------o-------------- ``` -------------------------------- ### C++ Dynamic Port Addition and Removal in QtNodes Source: https://context7.com/paceholder/nodeeditor/llms.txt Demonstrates adding and removing input ports dynamically for a QtNodes NodeDelegateModel. It utilizes signals like `portsAboutToBeInserted`, `portsInserted`, `portsAboutToBeDeleted`, and `portsDeleted` to notify the framework of changes, ensuring connection integrity. The example includes a simple UI with buttons to trigger these operations and recomputes data based on connected inputs. ```cpp #include #include class DynamicPortsModel : public QtNodes::NodeDelegateModel { Q_OBJECT public: QString name() const override { return "DynamicPorts"; } QString caption() const override { return "Dynamic Ports"; } unsigned int nPorts(QtNodes::PortType portType) const override { return (portType == QtNodes::PortType::In) ? _inputPorts.size() : 1; } QtNodes::NodeDataType dataType(QtNodes::PortType, QtNodes::PortIndex) const override { return DecimalData().type(); } void addInputPort() { QtNodes::PortIndex newIndex = _inputPorts.size(); // Notify before insertion Q_EMIT portsAboutToBeInserted(QtNodes::PortType::In, newIndex, newIndex); _inputPorts.push_back(nullptr); // Notify after insertion Q_EMIT portsInserted(); } void removeInputPort(QtNodes::PortIndex index) { if (index >= _inputPorts.size()) return; // Notify before deletion (connections will be removed) Q_EMIT portsAboutToBeDeleted(QtNodes::PortType::In, index, index); _inputPorts.erase(_inputPorts.begin() + index); // Notify after deletion Q_EMIT portsDeleted(); } void setInData(std::shared_ptr data, QtNodes::PortIndex index) override { if (index < _inputPorts.size()) { _inputPorts[index] = std::dynamic_pointer_cast(data); compute(); } } std::shared_ptr outData(QtNodes::PortIndex) override { return _result; } QWidget* embeddedWidget() override { if (!_widget) { _widget = new QWidget(); auto* layout = new QVBoxLayout(_widget); auto* addBtn = new QPushButton("Add Input"); connect(addBtn, &QPushButton::clicked, this, &DynamicPortsModel::addInputPort); layout->addWidget(addBtn); auto* removeBtn = new QPushButton("Remove Input"); connect(removeBtn, &QPushButton::clicked, [this]() { if (!_inputPorts.empty()) removeInputPort(_inputPorts.size() - 1); }); layout->addWidget(removeBtn); } return _widget; } private: void compute() { double sum = 0.0; for (auto const& data : _inputPorts) { if (data) sum += data->number(); } _result = std::make_shared(sum); Q_EMIT dataUpdated(0); } std::vector> _inputPorts; std::shared_ptr _result; QWidget* _widget = nullptr; }; ``` -------------------------------- ### Node Serialization Example (JSON) Source: https://github.com/paceholder/nodeeditor/blob/master/docs/features.md Illustrates the typical JSON format for a serialized node, including its ID, internal data specific to the model, and its position within the graph. This format is used for saving and loading graph states. ```json { "id" : 0, "internal-data" : { "model-name" : "Subtraction" }, "position" : { "x" : -383, "y" : -95 } } ``` -------------------------------- ### Build and Run QtNodes Unit Tests Source: https://github.com/paceholder/nodeeditor/blob/master/README.rst This set of commands illustrates how to build and execute the unit tests for QtNodes. After building the tests with 'make test_nodes', the executable './bin/test_nodes' can be run to execute all tests or specific categories using bracketed identifiers like '[core]'. ```bash # Build tests make test_nodes # Run all tests ./bin/test_nodes # Run specific categories ./bin/test_nodes "[core]" ./bin/test_nodes "[graphics]" ``` -------------------------------- ### Configure Sphinx Documentation Build (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/docs/CMakeLists.txt This CMake snippet sets up the Sphinx documentation generator. It finds the Sphinx package, defines source and build directories, and creates a custom command to run Sphinx. This command integrates Doxygen's XML output with Sphinx for comprehensive documentation, with dependencies on Doxygen output and source files. ```cmake find_package(Sphinx) if (Sphinx_FOUND) set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}) set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx) set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html) # Only regenerate Sphinx when: # - Doxygen has rerun # - Our doc files have been updated # - The Sphinx config has been updated add_custom_command(OUTPUT ${SPHINX_INDEX_FILE} COMMAND ${SPHINX_EXECUTABLE} -b html # Tell Breathe where to find the Doxygen output -Dbreathe_projects.QtNodes=${DOXYGEN_OUTPUT_DIR}/xml ${SPHINX_SOURCE} ${SPHINX_BUILD} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} # Other docs files you want to track should go here (or in some variable) DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/index.rst ${DOXYGEN_INDEX_FILE} MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py COMMENT "Generating documentation with Sphinx") # Nice named target so we can run the job easily add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE}) # Add an install target to install the docs include(GNUInstallDirs) install(DIRECTORY ${SPHINX_BUILD} DESTINATION ${CMAKE_INSTALL_DOCDIR}) endif() ``` -------------------------------- ### Download Catch2 Header and Configure CMake Interface Library Source: https://github.com/paceholder/nodeeditor/blob/master/external/Catch2/CMakeLists.txt This snippet demonstrates downloading the Catch2 single include header file if it doesn't already exist in the build directory. It then creates an INTERFACE library named 'Catch2' and an alias 'Catch2::Catch2'. Finally, it configures the include directories for the interface library to point to the location where the Catch2 header is downloaded. ```cmake if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/single_include/catch2/catch.hpp") file(DOWNLOAD https://raw.githubusercontent.com/catchorg/Catch2/v2.13.7/single_include/catch2/catch.hpp "${CMAKE_CURRENT_BINARY_DIR}/single_include/catch2/catch.hpp" EXPECTED_HASH SHA256=ea379c4a3cb5799027b1eb451163dff065a3d641aaba23bf4e24ee6b536bd9bc ) endif() add_library(Catch2 INTERFACE) add_library(Catch2::Catch2 ALIAS Catch2) target_include_directories(Catch2 INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/single_include" ) ``` -------------------------------- ### Configure Doxygen Documentation Build (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/docs/CMakeLists.txt This CMake snippet configures the Doxygen documentation generator. It finds the Doxygen package, locates public headers, sets input and output directories, and defines a custom command to run Doxygen, creating a target for the documentation build. ```cmake find_package(Doxygen) if(DOXYGEN_FOUND) # Find all the public headers get_target_property(QT_NODES_PUBLIC_HEADER_DIR QtNodes INTERFACE_INCLUDE_DIRECTORIES) file(GLOB_RECURSE QT_NODES_PUBLIC_HEADERS ${QT_NODES_PUBLIC_HEADER_DIR}/*.hpp) #This will be the main output of our command set(DOXYGEN_INDEX_FILE ${CMAKE_CURRENT_BINARY_DIR}/html/index.html) set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/examples/calculator) # Making string joined with " " list(JOIN DOXYGEN_INPUT_DIR " " DOXYGEN_INPUT_DIR_JOINED) set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doxygen) set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/html/index.html) set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY) file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR}) #Doxygen won't create this for us add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE} DEPENDS ${QT_NODES_PUBLIC_HEADERS} COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN} COMMENT "Generating docs" VERBATIM) add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE}) endif() ``` -------------------------------- ### NodeEditor Node Locking (C++) Source: https://github.com/paceholder/nodeeditor/blob/master/docs/features.md Provides a C++ example for locking nodes in NodeEditor, making them insensitive to mouse events. This is achieved by overriding the `nodeFlags` function in `AbstractGraphModel` and adding the `NodeFlag::Locked` flag. ```cpp NodeFlags YourGraphModel:: nodeFlags(NodeId nodeId) const override { auto basicFlags = DataFlowGraphModel::nodeFlags(nodeId); if (_nodesLocked) basicFlags |= NodeFlag::Locked; return basicFlags; } ``` -------------------------------- ### Link Libraries to Executable Source: https://github.com/paceholder/nodeeditor/blob/master/test/CMakeLists.txt Links the necessary libraries to the 'test_nodes' executable. This includes the project's QtNodes library, the Catch2 testing framework, and the Qt Test module, dynamically selecting the Qt Test library based on the Qt version. ```cmake target_link_libraries(test_nodes PRIVATE QtNodes::QtNodes Catch2::Catch2 Qt${QT_VERSION_MAJOR}::Test ) ``` -------------------------------- ### Enable Testing and Build Tests (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Enables the testing framework using `enable_testing()` and conditionally includes the 'test' subdirectory if `BUILD_TESTING` is enabled. This allows for running automated tests. ```cmake enable_testing() if(BUILD_TESTING) add_subdirectory(test) endif() ``` -------------------------------- ### BasicGraphicsScene - C++ Graph Visualization Source: https://context7.com/paceholder/nodeeditor/llms.txt Implements a QGraphicsScene for visualizing nodes and connections in a graph. It manages visual representations and handles user interactions like clicks and node movement. Dependencies include QtNodes basic scene, graphics view, graph model, and Qt's QApplication. ```cpp #include #include #include #include // Create model SimpleGraphModel graphModel; // Initialize nodes QtNodes::NodeId id1 = graphModel.addNode(); graphModel.setNodeData(id1, QtNodes::NodeRole::Position, QPointF(0, 0)); QtNodes::NodeId id2 = graphModel.addNode(); graphModel.setNodeData(id2, QtNodes::NodeRole::Position, QPointF(300, 300)); // Connect nodes graphModel.addConnection(QtNodes::ConnectionId{id1, 0, id2, 0}); // Create scene and view auto* scene = new QtNodes::BasicGraphicsScene(graphModel); QtNodes::GraphicsView view(scene); // Handle scene events QObject::connect(scene, &QtNodes::BasicGraphicsScene::nodeClicked, [](QtNodes::NodeId nodeId) { qDebug() << "Node clicked:" << nodeId; }); QObject::connect(scene, &QtNodes::BasicGraphicsScene::nodeMoved, [](QtNodes::NodeId nodeId, QPointF const& pos) { qDebug() << "Node" << nodeId << "moved to" << pos; }); QObject::connect(scene, &QtNodes::BasicGraphicsScene::nodeContextMenu, [](QtNodes::NodeId nodeId, QPointF const& pos) { // Show custom context menu }); // Change orientation scene->setOrientation(Qt::Vertical); // or Qt::Horizontal // Access graphics objects auto* nodeGraphicsObj = scene->nodeGraphicsObject(id1); auto* connGraphicsObj = scene->connectionGraphicsObject(QtNodes::ConnectionId{id1, 0, id2, 0}); // Undo/redo support QUndoStack& undoStack = scene->undoStack(); undoStack.undo(); undoStack.redo(); view.show(); ``` -------------------------------- ### Customize Node and Connection Styles using JSON in C++ Source: https://context7.com/paceholder/nodeeditor/llms.txt This code provides methods to customize the visual appearance of nodes and connections in the QtNodes framework using JSON-formatted strings. It involves setting global connection styles and defining specific node styles. These styles can be loaded directly from JSON or configured programmatically. This requires the QtNodes library. ```cpp #include #include // Configure connection style void configureConnectionStyle() { QtNodes::ConnectionStyle::setConnectionStyle(R"( { "ConnectionStyle": { "ConstructionColor": "gray", "NormalColor": "black", "SelectedColor": "red", "SelectedHaloColor": "deepskyblue", "HoveredColor": "deepskyblue", "LineWidth": 3.0, "ConstructionLineWidth": 2.0, "PointDiameter": 10.0, "UseDataDefinedColors": true } } )"); } // Custom node styling QtNodes::NodeStyle createCustomNodeStyle() { QtNodes::NodeStyle customNodeStyle; customNodeStyle.loadStyleFromJson(R"( { "NodeStyle": { "NormalBoundaryColor": [0, 0, 0], "SelectedBoundaryColor": [255, 165, 0], "GradientColor0": [240, 240, 240], "GradientColor1": [220, 220, 220], "GradientColor2": [200, 200, 200], "GradientColor3": [180, 180, 180], "ShadowColor": [0, 0, 0, 50], "FontColor": [0, 0, 0], "FontColorFaded": [128, 128, 128], "ConnectionPointColor": [100, 100, 100], "PenWidth": 2.0, "HoveredPenWidth": 3.0, "ConnectionPointDiameter": 8.0, "Opacity": 1.0 } } )"); return customNodeStyle; } // Usage example: // configureConnectionStyle(); // auto style = createCustomNodeStyle(); // auto* nodeModel = new CustomNodeModel(); // Assuming CustomNodeModel is defined elsewhere // nodeModel->setNodeStyle(style); ``` -------------------------------- ### AbstractGraphModel Implementation - C++ Source: https://context7.com/paceholder/nodeeditor/llms.txt This C++ snippet demonstrates a basic implementation of the `AbstractGraphModel` class from the QtNodes library. It covers core functionalities like node creation, deletion, ID management, position setting, and connection handling. This class is fundamental for defining the graph's structure and behavior. ```cpp #include #include #include class MyGraphModel : public QtNodes::AbstractGraphModel { Q_OBJECT private: QtNodes::NodeId _nextNodeId = 0; std::unordered_set _nodeIds; std::unordered_set _connectivity; std::unordered_map _positions; public: QtNodes::NodeId newNodeId() override { return _nextNodeId++; } std::unordered_set allNodeIds() const override { return _nodeIds; } QtNodes::NodeId addNode(QString const nodeType = QString()) override { QtNodes::NodeId id = newNodeId(); _nodeIds.insert(id); Q_EMIT nodeCreated(id); return id; } bool nodeExists(QtNodes::NodeId const nodeId) const override { return _nodeIds.count(nodeId) > 0; } QVariant nodeData(QtNodes::NodeId nodeId, QtNodes::NodeRole role) const override { if (role == QtNodes::NodeRole::Position) { auto it = _positions.find(nodeId); return it != _positions.end() ? QVariant(it->second) : QVariant(QPointF(0, 0)); } return QVariant(); } bool setNodeData(QtNodes::NodeId nodeId, QtNodes::NodeRole role, QVariant value) override { if (role == QtNodes::NodeRole::Position) { _positions[nodeId] = value.value(); Q_EMIT nodePositionUpdated(nodeId); return true; } return false; } void addConnection(QtNodes::ConnectionId const connectionId) override { _connectivity.insert(connectionId); Q_EMIT connectionCreated(connectionId); } bool connectionPossible(QtNodes::ConnectionId const connectionId) const override { return !connectionExists(connectionId); } bool connectionExists(QtNodes::ConnectionId const connectionId) const override { return _connectivity.count(connectionId) > 0; } bool deleteNode(QtNodes::NodeId const nodeId) override { if (_nodeIds.erase(nodeId) > 0) { Q_EMIT nodeDeleted(nodeId); return true; } return false; } // Implement remaining pure virtual methods... }; ``` -------------------------------- ### Registering and Using DataFlowGraphModel in C++ Source: https://context7.com/paceholder/nodeeditor/llms.txt Demonstrates how to register custom node types (e.g., NumberSourceDataModel, AdditionModel, MultiplicationModel) with a NodeDelegateModelRegistry. It then shows the creation of a DataFlowGraphModel, programmatic addition and positioning of nodes, establishing connections for automatic data propagation, accessing specific node delegates to set data, and saving/loading the graph's state. ```cpp #include #include #include // Register custom node types auto registry = std::make_shared(); registry->registerModel("Sources"); registry->registerModel("Operators"); registry->registerModel("Operators"); // Create data flow model QtNodes::DataFlowGraphModel dataFlowModel(registry); // Add nodes programmatically QtNodes::NodeId sourceId1 = dataFlowModel.addNode("NumberSource"); QtNodes::NodeId sourceId2 = dataFlowModel.addNode("NumberSource"); QtNodes::NodeId addId = dataFlowModel.addNode("Addition"); QtNodes::NodeId multId = dataFlowModel.addNode("Multiplication"); // Position nodes dataFlowModel.setNodeData(sourceId1, QtNodes::NodeRole::Position, QPointF(0, 0)); dataFlowModel.setNodeData(sourceId2, QtNodes::NodeRole::Position, QPointF(0, 100)); dataFlowModel.setNodeData(addId, QtNodes::NodeRole::Position, QPointF(300, 50)); dataFlowModel.setNodeData(multId, QtNodes::NodeRole::Position, QPointF(600, 50)); // Connect nodes - data flows automatically QtNodes::ConnectionId conn1{sourceId1, 0, addId, 0}; QtNodes::ConnectionId conn2{sourceId2, 0, addId, 1}; QtNodes::ConnectionId conn3{addId, 0, multId, 0}; dataFlowModel.addConnection(conn1); dataFlowModel.addConnection(conn2); dataFlowModel.addConnection(conn3); // Access specific node delegate auto* sourceModel = dataFlowModel.delegateModel(sourceId1); if (sourceModel) { sourceModel->setNumber(42.0); } // Save/load graph state QJsonObject json = dataFlowModel.save(); // ... write to file ... dataFlowModel.load(json); ``` -------------------------------- ### Define Executable and Source Files Source: https://github.com/paceholder/nodeeditor/blob/master/test/CMakeLists.txt Defines the main executable target named 'test_nodes'. It lists all the C++ source files and header files required to build the executable. ```cmake add_executable(test_nodes test_main.cpp src/TestAbstractGraphModel.cpp src/TestAbstractGraphModelSignals.cpp src/TestDataFlowGraphModel.cpp src/TestNodeDelegateModelRegistry.cpp src/TestConnectionId.cpp src/TestSerialization.cpp src/TestUndoCommands.cpp src/TestBasicGraphicsScene.cpp src/TestUIInteraction.cpp src/TestDataFlow.cpp include/ApplicationSetup.hpp include/TestGraphModel.hpp include/UITestHelper.hpp include/TestDataFlowNodes.hpp ) ``` -------------------------------- ### DataFlowGraphicsScene - C++ Data Flow Visualization with Persistence Source: https://context7.com/paceholder/nodeeditor/llms.txt A specialized scene for data flow graphs offering JSON-based save and load functionality. It requires a node delegate model registry and a data flow graph model. The scene emits signals for scene loading and modification, enabling UI updates and persistence management. ```cpp #include #include #include #include #include #include QApplication app(argc, argv); QWidget mainWidget; // Setup registry and model auto registry = std::make_shared(); registry->registerModel("Sources"); registry->registerModel("Operators"); QtNodes::DataFlowGraphModel dataFlowModel(registry); // Create scene auto* scene = new QtNodes::DataFlowGraphicsScene(dataFlowModel, &mainWidget); auto* view = new QtNodes::GraphicsView(scene); // Setup menu auto* menuBar = new QMenuBar(); QMenu* fileMenu = menuBar->addMenu("File"); auto* saveAction = fileMenu->addAction("Save Scene"); saveAction->setShortcut(QKeySequence::Save); QObject::connect(saveAction, &QAction::triggered, [scene, &mainWidget]() { if (scene->save()) { mainWidget.setWindowModified(false); } }); auto* loadAction = fileMenu->addAction("Load Scene"); loadAction->setShortcut(QKeySequence::Open); QObject::connect(loadAction, &QAction::triggered, scene, &QtNodes::DataFlowGraphicsScene::load); // Center view after loading QObject::connect(scene, &QtNodes::DataFlowGraphicsScene::sceneLoaded, view, &QtNodes::GraphicsView::centerScene); // Track modifications QObject::connect(scene, &QtNodes::DataFlowGraphicsScene::modified, [&mainWidget]() { mainWidget.setWindowModified(true); }); // Layout QVBoxLayout* layout = new QVBoxLayout(&mainWidget); layout->addWidget(menuBar); layout->addWidget(view); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); mainWidget.setWindowTitle("[*]Data Flow Editor"); mainWidget.resize(800, 600); mainWidget.show(); ``` -------------------------------- ### CMake Output Directory Configuration for QtNodesLibrary Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Configures the output directories for runtime binaries, libraries, and archives. These settings are applied when developer defaults are enabled, placing outputs in the build directory's 'bin' and 'lib' subfolders. ```cmake if(QT_NODES_DEVELOPER_DEFAULTS) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") endif() ``` -------------------------------- ### Implement Addition Processing Node Source: https://context7.com/paceholder/nodeeditor/llms.txt Implements an 'AdditionModel' node that takes two decimal inputs and outputs their sum. This node inherits from NodeDelegateModel, defines two input ports and one output port, and computes the result when input data is received. The computation logic is handled in the 'compute' method. ```cpp #include #include #include // Assuming DecimalData is defined elsewhere or included // Implement processing node class AdditionModel : public QtNodes::NodeDelegateModel { Q_OBJECT public: QString name() const override { return "Addition"; } QString caption() const override { return "Addition"; } unsigned int nPorts(QtNodes::PortType portType) const override { return (portType == QtNodes::PortType::In) ? 2 : 1; } QtNodes::NodeDataType dataType(QtNodes::PortType, QtNodes::PortIndex) const override { return DecimalData().type(); } void setInData(std::shared_ptr nodeData, QtNodes::PortIndex portIndex) override { auto data = std::dynamic_pointer_cast(nodeData); if (portIndex == 0) _number1 = data; else if (portIndex == 1) _number2 = data; compute(); } std::shared_ptr outData(QtNodes::PortIndex) override { return _result; } QWidget* embeddedWidget() override { return nullptr; } private: void compute() { if (_number1 && _number2) { _result = std::make_shared(_number1->number() + _number2->number()); } else { _result.reset(); } Q_EMIT dataUpdated(0); } std::shared_ptr _number1; std::shared_ptr _number2; std::shared_ptr _result; }; ``` -------------------------------- ### Source and Header File Definitions for QtNodesLibrary Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Lists the C++ source files and header files used by the QtNodesLibrary project. These lists are used by CMake to compile the library and its components. ```cmake set(CPP_SOURCE_FILES src/AbstractGraphModel.cpp src/AbstractNodeGeometry.cpp src/BasicGraphicsScene.cpp src/ConnectionGraphicsObject.cpp src/ConnectionState.cpp src/ConnectionStyle.cpp src/DataFlowGraphModel.cpp src/DataFlowGraphicsScene.cpp src/DefaultConnectionPainter.cpp src/DefaultHorizontalNodeGeometry.cpp src/DefaultNodePainter.cpp src/DefaultVerticalNodeGeometry.cpp src/Definitions.cpp src/GraphicsView.cpp src/GraphicsViewStyle.cpp src/NodeConnectionInteraction.cpp src/NodeDelegateModel.cpp src/NodeDelegateModelRegistry.cpp src/NodeGraphicsObject.cpp src/NodeState.cpp src/NodeStyle.cpp src/StyleCollection.cpp src/UndoCommands.cpp src/locateNode.cpp resources/resources.qrc ) set(HPP_HEADER_FILES include/QtNodes/internal/AbstractConnectionPainter.hpp include/QtNodes/internal/AbstractGraphModel.hpp include/QtNodes/internal/AbstractNodeGeometry.hpp include/QtNodes/internal/AbstractNodePainter.hpp include/QtNodes/internal/BasicGraphicsScene.hpp include/QtNodes/internal/Compiler.hpp include/QtNodes/internal/ConnectionGraphicsObject.hpp include/QtNodes/internal/ConnectionIdHash.hpp include/QtNodes/internal/ConnectionIdUtils.hpp include/QtNodes/internal/ConnectionState.hpp include/QtNodes/internal/ConnectionStyle.hpp include/QtNodes/internal/DataFlowGraphicsScene.hpp include/QtNodes/internal/DataFlowGraphModel.hpp include/QtNodes/internal/Definitions.hpp include/QtNodes/internal/Export.hpp include/QtNodes/internal/GraphicsView.hpp include/QtNodes/internal/GraphicsViewStyle.hpp include/QtNodes/internal/locateNode.hpp include/QtNodes/internal/NodeData.hpp include/QtNodes/internal/NodeDelegateModel.hpp include/QtNodes/internal/NodeDelegateModelRegistry.hpp include/QtNodes/internal/NodeGraphicsObject.hpp include/QtNodes/internal/NodeState.hpp include/QtNodes/internal/NodeStyle.hpp include/QtNodes/internal/OperatingSystem.hpp include/QtNodes/internal/QStringStdHash.hpp include/QtNodes/internal/QUuidStdHash.hpp include/QtNodes/internal/Serializable.hpp include/QtNodes/internal/Style.hpp include/QtNodes/internal/StyleCollection.hpp include/QtNodes/internal/DefaultConnectionPainter.hpp include/QtNodes/internal/DefaultHorizontalNodeGeometry.hpp include/QtNodes/internal/DefaultNodePainter.hpp include/QtNodes/internal/DefaultVerticalNodeGeometry.hpp include/QtNodes/internal/NodeConnectionInteraction.hpp include/QtNodes/internal/UndoCommands.hpp ) # If we want to give the option to build a static library, ``` -------------------------------- ### Add Test Case for Executable Source: https://github.com/paceholder/nodeeditor/blob/master/test/CMakeLists.txt Defines a test case named 'test_nodes' that will execute the built 'test_nodes' executable. It includes an optional argument to enable colored output if the NE_FORCE_TEST_COLOR variable is defined. ```cmake add_test( NAME test_nodes COMMAND $ $<$:--use-colour=yes> ) ``` -------------------------------- ### Configure CMake for Static Library Build Source: https://github.com/paceholder/nodeeditor/blob/master/README.rst This command configures the CMake build to produce a static library instead of a shared one. The BUILD_SHARED_LIBS=off flag ensures that all components are linked statically, which can be useful for deployment or specific project requirements. ```cmake cmake .. -DBUILD_SHARED_LIBS=off ``` -------------------------------- ### GraphicsView - C++ Interactive Node Editor View Source: https://context7.com/paceholder/nodeeditor/llms.txt A specialized QGraphicsView providing interactive features for node graphs, including pan, zoom, and context menu support. It allows programmatic control over scene centering and scaling, and facilitates adding custom actions like node creation and deletion via context menus. ```cpp #include #include #include #include QtNodes::GraphicsView view(scene); // Setup context menu for node creation view.setContextMenuPolicy(Qt::ActionsContextMenu); QAction createNodeAction("Create Node", &view); QObject::connect(&createNodeAction, &QAction::triggered, [&]() { QPointF scenePos = view.mapToScene(view.mapFromGlobal(QCursor::pos())); QtNodes::NodeId newId = graphModel.addNode(); graphModel.setNodeData(newId, QtNodes::NodeRole::Position, scenePos); }); view.addAction(&createNodeAction); QAction deleteNodeAction("Delete Selected", &view); deleteNodeAction.setShortcut(QKeySequence::Delete); QObject::connect(&deleteNodeAction, &QAction::triggered, [&]() { auto selectedItems = scene->selectedItems(); for (auto* item : selectedItems) { // Handle deletion } }); view.addAction(&deleteNodeAction); // Center scene programmatically view.centerScene(); // Zoom controls view.scale(1.5, 1.5); // Zoom in view.scale(0.75, 0.75); // Zoom out view.setWindowTitle("Node Editor"); view.resize(1024, 768); view.show(); ``` -------------------------------- ### Save and Load Graphs using JSON Serialization in C++ Source: https://context7.com/paceholder/nodeeditor/llms.txt This code demonstrates how to save and load the complete state of a graph, including node positions, connections, and custom data, using JSON serialization with QtNodes. It requires QtNodes library and standard C++ libraries for file I/O and JSON handling. The functions take a DataFlowGraphModel and a filename as input and output, respectively. Custom node data can also be serialized and deserialized. ```cpp #include #include #include #include // Save graph to file void saveGraph(QtNodes::DataFlowGraphModel& model, QString const& filename) { QJsonObject json = model.save(); QJsonDocument doc(json); QFile file(filename); if (file.open(QIODevice::WriteOnly)) { file.write(doc.toJson()); file.close(); } } // Load graph from file void loadGraph(QtNodes::DataFlowGraphModel& model, QString const& filename) { QFile file(filename); if (file.open(QIODevice::ReadOnly)) { QByteArray data = file.readAll(); file.close(); QJsonDocument doc = QJsonDocument::fromJson(data); model.load(doc.object()); } } // Custom node serialization class CustomNodeModel : public QtNodes::NodeDelegateModel { public: QJsonObject save() const override { QJsonObject obj = QtNodes::NodeDelegateModel::save(); obj["customValue"] = _customValue; obj["customName"] = _customName; return obj; } void load(QJsonObject const& json) override { QtNodes::NodeDelegateModel::load(json); _customValue = json["customValue"].toInt(); _customName = json["customName"].toString(); } private: int _customValue = 0; QString _customName; }; // Usage // Assuming dataFlowModel is an instance of QtNodes::DataFlowGraphModel // saveGraph(dataFlowModel, "my_graph.json"); // loadGraph(dataFlowModel, "my_graph.json"); ``` -------------------------------- ### CMake Debug Postfix Configuration for QtNodesLibrary Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Configures postfixes for different build types when the BUILD_DEBUG_POSTFIX_D option is enabled. This allows for custom suffixes on debug, release, relwithdebinfo, and minsizerel libraries. ```cmake if(BUILD_DEBUG_POSTFIX_D) set(CMAKE_DEBUG_POSTFIX "d") set(CMAKE_RELEASE_POSTFIX "") set(CMAKE_RELWITHDEBINFO_POSTFIX "rd") set(CMAKE_MINSIZEREL_POSTFIX "s") endif() ``` -------------------------------- ### Configure CMake Build with Qt Version Source: https://github.com/paceholder/nodeeditor/blob/master/README.rst This snippet demonstrates how to configure the CMake build process to use either Qt6 or Qt5. The USE_QT6 option controls the Qt version selection. It's used during the CMake configuration step to specify the desired Qt version for building the library. ```cmake mkdir build && cd build && cmake .. -DUSE_QT6=on or mkdir build && cd build && cmake .. -DUSE_QT6=off ``` -------------------------------- ### Implement Number Source Node Source: https://context7.com/paceholder/nodeeditor/llms.txt Implements a 'NumberSourceDataModel' that acts as a node providing a decimal number. It features a QLineEdit for user input, converts the text to a double, and emits a data update signal. It inherits from NodeDelegateModel and defines input/output ports and data types. ```cpp #include #include #include #include // Assuming DecimalData is defined elsewhere or included // Implement source node class NumberSourceDataModel : public QtNodes::NodeDelegateModel { Q_OBJECT public: QString name() const override { return "NumberSource"; } QString caption() const override { return "Number Source"; } unsigned int nPorts(QtNodes::PortType portType) const override { return (portType == QtNodes::PortType::Out) ? 1 : 0; } QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override { return DecimalData().type(); } std::shared_ptr outData(QtNodes::PortIndex port) override { return _number; } void setInData(std::shared_ptr, QtNodes::PortIndex) override {} QWidget* embeddedWidget() override { if (!_lineEdit) { _lineEdit = new QLineEdit(); connect(_lineEdit, &QLineEdit::textEdited, this, &NumberSourceDataModel::onTextEdited); } return _lineEdit; } void setNumber(double number) { _number = std::make_shared(number); Q_EMIT dataUpdated(0); } private Q_SLOTS: void onTextEdited(QString const& text) { bool ok; double value = text.toDouble(&ok); if (ok) { _number = std::make_shared(value); Q_EMIT dataUpdated(0); } } private: std::shared_ptr _number; QLineEdit* _lineEdit = nullptr; }; ``` -------------------------------- ### Qt Package Finding and Version Check in CMake Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Finds the required Qt packages (Widgets, Core, Gui, OpenGL) based on the selected Qt version (Qt5 or Qt6). It also checks if the detected Qt version is at least 5.11.0, failing the build otherwise. ```cmake if(USE_QT6) find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets) else() find_package(QT NAMES Qt5 REQUIRED COMPONENTS Widgets) endif() find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui OpenGL) message(STATUS "QT_VERSION: ${QT_VERSION}, QT_DIR: ${QT_DIR}") if (${QT_VERSION} VERSION_LESS 5.11.0) message(FATAL_ERROR "Requires qt version >= 5.11.0, Your current version is ${QT_VERSION}") endif() ``` -------------------------------- ### Specify Include Directories Source: https://github.com/paceholder/nodeeditor/blob/master/test/CMakeLists.txt Configures the include paths for the 'test_nodes' target. It specifies that the 'include' directory should be searched for header files during compilation. ```cmake target_include_directories(test_nodes PRIVATE include ) ``` -------------------------------- ### Configure Compiler Options for QtNodes (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Sets compiler-specific options for the QtNodes library, including warning levels and error flags for MSVC, GNU, and Clang compilers. This aims to improve code quality and catch potential issues during compilation. ```cmake target_compile_options(QtNodes PRIVATE $<$:/W4 /wd4127 /EHsc /utf-8> $<$:-Wall -Wextra> $<$:-Wall -Wextra -Werror> ) if(NOT "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC") # Clang-Cl on MSVC identifies as "Clang" but behaves more like MSVC: target_compile_options(QtNodes PRIVATE $<$:-Wall -Wextra> ) endif() ``` -------------------------------- ### Configure Qt Version Detection Source: https://github.com/paceholder/nodeeditor/blob/master/test/CMakeLists.txt Detects and configures the appropriate Qt version (Qt6 or Qt5) for the project. It uses a conditional statement to find the specified Qt components based on the USE_QT6 flag. ```cmake if (USE_QT6) find_package(Qt6 COMPONENTS Test) else() find_package(Qt5 COMPONENTS Test) endif() ``` -------------------------------- ### Set Output Directories for QtNodes (CMake) Source: https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt Configures the output directories for the QtNodes library artifacts (archive, library, runtime) relative to the build directory. This helps in organizing build outputs. ```cmake set_target_properties(QtNodes PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) ```