Skip to content
Open
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ set(CPP_SOURCE_FILES
src/FlowScene.cpp
src/FlowView.cpp
src/FlowViewStyle.cpp
src/ModelSelectionWidget.cpp
src/Node.cpp
src/NodeConnectionInteraction.cpp
src/NodeDataModel.cpp
Expand Down
30 changes: 26 additions & 4 deletions include/nodes/internal/DataModelRegistry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ class NODE_EDITOR_PUBLIC DataModelRegistry
using RegistryItemCreator = std::function<RegistryItemPtr()>;
using RegisteredModelCreatorsMap = std::unordered_map<QString, RegistryItemCreator>;
using RegisteredModelsCategoryMap = std::unordered_map<QString, QString>;
using RegisteredModelsOrder = std::vector<QString>;
using CategoriesSet = std::set<QString>;
using CategoriesOrder = std::vector<QString>;

using RegisteredTypeConvertersMap = std::map<TypeConverterId, TypeConverter>;

Expand Down Expand Up @@ -82,10 +84,16 @@ class NODE_EDITOR_PUBLIC DataModelRegistry

RegisteredModelCreatorsMap const &registeredModelCreators() const;

RegisteredModelsOrder const& registeredModelsOrder() const;

RegisteredModelsCategoryMap const &registeredModelsCategoryAssociation() const;

CategoriesSet const &categories() const;

CategoriesOrder const &categoriesOrder() const;

void sortCategories();

TypeConverter getTypeConverter(NodeDataType const & d1,
NodeDataType const & d2) const;

Expand All @@ -97,6 +105,10 @@ class NODE_EDITOR_PUBLIC DataModelRegistry

RegisteredModelCreatorsMap _registeredItemCreators;

CategoriesOrder _categoriesOrder;

RegisteredModelsOrder _registeredModelsOrder;

RegisteredTypeConvertersMap _registeredTypeConverters;

private:
Expand Down Expand Up @@ -125,11 +137,16 @@ class NODE_EDITOR_PUBLIC DataModelRegistry
registerModelImpl(RegistryItemCreator creator, QString const &category )
{
const QString name = ModelType::Name();
if (_registeredItemCreators.count(name) == 0)
if (!_registeredItemCreators.count(name))
{
_registeredItemCreators[name] = std::move(creator);
_categories.insert(category);
_registeredModelsOrder.push_back(name);
_registeredModelsCategory[name] = category;

if (!_categories.count(category)) {
_categories.insert(category);
_categoriesOrder.push_back(category);
}
}
}

Expand All @@ -138,11 +155,16 @@ class NODE_EDITOR_PUBLIC DataModelRegistry
registerModelImpl(RegistryItemCreator creator, QString const &category )
{
const QString name = creator()->name();
if (_registeredItemCreators.count(name) == 0)
if (!_registeredItemCreators.count(name))
{
_registeredItemCreators[name] = std::move(creator);
_categories.insert(category);
_registeredModelsOrder.push_back(name);
_registeredModelsCategory[name] = category;

if (!_categories.count(category)) {
_categories.insert(category);
_categoriesOrder.push_back(category);
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions include/nodes/internal/FlowView.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#pragma once

#include <QtCore/QPoint>

#include <QtWidgets/QGraphicsView>
#include <QtWidgets/QTreeWidget>

#include "Export.hpp"

Expand Down
23 changes: 23 additions & 0 deletions src/DataModelRegistry.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "DataModelRegistry.hpp"

#include <algorithm>

#include <QtCore/QFile>
#include <QtWidgets/QMessageBox>

Expand Down Expand Up @@ -30,6 +32,12 @@ registeredModelCreators() const
return _registeredItemCreators;
}

DataModelRegistry::RegisteredModelsOrder const &
DataModelRegistry::
registeredModelsOrder() const
{
return _registeredModelsOrder;
}

DataModelRegistry::RegisteredModelsCategoryMap const &
DataModelRegistry::
Expand All @@ -47,6 +55,21 @@ categories() const
}


DataModelRegistry::CategoriesOrder const &
DataModelRegistry::
categoriesOrder() const
{
return _categoriesOrder;
}

void
DataModelRegistry::
sortCategories()
{
std::sort(_categoriesOrder.begin(), _categoriesOrder.end());
}


TypeConverter
DataModelRegistry::
getTypeConverter(NodeDataType const & d1,
Expand Down
83 changes: 12 additions & 71 deletions src/FlowView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <QtOpenGL>
#include <QtWidgets>
#include <QtGlobal>

#include <QDebug>
#include <iostream>
Expand All @@ -22,9 +23,15 @@
#include "NodeGraphicsObject.hpp"
#include "ConnectionGraphicsObject.hpp"
#include "StyleCollection.hpp"
#include "ModelSelectionWidget.hpp"

using QtNodes::FlowView;
using QtNodes::FlowScene;
using QtNodes::ModelSelectionWidget;


static auto const SkipText = QStringLiteral("skip me");


FlowView::
FlowView(QWidget *parent)
Expand Down Expand Up @@ -100,7 +107,7 @@ FlowView::setScene(FlowScene *scene)

void
FlowView::
contextMenuEvent(QContextMenuEvent *event)
contextMenuEvent(QContextMenuEvent* event)
{
if (itemAt(event->pos()))
{
Expand All @@ -110,56 +117,14 @@ contextMenuEvent(QContextMenuEvent *event)

QMenu modelMenu;

auto skipText = QStringLiteral("skip me");

//Add filterbox to the context menu
auto *txtBox = new QLineEdit(&modelMenu);

txtBox->setPlaceholderText(QStringLiteral("Filter"));
txtBox->setClearButtonEnabled(true);

auto *txtBoxAction = new QWidgetAction(&modelMenu);
txtBoxAction->setDefaultWidget(txtBox);

modelMenu.addAction(txtBoxAction);
auto* modelSelectionWidget = new ModelSelectionWidget(_scene->registry(), &modelMenu);

//Add result treeview to the context menu
auto *treeView = new QTreeWidget(&modelMenu);
treeView->header()->close();

auto *treeViewAction = new QWidgetAction(&modelMenu);
treeViewAction->setDefaultWidget(treeView);

modelMenu.addAction(treeViewAction);

QMap<QString, QTreeWidgetItem*> topLevelItems;
for (auto const &cat : _scene->registry().categories())
for (QAction* action : modelSelectionWidget->actions())
{
auto item = new QTreeWidgetItem(treeView);
item->setText(0, cat);
item->setData(0, Qt::UserRole, skipText);
topLevelItems[cat] = item;
modelMenu.addAction(action);
}

for (auto const &assoc : _scene->registry().registeredModelsCategoryAssociation())
{
auto parent = topLevelItems[assoc.second];
auto item = new QTreeWidgetItem(parent);
item->setText(0, assoc.first);
item->setData(0, Qt::UserRole, assoc.first);
}

treeView->expandAll();

connect(treeView, &QTreeWidget::itemClicked, [&](QTreeWidgetItem *item, int)
{
QString modelName = item->data(0, Qt::UserRole).toString();

if (modelName == skipText)
{
return;
}

connect(modelSelectionWidget, &ModelSelectionWidget::modelSelected, [&](QString modelName) {
auto type = _scene->registry().create(modelName);

if (type)
Expand All @@ -180,30 +145,6 @@ contextMenuEvent(QContextMenuEvent *event)
modelMenu.close();
});

//Setup filtering
connect(txtBox, &QLineEdit::textChanged, [&](const QString &text)
{
for (auto& topLvlItem : topLevelItems)
{
for (int i = 0; i < topLvlItem->childCount(); ++i)
{
auto child = topLvlItem->child(i);
auto modelName = child->data(0, Qt::UserRole).toString();
if (modelName.contains(text, Qt::CaseInsensitive))
{
child->setHidden(false);
}
else
{
child->setHidden(true);
}
}
}
});

// make sure the text box gets focus so the user doesn't have to click on it
txtBox->setFocus();

modelMenu.exec(event->globalPos());
}

Expand Down
102 changes: 102 additions & 0 deletions src/ModelSelectionWidget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include "ModelSelectionWidget.hpp"

#include <utility>

#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QTreeWidget>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidgetAction>

#include <nodes/DataModelRegistry>

using QtNodes::DataModelRegistry;
using QtNodes::ModelSelectionWidget;


static auto const SkipText = QStringLiteral("skip me");


ModelSelectionWidget::
ModelSelectionWidget(DataModelRegistry& registry, QWidget* parent)
: QWidget(parent)
{
auto* layout = new QVBoxLayout(this);
setLayout(layout);

// Add filterbox to the context menu
auto* filter = new QLineEdit(this);

filter->setPlaceholderText(QStringLiteral("Filter"));
filter->setClearButtonEnabled(true);

auto* filterAction = new QWidgetAction(this);
filterAction->setDefaultWidget(filter);

addAction(filterAction);
layout->addWidget(filter);

// Add result treeview to the context menu
auto* treeView = new QTreeWidget(this);
treeView->header()->close();

auto* treeViewAction = new QWidgetAction(this);
treeViewAction->setDefaultWidget(treeView);

addAction(treeViewAction);
layout->addWidget(treeView);

QMap<QString, QTreeWidgetItem*> topLevelItems;
for (auto const& cat : registry.categoriesOrder())
{
auto item = new QTreeWidgetItem(treeView);
item->setText(0, cat);
item->setData(0, Qt::UserRole, SkipText);
topLevelItems[cat] = item;
}

auto const& assocCategory = registry.registeredModelsCategoryAssociation();
for (auto const& name : registry.registeredModelsOrder())
{
auto topLevelParent = topLevelItems[assocCategory.at(name)];
auto item = new QTreeWidgetItem(topLevelParent);
item->setText(0, name);
item->setData(0, Qt::UserRole, name);
}

treeView->expandAll();

connect(treeView, &QTreeWidget::itemClicked, this, [this](QTreeWidgetItem* item) {
QString modelName = item->data(0, Qt::UserRole).toString();

if (modelName == SkipText)
{
return;
}

emit modelSelected(modelName);
});

// Setup filtering
connect(filter, &QLineEdit::textChanged, [topLevelItems = std::move(topLevelItems)](const QString& text) {
for (auto& topLvlItem : topLevelItems)
{
for (int i = 0; i < topLvlItem->childCount(); ++i)
{
auto child = topLvlItem->child(i);
auto modelName = child->data(0, Qt::UserRole).toString();
if (modelName.contains(text, Qt::CaseInsensitive))
{
child->setHidden(false);
}
else
{
child->setHidden(true);
}
}
}
});

// make sure the text box gets focus so the user doesn't have to click on it
filter->setFocus();
}
26 changes: 26 additions & 0 deletions src/ModelSelectionWidget.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <QtCore/QString>
#include <QtWidgets/QTreeWidgetItem>
#include <QtWidgets/QWidget>

#include "Export.hpp"

namespace QtNodes
{

class DataModelRegistry;

class NODE_EDITOR_PUBLIC ModelSelectionWidget : public QWidget
{
Q_OBJECT

public:
explicit ModelSelectionWidget(DataModelRegistry& registry, QWidget* parent = Q_NULLPTR);

signals:
void
modelSelected(QString modelName);
};

}
Loading