From 73d0374194d196a08003915efd6e3f753d1938d9 Mon Sep 17 00:00:00 2001 From: RobBuchanan <106311829+RobBuchananCompPhys@users.noreply.github.com> Date: Fri, 21 Aug 2026 12:08:35 +0100 Subject: [PATCH 1/3] refactor: Categorical `NodeRegistry` and updated QML Graph menu (#2582) --- src/gui2/models/enumOptionsModel.cpp | 1 - src/gui2/models/enumRegistry.cpp | 2 + src/gui2/models/graphModel.cpp | 2 +- src/gui2/models/nodeRegistryModel.cpp | 34 +++++- src/gui2/models/nodeRegistryModel.h | 7 ++ src/gui2/qml/nodeGraph/GraphView.qml | 143 +++++----------------- src/nodes/dotProduct.cpp | 2 +- src/nodes/exportDLPUtilsPDensData.cpp | 2 +- src/nodes/exportXYZTrajectory.cpp | 2 +- src/nodes/importXYData.cpp | 4 +- src/nodes/registry.cpp | 167 ++++++++++++++++---------- src/nodes/registry.h | 22 +++- 12 files changed, 198 insertions(+), 190 deletions(-) diff --git a/src/gui2/models/enumOptionsModel.cpp b/src/gui2/models/enumOptionsModel.cpp index 49e6123020..1a39baaa77 100644 --- a/src/gui2/models/enumOptionsModel.cpp +++ b/src/gui2/models/enumOptionsModel.cpp @@ -16,7 +16,6 @@ void EnumOptionsModel::setData(std::shared_ptr options) /* * QAbstractItemModel overrides */ - int EnumOptionsModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); diff --git a/src/gui2/models/enumRegistry.cpp b/src/gui2/models/enumRegistry.cpp index 44ae14bd47..7ca285e568 100644 --- a/src/gui2/models/enumRegistry.cpp +++ b/src/gui2/models/enumRegistry.cpp @@ -7,6 +7,7 @@ #include "math/windowFunction.h" #include "nodes/gr.h" #include "nodes/md.h" +#include "nodes/registry.h" std::map> EnumRegistry::options_; @@ -35,6 +36,7 @@ void EnumRegistry::instantiateOptions() }; options_ = {{typeid(StructureFactors::NormalisationType), wrap(StructureFactors::normalisationTypes())}, + {typeid(NodeRegistry::Category), wrap(NodeRegistry::category())}, {typeid(GRNode::PartialsMethod), wrap(GRNode::partialsMethods())}, {typeid(MDNode::TimestepType), wrap(MDNode::timestepType())}, {typeid(WindowFunction::Form), wrap(WindowFunction::forms())}}; diff --git a/src/gui2/models/graphModel.cpp b/src/gui2/models/graphModel.cpp index 57abf9d978..b8f752b5a1 100644 --- a/src/gui2/models/graphModel.cpp +++ b/src/gui2/models/graphModel.cpp @@ -126,7 +126,7 @@ void GraphModel::emplace_back(int x, int y, QVariant type, std::string name) node->x = x; node->y = y; auto &item = wrapped_.emplace_back(*node); - item.rawValue().setName(name); + item.rawValue().setName(name.toStdString()); nodes_.endInsertRows(); graphChanged(); } diff --git a/src/gui2/models/nodeRegistryModel.cpp b/src/gui2/models/nodeRegistryModel.cpp index c3cf6a58bc..cdbb48c9e4 100644 --- a/src/gui2/models/nodeRegistryModel.cpp +++ b/src/gui2/models/nodeRegistryModel.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2026 Team Dissolve and contributors #include "gui2/models/nodeRegistryModel.h" +#include "enumRegistry.h" #include "nodes/dissolve.h" NodeRegistryModel::NodeRegistryModel(QObject *parent) @@ -42,16 +43,43 @@ int &NodeRegistryModel::tally(QString nodeType) return entries_[idx].tally; } -// Instantiate node from registry -void NodeRegistryModel::instantiateNode(int x, int y, QVariant type) +// Return node names by category +QList NodeRegistryModel::nodeNames(QString category) +{ + QList names; + auto categoryEnum = NodeRegistry::category().enumeration(category.toStdString()); + auto nodes = NodeRegistry::categoricalProducers_; + for (const auto &[name, _] : nodes[categoryEnum]) + { + auto nodeName = QString::fromStdString(std::string(name)); + auto descriptionIt = std::find_if(entries_.begin(), entries_.end(), + [&nodeName](const auto &entry) { return std::get<0>(entry) == nodeName; }); + auto descriptionIdx = std::distance(entries_.begin(), descriptionIt); + auto nodeDescription = std::get<1>(entries_[descriptionIdx]); + QVariantMap nodeInfo; + nodeInfo[QString::fromStdString("name")] = nodeName; + nodeInfo[QString::fromStdString("description")] = nodeDescription; + names.push_back(nodeInfo); + } + return names; +} + +// Return the enum options for the node categories +EnumOptionsModel *NodeRegistryModel::categories() { return EnumRegistry::options(typeid(NodeRegistry::Category)).get(); } + +// Return a unique default node name for a given node type +QString NodeRegistryModel::uniqueNodeName(QVariant type) { increment(type.toString()); const auto count = tally(type.toString()); std::string prefix = type.toString().toStdString() + "_"; auto name = prefix + std::format("{}", count); - graphModel_->emplace_back(x, y, type, name); + return QString::fromStdString(name); } +// Instantiate node from registry +void NodeRegistryModel::instantiateNode(int x, int y, QVariant type) { graphModel_->emplace_back(x, y, type, uniqueNodeName(type), true); } + // Set the graph model void NodeRegistryModel::setGraphModel(GraphModel *graphModel) { diff --git a/src/gui2/models/nodeRegistryModel.h b/src/gui2/models/nodeRegistryModel.h index aba50ed03b..f128b43947 100644 --- a/src/gui2/models/nodeRegistryModel.h +++ b/src/gui2/models/nodeRegistryModel.h @@ -3,6 +3,7 @@ #pragma once +#include "enumOptionsModel.h" #include "gui2/models/graphModel.h" #include "nodes/registry.h" #include @@ -55,6 +56,12 @@ class NodeRegistryModel : public QAbstractListModel GraphModel *graphModel_{nullptr}; public: + // Return a unique default node name for a given node type + Q_INVOKABLE QString uniqueNodeName(QVariant type); + // Return node names by category + Q_INVOKABLE QList nodeNames(QString category); + // Return the enum options for the node categories + Q_INVOKABLE EnumOptionsModel *categories(); // Instantiate node from registry Q_INVOKABLE void instantiateNode(int x, int y, QVariant type); // Set the graph model diff --git a/src/gui2/qml/nodeGraph/GraphView.qml b/src/gui2/qml/nodeGraph/GraphView.qml index 23d6e05930..7057fc0d56 100644 --- a/src/gui2/qml/nodeGraph/GraphView.qml +++ b/src/gui2/qml/nodeGraph/GraphView.qml @@ -15,7 +15,6 @@ Pane { Component.onCompleted: nodeRegistry.setGraphModel(rootGraphModel); - /* MouseArea { id: ctxMenuCatcher @@ -24,133 +23,51 @@ Pane { onClicked: contextMenu.popup() + property point mousePos: Qt.point(ctxMenuCatcher.mouseX, ctxMenuCatcher.mouseY) + Menu { id: contextMenu - Menu { - title: "Math" - - MenuItem { - text: "Add" - - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "Add", "New Node") - } - MenuItem { - text: "Derivative" - - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "Derivative", "New Node") - } - MenuItem { - text: "Dot Product" - - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "DotProduct", "New Node") - } - MenuItem { - text: "Integrator" - - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "Integrator", "New Node") - } - MenuItem { - text: "Multiply" - - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "Multiply", "New Node") - } - MenuItem { - text: "Number" + Repeater { + model: nodeRegistry.categories() - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "Number", "New Number") - } - MenuItem { - text: "Subtract" - - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "Subtract", "New Node") - } - MenuItem { - text: "Vec3Assembly" + delegate: Item { + id: menuDelegateItem + required property var display + property Menu innerMenu: innerMenuComponent.createObject(parent) - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "Vec3Assembly", "New Node") - } - MenuItem { - text: "Vec3Decompostion" + Component { + id: innerMenuComponent - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "Vec3Decomposition", "New Node") - } - } - Menu { - title: "Action" + Menu { + id: nodeCategoryMenu - MenuItem { - text: "Atomic MC" + title: menuDelegateItem.display - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "AtomicMC", "New Node") - } - MenuItem { - text: "G(r)" + Repeater { + model: nodeRegistry.nodeNames(menuDelegateItem.display) - onClicked: rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "GR", "New Node") + delegate: MenuItem { + required property var modelData + text: modelData.name + onClicked: graphRoot.rootGraphModel.emplace_back(ctxMenuCatcher.mousePos.x, ctxMenuCatcher.mousePos.y, modelData.name, nodeRegistry.uniqueNodeName(modelData.name), false) + ToolTip.text: modelData.description + ToolTip.visible: hovered + ToolTip.delay: 500 + } + } + } + } } - MenuItem { - text: "Insert" - - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "Insert", "New Node") + onItemAdded: (index, item) => { + contextMenu.addMenu(item.innerMenu) } - MenuItem { - text: "Molecular Dynamics" - - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "MD", "New Node") - } - MenuItem { - text: "S(q)" - - onClicked: rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "SQ", "New Node") - } - } - Menu { - title: "Data" - - MenuItem { - text: "Atomic Species" - - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "AtomicSpecies", "New Node") - } - MenuItem { - text: "Configuration" - - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "Configuration", "New Node") - } - MenuItem { - text: "Forcefield" - - onClicked: forcefieldDialog.open() - - ForcefieldDialog { - id: forcefieldDialog - - graphModel: graphRoot.rootGraphModel - posx: Math.round(ctxMenuCatcher.mouseX) - posy: Math.round(ctxMenuCatcher.mouseY) - } - } - MenuItem { - text: "Graph" - - onClicked: graphRoot.rootGraphModel.emplace_back(Math.round(ctxMenuCatcher.mouseX), Math.round(ctxMenuCatcher.mouseY), "Graph", "New Graph") - } - MenuItem { - text: "Species" - - onClicked: speciesDialog.open() - - SpeciesDialog { - id: speciesDialog - - graphModel: graphRoot.rootGraphModel - } + onItemRemoved: (index, item) => { + contextMenu.removeMenu(item.innerMenu) } } } } - */ // Edge connections Repeater { model: graphRoot.parameterEndPointsModel diff --git a/src/nodes/dotProduct.cpp b/src/nodes/dotProduct.cpp index ff9c7e241c..2df6dcf201 100644 --- a/src/nodes/dotProduct.cpp +++ b/src/nodes/dotProduct.cpp @@ -15,7 +15,7 @@ DotProductNode::DotProductNode(Graph *parentGraph) : Node(parentGraph) */ // Return type of the node -std::string_view DotProductNode::type() const { return "Dot Product"; } +std::string_view DotProductNode::type() const { return "DotProduct"; } // Return short summary of the node's purpose std::string_view DotProductNode::summary() const { return "Compute the dot product of vectors u and v"; } diff --git a/src/nodes/exportDLPUtilsPDensData.cpp b/src/nodes/exportDLPUtilsPDensData.cpp index 513e6196a0..eabdf6696e 100644 --- a/src/nodes/exportDLPUtilsPDensData.cpp +++ b/src/nodes/exportDLPUtilsPDensData.cpp @@ -17,7 +17,7 @@ ExportDLPUtilsPDensDataNode::ExportDLPUtilsPDensDataNode(Graph *parentGraph) : N */ // Return type of the node -std::string_view ExportDLPUtilsPDensDataNode::type() const { return "ExportPDensData"; } +std::string_view ExportDLPUtilsPDensDataNode::type() const { return "ExportDLPUtilsPDensData"; } // Return short summary of the node's purpose std::string_view ExportDLPUtilsPDensDataNode::summary() const { return "Export 3D data in DLPUtils PDens format"; } diff --git a/src/nodes/exportXYZTrajectory.cpp b/src/nodes/exportXYZTrajectory.cpp index 6eb8fc9a69..7a75cef52f 100644 --- a/src/nodes/exportXYZTrajectory.cpp +++ b/src/nodes/exportXYZTrajectory.cpp @@ -21,7 +21,7 @@ ExportXYZTrajectoryNode::ExportXYZTrajectoryNode(Graph *parentGraph) : Node(pare */ // Return type of the node -std::string_view ExportXYZTrajectoryNode::type() const { return "ExportTrajectory"; } +std::string_view ExportXYZTrajectoryNode::type() const { return "ExportXYZTrajectory"; } // Return short summary of the node's purpose std::string_view ExportXYZTrajectoryNode::summary() const diff --git a/src/nodes/importXYData.cpp b/src/nodes/importXYData.cpp index fa06e4ffdf..766990e1e1 100644 --- a/src/nodes/importXYData.cpp +++ b/src/nodes/importXYData.cpp @@ -30,10 +30,10 @@ ImportXYDataNode::ImportXYDataNode(Graph *parentGraph) : Node(parentGraph) */ // Return type of the node -std::string_view ImportXYDataNode::type() const { return "Data1DImport"; } +std::string_view ImportXYDataNode::type() const { return "ImportXYData"; } // Return short summary of the node's purpose -std::string_view ImportXYDataNode::summary() const { return "Import 1D data"; } +std::string_view ImportXYDataNode::summary() const { return "Import 1D (XY) data"; } /* * Processing diff --git a/src/nodes/registry.cpp b/src/nodes/registry.cpp index 62baf23e5b..0fcf5bb828 100644 --- a/src/nodes/registry.cpp +++ b/src/nodes/registry.cpp @@ -68,15 +68,112 @@ #include #include -// Static Singletons -std::map NodeRegistry::producers_; - // Makes unique pointer to derived node instance template NodeProducer makeDerivedNode() { return [=](Graph *parent) -> std::unique_ptr { return std::make_unique(parent); }; } +// Static Singletons +const std::map NodeRegistry::categoricalProducers_{ + {Action, + { + {"AtomicMC", makeDerivedNode()}, + {"GR", makeDerivedNode()}, + {"InsertRandom", makeDerivedNode()}, + {"Instantiate", makeDerivedNode()}, + {"MD", makeDerivedNode()}, + {"SQ", makeDerivedNode()}, + }}, + {Data, + {{"Configuration", makeDerivedNode()}, + {"Forcefield", makeDerivedNode()}, + {"Species", makeDerivedNode()}}}, + {Export, + {{"ExportBlockData", makeDerivedNode()}, + {"ExportData", makeDerivedNode()}, + {"ExportDLPUtilsPDensData", makeDerivedNode()}, + {"ExportDLPOLYConfiguration", makeDerivedNode()}, + {"ExportXYZTrajectory", makeDerivedNode()}, + {"ExportXYZConfiguration", makeDerivedNode()}}}, + {Graphs, {{"Iterator", makeDerivedNode()}, {"Graph", makeDerivedNode()}}}, + {Import, + {{"ImportCIFStructure", makeDerivedNode()}, + {"ImportDLPOLYStructure", makeDerivedNode()}, + {"ImportDLPOLYTrajectory", makeDerivedNode()}, + {"ImportDLPUtilsPDens", makeDerivedNode()}, + {"ImportDLPUtilsSurface", makeDerivedNode()}, + {"ImportEPSRAtoStructure", makeDerivedNode()}, + {"ImportMoscitoStructure", makeDerivedNode()}, + {"ImportXYData", makeDerivedNode()}, + {"ImportXYZStructure", makeDerivedNode()}, + {"ImportXYZTrajectory", makeDerivedNode()}}}, + {Math, + {{"Add", makeDerivedNode()}, + {"Derivative", makeDerivedNode()}, + {"DotProduct", makeDerivedNode()}, + {"Integrator", makeDerivedNode()}, + {"Multiply", makeDerivedNode()}, + {"Number", makeDerivedNode()}, + {"Subtract", makeDerivedNode()}, + {"Vector3Assemble", makeDerivedNode()}, + {"Vector3Decompose", makeDerivedNode()}}}, + {Other, + {{"Angle", makeDerivedNode()}, + {"AxisAngle", makeDerivedNode()}, + {"AverageMolecule", makeDerivedNode()}, + {"Bragg", makeDerivedNode()}, + {"CalculateBonding", makeDerivedNode()}, + {"ClearBonding", makeDerivedNode()}, + {"DAngle", makeDerivedNode()}, + {"DetectMolecules", makeDerivedNode()}, + {"Energy", makeDerivedNode()}, + {"EPSR", makeDerivedNode()}, + {"HistogramCN", makeDerivedNode()}, + {"IntraAngle", makeDerivedNode()}, + {"IntraDistance", makeDerivedNode()}, + {"IntraMC", makeDerivedNode()}, + {"MC", makeDerivedNode()}, + {"ModifierOSites", makeDerivedNode()}, + {"MoleculeTorsion", makeDerivedNode()}, + {"NeutronSQ", makeDerivedNode()}, + {"OrientedSDF", makeDerivedNode()}, + {"QSpecies", makeDerivedNode()}, + {"SDF", makeDerivedNode()}, + {"SetBox", makeDerivedNode()}, + {"SetCoordinates", makeDerivedNode()}, + {"SiteRDF", makeDerivedNode()}, + {"SupercellConfiguration", makeDerivedNode()}, + {"XRaySQ", makeDerivedNode()}, + {"VoxelDensity", makeDerivedNode()}}}}; + +ProducerMap NodeRegistry::producers_; + +// Return enum option info for Category +EnumOptions NodeRegistry::category() +{ + return EnumOptions("Category", { + {Category::Action, "Action"}, + {Category::Data, "Data"}, + {Category::Export, "Export"}, + {Category::Graphs, "Graphs"}, + {Category::Import, "Import"}, + {Category::Math, "Math"}, + {Category::Other, "Other (TODO: finish categories)"}, + }); +} +EnumOptions getEnumOptions(NodeRegistry::Category) { return NodeRegistry::category(); } + +// Remove categories from categorial node producer map, returning a 'flat' producer map +ProducerMap NodeRegistry::decategoriseProducers() +{ + ProducerMap producers; + for (const auto &[_, map] : categoricalProducers_) + producers.insert(map.begin(), map.end()); + + return producers; +} + // Instantiate Node Producers void NodeRegistry::instantiateNodeProducers() { @@ -84,69 +181,7 @@ void NodeRegistry::instantiateNodeProducers() if (!producers_.empty()) return; - producers_ = {{"Add", makeDerivedNode()}, - {"Angle", makeDerivedNode()}, - {"AxisAngle", makeDerivedNode()}, - {"AtomicMC", makeDerivedNode()}, - {"AverageMolecule", makeDerivedNode()}, - {"Bragg", makeDerivedNode()}, - {"CalculateBonding", makeDerivedNode()}, - {"ClearBonding", makeDerivedNode()}, - {"Configuration", makeDerivedNode()}, - {"ImportCIFStructure", makeDerivedNode()}, - {"DAngle", makeDerivedNode()}, - {"Derivative", makeDerivedNode()}, - {"DetectMolecules", makeDerivedNode()}, - {"DotProduct", makeDerivedNode()}, - {"Energy", makeDerivedNode()}, - {"EPSR", makeDerivedNode()}, - {"ExportBlockData", makeDerivedNode()}, - {"ExportData", makeDerivedNode()}, - {"ExportDLPUtilsPDensData", makeDerivedNode()}, - {"ExportDLPOLYConfiguration", makeDerivedNode()}, - {"ExportXYZTrajectory", makeDerivedNode()}, - {"ExportXYZConfiguration", makeDerivedNode()}, - {"Forcefield", makeDerivedNode()}, - {"Graph", makeDerivedNode()}, - {"GR", makeDerivedNode()}, - {"HistogramCN", makeDerivedNode()}, - {"ImportDLPOLYStructure", makeDerivedNode()}, - {"ImportDLPOLYTrajectory", makeDerivedNode()}, - {"ImportDLPUtilsPDens", makeDerivedNode()}, - {"ImportDLPUtilsSurface", makeDerivedNode()}, - {"ImportEPSRAtoStructure", makeDerivedNode()}, - {"ImportMoscitoStructure", makeDerivedNode()}, - {"ImportXYData", makeDerivedNode()}, - {"ImportXYZStructure", makeDerivedNode()}, - {"ImportXYZTrajectory", makeDerivedNode()}, - {"InsertRandom", makeDerivedNode()}, - {"Instantiate", makeDerivedNode()}, - {"Integrator", makeDerivedNode()}, - {"IntraAngle", makeDerivedNode()}, - {"IntraDistance", makeDerivedNode()}, - {"IntraMC", makeDerivedNode()}, - {"Iterator", makeDerivedNode()}, - {"MC", makeDerivedNode()}, - {"MD", makeDerivedNode()}, - {"ModifierOSites", makeDerivedNode()}, - {"MoleculeTorsion", makeDerivedNode()}, - {"Multiply", makeDerivedNode()}, - {"NeutronSQ", makeDerivedNode()}, - {"Number", makeDerivedNode()}, - {"OrientedSDF", makeDerivedNode()}, - {"QSpecies", makeDerivedNode()}, - {"SDF", makeDerivedNode()}, - {"SetBox", makeDerivedNode()}, - {"SetCoordinates", makeDerivedNode()}, - {"SiteRDF", makeDerivedNode()}, - {"SQ", makeDerivedNode()}, - {"Species", makeDerivedNode()}, - {"Subtract", makeDerivedNode()}, - {"ReplicatedConfiguration", makeDerivedNode()}, - {"Vector3Assemble", makeDerivedNode()}, - {"Vector3Decompose", makeDerivedNode()}, - {"XRaySQ", makeDerivedNode()}, - {"VoxelDensity", makeDerivedNode()}}; + producers_ = decategoriseProducers(); } // Check whether the supplied node type is known diff --git a/src/nodes/registry.h b/src/nodes/registry.h index 4cbddf0b50..cc94694b21 100644 --- a/src/nodes/registry.h +++ b/src/nodes/registry.h @@ -7,15 +7,35 @@ #include using NodeProducer = std::function(Graph *parent)>; +using ProducerMap = std::map; // Registry of all Producible Node Types class NodeRegistry { + public: + enum Category + { + Action, + Data, + Export, + Graphs, + Import, + Math, + Other + }; + // Return enum option info for Category + static EnumOptions category(); + + public: + static const std::map categoricalProducers_; + private: // Available Node producers - static std::map producers_; + static ProducerMap producers_; private: + // Remove categories from categorial node producer map, returning a 'flat' producer map + static ProducerMap decategoriseProducers(); // Instantiate Node Producers static void instantiateNodeProducers(); From 1087d5a4a5073118127590eec564ae8cbd64bafc Mon Sep 17 00:00:00 2001 From: RobBuchanan Date: Mon, 21 Sep 2026 10:52:48 +0100 Subject: [PATCH 2/3] address pr comments and fix a couple of rebase related problems --- src/gui2/models/graphModel.cpp | 2 +- src/gui2/models/nodeRegistryModel.cpp | 12 +++++++----- src/nodes/registry.cpp | 3 +-- src/nodes/registry.h | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/gui2/models/graphModel.cpp b/src/gui2/models/graphModel.cpp index b8f752b5a1..57abf9d978 100644 --- a/src/gui2/models/graphModel.cpp +++ b/src/gui2/models/graphModel.cpp @@ -126,7 +126,7 @@ void GraphModel::emplace_back(int x, int y, QVariant type, std::string name) node->x = x; node->y = y; auto &item = wrapped_.emplace_back(*node); - item.rawValue().setName(name.toStdString()); + item.rawValue().setName(name); nodes_.endInsertRows(); graphChanged(); } diff --git a/src/gui2/models/nodeRegistryModel.cpp b/src/gui2/models/nodeRegistryModel.cpp index cdbb48c9e4..a39e6770df 100644 --- a/src/gui2/models/nodeRegistryModel.cpp +++ b/src/gui2/models/nodeRegistryModel.cpp @@ -52,13 +52,12 @@ QList NodeRegistryModel::nodeNames(QString category) for (const auto &[name, _] : nodes[categoryEnum]) { auto nodeName = QString::fromStdString(std::string(name)); - auto descriptionIt = std::find_if(entries_.begin(), entries_.end(), - [&nodeName](const auto &entry) { return std::get<0>(entry) == nodeName; }); + auto descriptionIt = + std::find_if(entries_.begin(), entries_.end(), [&nodeName](const auto &entry) { return entry.name == nodeName; }); auto descriptionIdx = std::distance(entries_.begin(), descriptionIt); - auto nodeDescription = std::get<1>(entries_[descriptionIdx]); QVariantMap nodeInfo; nodeInfo[QString::fromStdString("name")] = nodeName; - nodeInfo[QString::fromStdString("description")] = nodeDescription; + nodeInfo[QString::fromStdString("description")] = entries_[descriptionIdx].description; names.push_back(nodeInfo); } return names; @@ -78,7 +77,10 @@ QString NodeRegistryModel::uniqueNodeName(QVariant type) } // Instantiate node from registry -void NodeRegistryModel::instantiateNode(int x, int y, QVariant type) { graphModel_->emplace_back(x, y, type, uniqueNodeName(type), true); } +void NodeRegistryModel::instantiateNode(int x, int y, QVariant type) +{ + graphModel_->emplace_back(x, y, type, uniqueNodeName(type).toStdString()); +} // Set the graph model void NodeRegistryModel::setGraphModel(GraphModel *graphModel) diff --git a/src/nodes/registry.cpp b/src/nodes/registry.cpp index 0fcf5bb828..0df06bf74d 100644 --- a/src/nodes/registry.cpp +++ b/src/nodes/registry.cpp @@ -143,7 +143,6 @@ const std::map NodeRegistry::categoricalPro {"SetBox", makeDerivedNode()}, {"SetCoordinates", makeDerivedNode()}, {"SiteRDF", makeDerivedNode()}, - {"SupercellConfiguration", makeDerivedNode()}, {"XRaySQ", makeDerivedNode()}, {"VoxelDensity", makeDerivedNode()}}}}; @@ -164,7 +163,7 @@ EnumOptions NodeRegistry::category() } EnumOptions getEnumOptions(NodeRegistry::Category) { return NodeRegistry::category(); } -// Remove categories from categorial node producer map, returning a 'flat' producer map +// Remove categories from categorical node producer map, returning a 'flat' producer map ProducerMap NodeRegistry::decategoriseProducers() { ProducerMap producers; diff --git a/src/nodes/registry.h b/src/nodes/registry.h index cc94694b21..12959fa92d 100644 --- a/src/nodes/registry.h +++ b/src/nodes/registry.h @@ -34,7 +34,7 @@ class NodeRegistry static ProducerMap producers_; private: - // Remove categories from categorial node producer map, returning a 'flat' producer map + // Remove categories from categorical node producer map, returning a 'flat' producer map static ProducerMap decategoriseProducers(); // Instantiate Node Producers static void instantiateNodeProducers(); From d8fb8d6d5203dcae9880c822448bbec95b88600a Mon Sep 17 00:00:00 2001 From: RobBuchanan Date: Tue, 22 Sep 2026 10:04:32 +0100 Subject: [PATCH 3/3] add missing node --- src/nodes/registry.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nodes/registry.cpp b/src/nodes/registry.cpp index 0df06bf74d..6f6eba8867 100644 --- a/src/nodes/registry.cpp +++ b/src/nodes/registry.cpp @@ -139,6 +139,7 @@ const std::map NodeRegistry::categoricalPro {"NeutronSQ", makeDerivedNode()}, {"OrientedSDF", makeDerivedNode()}, {"QSpecies", makeDerivedNode()}, + {"ReplicatedConfiguration", makeDerivedNode()}, {"SDF", makeDerivedNode()}, {"SetBox", makeDerivedNode()}, {"SetCoordinates", makeDerivedNode()},