Skip to content

Keep registration order as order for context menu #163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
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