Skip to content
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

plugin extension #349

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ set(CPP_SOURCE_FILES
src/StyleCollection.cpp
src/UndoCommands.cpp
src/locateNode.cpp
src/PluginsManager.cpp
)

set(HPP_HEADER_FILES
Expand Down Expand Up @@ -128,6 +129,8 @@ set(HPP_HEADER_FILES
include/QtNodes/internal/Serializable.hpp
include/QtNodes/internal/Style.hpp
include/QtNodes/internal/StyleCollection.hpp
include/QtNodes/internal/PluginInterface.hpp
include/QtNodes/internal/PluginsManager.hpp
src/DefaultConnectionPainter.hpp
src/DefaultHorizontalNodeGeometry.hpp
src/DefaultNodePainter.hpp
Expand Down
2 changes: 2 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ add_subdirectory(dynamic_ports)

add_subdirectory(lock_nodes_and_connections)

add_subdirectory(plugins_load)

7 changes: 7 additions & 0 deletions examples/plugins_load/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
set(CPPS main.cpp)

add_executable(plugins_load ${CPPS})

target_link_libraries(plugins_load QtNodes)

add_subdirectory(plugins/plugin_text)
69 changes: 69 additions & 0 deletions examples/plugins_load/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <QApplication>
#include <QFileDialog>
#include <QMenuBar>
#include <QObject>
#include <QVBoxLayout>

#include <QtNodes/DataFlowGraphModel>
#include <QtNodes/DataFlowGraphicsScene>
#include <QtNodes/GraphicsView>
#include <QtNodes/NodeDelegateModelRegistry>
#include <QtNodes/PluginInterface>
#include <QtNodes/PluginsManager>

using QtNodes::ConnectionStyle;
using QtNodes::DataFlowGraphicsScene;
using QtNodes::DataFlowGraphModel;
using QtNodes::GraphicsView;
using QtNodes::NodeDelegateModelRegistry;
using QtNodes::PluginInterface;
using QtNodes::PluginsManager;

void loadPluginsFromFolder()
{
PluginsManager *pluginsManager = PluginsManager::instance();
std::shared_ptr<NodeDelegateModelRegistry> registry = pluginsManager->registry();

// load plugins
pluginsManager->loadPlugins(QDir::cleanPath(QCoreApplication::applicationDirPath()
+ QDir::separator() + "plugins"),
QStringList() << "*.node"
<< "*.data");

for (auto l : pluginsManager->loaders()) {
PluginInterface *plugin = qobject_cast<PluginInterface *>(l.second->instance());
if (!plugin)
continue;

plugin->registerDataModels(registry);
}
}

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

QWidget mainWidget;

// Load plugins and register models
loadPluginsFromFolder();

QVBoxLayout *l = new QVBoxLayout(&mainWidget);

DataFlowGraphModel dataFlowGraphModel(PluginsManager::instance()->registry());

auto scene = new DataFlowGraphicsScene(dataFlowGraphModel, &mainWidget);

auto view = new GraphicsView(scene);
l->addWidget(view);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);

QObject::connect(scene, &DataFlowGraphicsScene::sceneLoaded, view, &GraphicsView::centerScene);

mainWidget.setWindowTitle("Data Flow: Plugins Load");
mainWidget.resize(800, 600);
mainWidget.show();

return app.exec();
}
16 changes: 16 additions & 0 deletions examples/plugins_load/plugins/plugin_text/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
if(MSVC)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "$<TARGET_FILE_DIR:plugins_load>/plugins")
else()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "$<TARGET_FILE_DIR:plugins_load>/plugins")
endif()

file(GLOB_RECURSE CPPS ./*.cpp)
file(GLOB_RECURSE HPPS ./*.hpp)

add_library(plugin_text SHARED ${CPPS} ${HPPS})

target_link_libraries(plugin_text QtNodes)

target_compile_definitions(plugin_text PUBLIC NODE_EDITOR_SHARED)

set_target_properties(plugin_text PROPERTIES SUFFIX ".node")
22 changes: 22 additions & 0 deletions examples/plugins_load/plugins/plugin_text/PluginDefinition.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "PluginDefinition.hpp"

#include "TextModel.hpp"

Plugin *Plugin::_this_plugin = nullptr;

Plugin::Plugin()
{
_this_plugin = this;
}

Plugin::~Plugin()
{
// TODO: Unregister all models here
}

void Plugin::registerDataModels(std::shared_ptr<QtNodes::NodeDelegateModelRegistry> &reg)
{
assert(reg);

reg->registerModel<TextModel>();
}
34 changes: 34 additions & 0 deletions examples/plugins_load/plugins/plugin_text/PluginDefinition.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include <QObject>
#include <QtNodes/NodeDelegateModelRegistry>
#include <QtNodes/PluginInterface>

// This needs to be the same as the name of your project file ${PROJECT_NAME}
#ifdef plugin_text_EXPORTS
#define DLL_EXPORT Q_DECL_EXPORT
#else
#define DLL_EXPORT Q_DECL_IMPORT
#endif

#define PLUGIN_NAME "Text"

class DLL_EXPORT Plugin
: public QObject
, public QtNodes::PluginInterface
{
Q_OBJECT
Q_INTERFACES(QtNodes::PluginInterface)
Q_PLUGIN_METADATA(IID PLUGIN_NAME)

public:
Plugin();
~Plugin();

QString name() const override { return PLUGIN_NAME; };

void registerDataModels(std::shared_ptr<QtNodes::NodeDelegateModelRegistry> &reg) override;

private:
static Plugin *_this_plugin;
};
25 changes: 25 additions & 0 deletions examples/plugins_load/plugins/plugin_text/TextData.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <QtNodes/NodeData>

using QtNodes::NodeData;
using QtNodes::NodeDataType;

/// The class can potentially incapsulate any user data which
/// need to be transferred within the Node Editor graph
class TextData : public NodeData
{
public:
TextData() {}

TextData(QString const &text)
: _text(text)
{}

NodeDataType type() const override { return NodeDataType{"text", "Text"}; }

QString text() const { return _text; }

private:
QString _text;
};
66 changes: 66 additions & 0 deletions examples/plugins_load/plugins/plugin_text/TextModel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "TextModel.hpp"

#include <QtWidgets/QTextEdit>

TextModel::TextModel() {}

unsigned int TextModel::nPorts(PortType portType) const
{
unsigned int result = 1;

switch (portType) {
case PortType::In:
result = 1;
break;

case PortType::Out:
result = 1;

default:
break;
}

return result;
}

void TextModel::onTextEdited()
{
Q_EMIT dataUpdated(0);
}

NodeDataType TextModel::dataType(PortType, PortIndex) const
{
return TextData().type();
}

std::shared_ptr<NodeData> TextModel::outData(PortIndex const portIndex)
{
Q_UNUSED(portIndex);
return std::make_shared<TextData>(_textEdit->toPlainText());
}

QWidget *TextModel::embeddedWidget()
{
if (!_textEdit) {
_textEdit = new QTextEdit();

connect(_textEdit, &QTextEdit::textChanged, this, &TextModel::onTextEdited);
}

return _textEdit;
}

void TextModel::setInData(std::shared_ptr<NodeData> data, PortIndex const)
{
auto textData = std::dynamic_pointer_cast<TextData>(data);

QString inputText;

if (textData) {
inputText = textData->text();
} else {
inputText = "";
}

_textEdit->setText(inputText);
}
55 changes: 55 additions & 0 deletions examples/plugins_load/plugins/plugin_text/TextModel.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#pragma once

#include <QtCore/QObject>

#include "TextData.hpp"

#include <QtNodes/NodeDelegateModel>

#include <iostream>

using QtNodes::NodeData;
using QtNodes::NodeDelegateModel;
using QtNodes::PortIndex;
using QtNodes::PortType;

class QTextEdit;

/// The model dictates the number of inputs and outputs for the Node.
/// In this example it has no logic.
class TextModel : public NodeDelegateModel
{
Q_OBJECT

public:
TextModel();

public:
QString caption() const override { return QString("Text"); }

bool captionVisible() const override { return true; }

static QString Name() { return QString("Text"); }

QString name() const override { return TextModel::Name(); }

public:
unsigned int nPorts(PortType portType) const override;

NodeDataType dataType(PortType portType, PortIndex portIndex) const override;

std::shared_ptr<NodeData> outData(PortIndex const portIndex) override;

void setInData(std::shared_ptr<NodeData>, PortIndex const) override;

QWidget *embeddedWidget() override;

bool resizable() const override { return true; }

private Q_SLOTS:

void onTextEdited();

private:
QTextEdit *_textEdit = nullptr;
};
1 change: 1 addition & 0 deletions include/QtNodes/PluginInterface
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "internal/PluginInterface.hpp"
1 change: 1 addition & 0 deletions include/QtNodes/PluginsManager
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "internal/PluginsManager.hpp"
21 changes: 21 additions & 0 deletions include/QtNodes/internal/PluginInterface.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <QtPlugin>

namespace QtNodes {

class NodeDelegateModelRegistry;

class PluginInterface
{
public:
virtual ~PluginInterface() = default;

virtual QString name() const = 0;

virtual void registerDataModels(std::shared_ptr<QtNodes::NodeDelegateModelRegistry> &reg) = 0;
};

} // namespace QtNodes

Q_DECLARE_INTERFACE(QtNodes::PluginInterface, "QtNodes.PluginInterface/1.0")
Loading
Loading