Introduces context menu
First of all the context menu is not finished and introduced a bug with the panel. The ContextMenu spawns on a right click and enables the user to insert and later also, rename and view properties. The follwing changes where edited: - Context menu, Insert Nodes functionality for both panel and node editor - Creating factories to create Nodes, give the Document more power / properties, so that it is more central and opening various documents is easier later - The active document is handled by itself - Nodes have a new property "position_hint" to position them on node editor and panel - The method setPanel was removed and was replaced by the Panel::addVisual method - The class VisualContainer holds a new property "node" which is the visual node that is stored in the VisualContainer
This commit is contained in:
@@ -2,6 +2,7 @@ qt_add_executable(skui
|
||||
main.cpp
|
||||
skui.h skui.cpp
|
||||
mainwindow.h mainwindow.cpp mainwindow.ui
|
||||
context_menu.h context_menu.cpp
|
||||
document.h document.cpp
|
||||
../../libs/icons.qrc
|
||||
)
|
||||
|
||||
33
src/app/context_menu.cpp
Normal file
33
src/app/context_menu.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "context_menu.h"
|
||||
#include "document.h"
|
||||
|
||||
ContextMenu::ContextMenu(QWidget *parent, const Node *node, const QPoint spawn_position)
|
||||
: QMenu{parent}
|
||||
, m_spawn_position{spawn_position}
|
||||
{
|
||||
QAction *properties_action = new QAction("Properties", this);
|
||||
addAction(properties_action);
|
||||
|
||||
QAction *rename_action = new QAction("Rename...", this);
|
||||
addAction(rename_action);
|
||||
|
||||
QAction *delete_action = new QAction("Delete", this);
|
||||
addAction(delete_action);
|
||||
|
||||
QMenu *add_node_menu = addMenu("Add Node");
|
||||
addMenu(add_node_menu);
|
||||
loadNodesToMenu(add_node_menu);
|
||||
|
||||
exec(m_spawn_position);
|
||||
}
|
||||
|
||||
void ContextMenu::loadNodesToMenu(QMenu *menu)
|
||||
{
|
||||
for (const QString &node_name : Document::activeDocument()->availableNodes()) {
|
||||
QAction *node_action = new QAction(node_name, this);
|
||||
connect(node_action, &QAction::triggered, this, [this, node_name] {
|
||||
Document::activeDocument()->createNode(node_name, m_spawn_position);
|
||||
});
|
||||
menu->addAction(node_action);
|
||||
}
|
||||
}
|
||||
20
src/app/context_menu.h
Normal file
20
src/app/context_menu.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef CONTEXT_MENU_H
|
||||
#define CONTEXT_MENU_H
|
||||
|
||||
#include <QMenu>
|
||||
|
||||
#include "../node/node.h"
|
||||
|
||||
class ContextMenu : public QMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ContextMenu(QWidget *parent = nullptr, const Node *node = nullptr, const QPoint spawn_position = QPoint(0, 0));
|
||||
|
||||
private:
|
||||
void loadNodesToMenu(QMenu *menu);
|
||||
|
||||
const QPoint m_spawn_position;
|
||||
};
|
||||
|
||||
#endif // CONTEXT_MENU_H
|
||||
@@ -1,43 +1,39 @@
|
||||
#include "document.h"
|
||||
|
||||
Document::Document(QObject *parent, Panel *panel, NodeEditor *nodeeditor)
|
||||
Q_DECLARE_LOGGING_CATEGORY(document)
|
||||
Q_LOGGING_CATEGORY(document, "DOCUMENT")
|
||||
|
||||
Document *Document::s_active_document = nullptr;
|
||||
|
||||
Document::Document(QObject *parent)
|
||||
: QObject{parent}
|
||||
, m_panel(panel)
|
||||
, m_nodeeditor(nodeeditor)
|
||||
{}
|
||||
|
||||
Document::~Document() {}
|
||||
|
||||
QJsonObject Document::save()
|
||||
{
|
||||
return QJsonObject();
|
||||
m_panel = new Panel;
|
||||
m_nodeeditor = new NodeEditor;
|
||||
s_active_document = this;
|
||||
}
|
||||
|
||||
void Document::load(QJsonObject content)
|
||||
Document::~Document()
|
||||
{
|
||||
return;
|
||||
delete m_panel;
|
||||
delete m_nodeeditor;
|
||||
}
|
||||
|
||||
void Document::createVisual(VisualType type)
|
||||
QList<QString> Document::availableNodes() const
|
||||
{
|
||||
if (type == VisualType::Test) {
|
||||
Label *label = new Label(this);
|
||||
label->setPanel(m_panel, QPoint(200, 200));
|
||||
m_nodeeditor->addNode(label);
|
||||
} else if (type == VisualType::Slider) {
|
||||
Slider *slider = new Slider(this);
|
||||
slider->setPanel(m_panel, QPoint(400, 200));
|
||||
m_nodeeditor->addNode(slider);
|
||||
} else if (type == VisualType::SerialSend) {
|
||||
SerialSend *serialsend = new SerialSend(this);
|
||||
serialsend->setPanel(m_panel, QPoint(300, 300));
|
||||
m_nodeeditor->addNode(serialsend);
|
||||
} else if (type == VisualType::LineEdit) {
|
||||
LineEdit *line_edit = new LineEdit(this);
|
||||
line_edit->setPanel(m_panel, QPoint(100, 100));
|
||||
m_nodeeditor->addNode(line_edit);
|
||||
} else if (type == VisualType::TextCombine) {
|
||||
TextCombine *text_combine = new TextCombine(this);
|
||||
m_nodeeditor->addNode(text_combine);
|
||||
return m_node_factories.keys();
|
||||
}
|
||||
|
||||
void Document::createNode(const QString &name, const QPoint position_hint)
|
||||
{
|
||||
if (m_node_factories.contains(name)) {
|
||||
Node *node = m_node_factories[name]();
|
||||
node->setPositionHint(position_hint);
|
||||
m_nodeeditor->addNode(node);
|
||||
if (node->isVisual()) {
|
||||
m_panel->addVisual(static_cast<Visual *>(node));
|
||||
}
|
||||
} else {
|
||||
qWarning() << "No Node factory for name" << name << "found. Could not create node!";
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
#ifndef DOCUMENT_H
|
||||
#define DOCUMENT_H
|
||||
|
||||
#include <functional>
|
||||
#include <QJsonObject>
|
||||
#include <QLoggingCategory>
|
||||
#include <QObject>
|
||||
|
||||
#include "nodeeditor.h"
|
||||
@@ -12,26 +14,76 @@
|
||||
#include "nodes/textcombine.h"
|
||||
#include "panel.h"
|
||||
|
||||
enum class VisualType { Parent, Test, Slider, SerialSend, LineEdit, TextCombine };
|
||||
|
||||
/** @brief The Document class represents a document in the application.
|
||||
*
|
||||
* It manages the node editor and panel for the document.
|
||||
* The Document class also provides methods to create visual nodes and access the available node types.
|
||||
* There is always one active document in the application, which can be accessed via the static method activeDocument().
|
||||
*/
|
||||
class Document : QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Document(QObject *, Panel *, NodeEditor *);
|
||||
Document(QObject *parent = nullptr);
|
||||
~Document();
|
||||
|
||||
QJsonObject save();
|
||||
void load(QJsonObject);
|
||||
/** @brief Returns the active document
|
||||
*
|
||||
* This method returns a pointer to the active document.
|
||||
* The active document is the document that is currently being edited.
|
||||
*
|
||||
* @return A pointer to the active document.
|
||||
*/
|
||||
static Document *activeDocument() { return s_active_document; }
|
||||
|
||||
void createVisual(VisualType type);
|
||||
/** @brief Returns the panel of the document
|
||||
*
|
||||
* This method returns a pointer to the panel of the document.
|
||||
*
|
||||
* @return A pointer to the panel of the document.
|
||||
* @see Panel::Panel(QWidget *)
|
||||
*/
|
||||
Panel *panel() const { return m_panel; }
|
||||
|
||||
DisplayMode display_mode = DisplayMode::Run;
|
||||
/** @brief Returns the node editor of the document
|
||||
*
|
||||
* This method returns a pointer to the node editor of the document.
|
||||
*
|
||||
* @return A pointer to the node editor of the document.
|
||||
* @see NodeEditor
|
||||
*/
|
||||
NodeEditor *nodeEditor() const { return m_nodeeditor; }
|
||||
|
||||
/** @brief Returns the list of available node types
|
||||
*
|
||||
* This method returns a list of strings representing the types of nodes that can be created.
|
||||
*
|
||||
* @return A list of available node types.
|
||||
* @see Document::createVisual(const QString &name)
|
||||
*/
|
||||
QList<QString> availableNodes() const;
|
||||
|
||||
/** @brief Creates a node of the specified type
|
||||
*
|
||||
* This method creates a node of the specified type by the name and adds it to the node editor.
|
||||
*
|
||||
* @param name The type of the node to create.
|
||||
* @see Document::availableNodes()
|
||||
*/
|
||||
void createNode(const QString &name, const QPoint position_hint = QPoint(0, 0));
|
||||
|
||||
private:
|
||||
Panel *m_panel;
|
||||
NodeEditor *m_nodeeditor;
|
||||
const QMap<QString, std::function<Node *()>> m_node_factories
|
||||
= {{"Label", [this]() { return new Label(this); }},
|
||||
{"Slider", [this]() { return new Slider(this); }},
|
||||
{"SerialSend", [this]() { return new SerialSend(this); }},
|
||||
{"LineEdit", [this]() { return new LineEdit(this); }},
|
||||
{"TextCombine", [this]() { return new TextCombine(this); }}};
|
||||
|
||||
Panel *m_panel = nullptr;
|
||||
NodeEditor *m_nodeeditor = nullptr;
|
||||
static Document *s_active_document;
|
||||
};
|
||||
|
||||
#endif // DOCUMENT_H
|
||||
|
||||
@@ -17,21 +17,17 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
|
||||
setWindowIcon(QIcon(icon));
|
||||
|
||||
panel = new Panel;
|
||||
ui->tabWidget->addTab(panel, "Panel");
|
||||
|
||||
NodeEditor *nodeeditor = new NodeEditor;
|
||||
ui->tabWidget->addTab(nodeeditor, "Node Editor");
|
||||
ui->tabWidget->setCurrentWidget(nodeeditor);
|
||||
|
||||
focus_document = new Document(this, panel, nodeeditor);
|
||||
Document *new_document = new Document(this);
|
||||
ui->tabWidget->addTab(new_document->panel(), "Panel");
|
||||
ui->tabWidget->addTab(new_document->nodeEditor(), "Node Editor");
|
||||
ui->tabWidget->setCurrentWidget(new_document->nodeEditor());
|
||||
|
||||
loadInsertVisualMenu();
|
||||
loadDebugMenu();
|
||||
|
||||
loadAlignTools();
|
||||
|
||||
connect(this, &MainWindow::modeChanged, panel, &Panel::setMode);
|
||||
connect(this, &MainWindow::modeChanged, new_document->panel(), &Panel::setMode);
|
||||
//focus_document->createVisual(VisualType::Slider);
|
||||
}
|
||||
|
||||
@@ -42,22 +38,13 @@ MainWindow::~MainWindow()
|
||||
|
||||
void MainWindow::loadInsertVisualMenu()
|
||||
{
|
||||
const VisualMenuAction wrapped_actions[] = {
|
||||
{"Label", VisualType::Test},
|
||||
{"Slider", VisualType::Slider},
|
||||
{"SerialSend", VisualType::SerialSend},
|
||||
{"LineEdit", VisualType::LineEdit},
|
||||
{"TextCombine", VisualType::TextCombine},
|
||||
};
|
||||
|
||||
for (const VisualMenuAction &wraped_action : wrapped_actions) {
|
||||
QAction *menu_insert_action = new QAction(wraped_action.name);
|
||||
connect(menu_insert_action, &QAction::triggered, this, [this, wraped_action] {
|
||||
focus_document->createVisual(wraped_action.type);
|
||||
for (const QString &visual_name : Document::activeDocument()->availableNodes()) {
|
||||
QAction *menu_insert_action = new QAction(visual_name);
|
||||
connect(menu_insert_action, &QAction::triggered, this, [this, visual_name] {
|
||||
Document::activeDocument()->createNode(visual_name, mapToGlobal(QPoint(100, 200)));
|
||||
//connect(this, &MainWindow::modeChanged, visual, &Visual::setMode);
|
||||
});
|
||||
|
||||
menu_insert_action->setText(wraped_action.name);
|
||||
menu_insert_action->setText(visual_name);
|
||||
ui->menuInsertVisual->addAction(menu_insert_action);
|
||||
}
|
||||
}
|
||||
@@ -66,43 +53,9 @@ void MainWindow::loadDebugMenu()
|
||||
{
|
||||
#ifdef QT_DEBUG
|
||||
QMenu *debug_menu = menuBar()->addMenu("Debug");
|
||||
debug_menu->addAction("Insert routed Slider => Laber", this, [this]() {
|
||||
Slider *slider = new Slider(this);
|
||||
slider->setPanel(panel);
|
||||
Label *label = new Label(this);
|
||||
label->setPanel(panel);
|
||||
qDebug() << "Routing Slider to Label";
|
||||
qDebug() << slider->getInterfaces().first().routeTo(&label->getInterfaces().first());
|
||||
});
|
||||
debug_menu->addAction("Add Test Node", this, [this]() {
|
||||
focus_document->createVisual(VisualType::Slider);
|
||||
qDebug() << "Added test slider node via Document";
|
||||
});
|
||||
debug_menu->addAction("Add Label Node", this, [this]() {
|
||||
focus_document->createVisual(VisualType::Test); // Test creates Label
|
||||
qDebug() << "Added test label node via Document";
|
||||
});
|
||||
debug_menu->addAction("Add Label Node", this, [this]() {
|
||||
Label *test_label = new Label(this);
|
||||
test_label->setPanel(panel, QPoint(300, 100));
|
||||
// Find the nodeeditor from the tab widget
|
||||
for (int i = 0; i < ui->tabWidget->count(); ++i) {
|
||||
NodeEditor *nodeeditor = qobject_cast<NodeEditor *>(ui->tabWidget->widget(i));
|
||||
if (nodeeditor) {
|
||||
nodeeditor->addNode(test_label);
|
||||
qDebug() << "Added test label node to NodeEditor";
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
const QIcon MainWindow::loadIcon(const QString &identifier)
|
||||
{
|
||||
return QIcon("./assets/breeze_icon/" + identifier);
|
||||
}
|
||||
|
||||
void MainWindow::loadAlignTools()
|
||||
{
|
||||
const AlignTool align_tools[]
|
||||
@@ -123,23 +76,23 @@ void MainWindow::loadAlignTools()
|
||||
align_button->setToolTip(align_tool.tool_tip);
|
||||
|
||||
connect(align_button, &QPushButton::clicked, this, [this, align_tool] {
|
||||
panel->triggeredAlign(align_tool.direction);
|
||||
Document::activeDocument()->panel()->triggeredAlign(align_tool.direction);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_mode_changed_button_clicked()
|
||||
{
|
||||
if (focus_document->display_mode == DisplayMode::Run) {
|
||||
focus_document->display_mode = DisplayMode::Edit;
|
||||
if (m_display_mode == DisplayMode::Run) {
|
||||
m_display_mode = DisplayMode::Edit;
|
||||
ui->mode_changed_button->setText("Run Mode");
|
||||
qInfo(gui) << "Display mode changed to Edit";
|
||||
} else {
|
||||
focus_document->display_mode = DisplayMode::Run;
|
||||
m_display_mode = DisplayMode::Run;
|
||||
ui->mode_changed_button->setText("Edit Mode");
|
||||
qInfo(gui) << "Display mode to Run";
|
||||
qInfo(gui) << "Display mode changed to Run";
|
||||
}
|
||||
emit modeChanged(focus_document->display_mode);
|
||||
emit modeChanged(m_display_mode);
|
||||
}
|
||||
|
||||
bool MainWindow::event(QEvent *event)
|
||||
|
||||
@@ -14,12 +14,6 @@ class MainWindow;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
struct VisualMenuAction
|
||||
{
|
||||
QString name;
|
||||
VisualType type;
|
||||
};
|
||||
|
||||
struct AlignTool
|
||||
{
|
||||
QString tool_tip;
|
||||
@@ -35,8 +29,6 @@ public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
Document *focus_document;
|
||||
|
||||
protected:
|
||||
bool event(QEvent *);
|
||||
|
||||
@@ -49,11 +41,10 @@ private slots:
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
Panel *panel;
|
||||
|
||||
void loadInsertVisualMenu();
|
||||
void loadDebugMenu();
|
||||
void loadAlignTools();
|
||||
const QIcon loadIcon(const QString &);
|
||||
|
||||
DisplayMode m_display_mode = DisplayMode::Run;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
||||
@@ -29,4 +29,14 @@ void Node::config()
|
||||
setObjectName(instance_name);
|
||||
|
||||
qDebug() << "Created Viusal <" << instance_name << ">";
|
||||
}
|
||||
|
||||
void Node::setPositionHint(QPoint position_hint)
|
||||
{
|
||||
if (m_position_hint == position_hint) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_position_hint = position_hint;
|
||||
emit positionHintChanged(position_hint);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QPoint>
|
||||
#include <QVariant>
|
||||
|
||||
#include "interface.h"
|
||||
@@ -10,19 +11,78 @@
|
||||
class Node : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name MEMBER m_name)
|
||||
Q_PROPERTY(QPoint position_hint READ positionHint WRITE setPositionHint NOTIFY
|
||||
positionHintChanged MEMBER m_position_hint)
|
||||
|
||||
public:
|
||||
explicit Node(QObject *parent);
|
||||
|
||||
Q_PROPERTY(QString name MEMBER m_name)
|
||||
|
||||
void setInterfaces(const QList<Interface> &interfaces) { m_interfaces = interfaces; }
|
||||
/** @brief Get the list of interfaces
|
||||
*
|
||||
* This method returns the reference to the interfaces of the node.
|
||||
*
|
||||
* @return A reference to the list of interfaces.
|
||||
* @see getInterface()
|
||||
* @see Interface
|
||||
*/
|
||||
QList<Interface> &getInterfaces() { return m_interfaces; }
|
||||
|
||||
/** @brief Get an interface by its identifier
|
||||
*
|
||||
* This method returns a pointer to the interface with the given identifier, or nullptr if no such interface exists.
|
||||
*
|
||||
* @param identifier The identifier of the interface to retrieve.
|
||||
* @return A pointer to the interface with the given identifier, or nullptr if no such interface exists.
|
||||
* @see setInterfaces()
|
||||
* @see Interface
|
||||
*/
|
||||
Interface *getInterface(const QString &identifier);
|
||||
|
||||
/** @brief Checks if the node is a visual node
|
||||
*
|
||||
* This method returns true if the node is a visual node, false otherwise.
|
||||
* Nodes are no visual nodes by default, so this method is overridden by the visual base class.
|
||||
*
|
||||
* @return True if the node is a visual node, false otherwise.
|
||||
* @see Visual
|
||||
*/
|
||||
const virtual bool isVisual() const { return false; }
|
||||
|
||||
/** @brief Get the position hint
|
||||
*
|
||||
* This property is used to store the position hint of the node.
|
||||
* It is used to position the node in the node editor or panel.
|
||||
*
|
||||
* @return The position hint of the node.
|
||||
* @see setPositionHint()
|
||||
*/
|
||||
QPoint positionHint() const { return m_position_hint; }
|
||||
|
||||
/** @brief Set the position hint
|
||||
*
|
||||
* This property is used to store the position hint of the node.
|
||||
* It is used to position the node in the node editor or panel.
|
||||
*
|
||||
* @param position_hint The position hint of the node.
|
||||
* @see positionHint()
|
||||
*/
|
||||
void setPositionHint(QPoint position_hint);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @see getInterface()
|
||||
* @see Interface
|
||||
*/
|
||||
void changedInterfaceValue(const Interface &);
|
||||
|
||||
/**
|
||||
* @see setPositionHint()
|
||||
* @see positionHint()
|
||||
*/
|
||||
void positionHintChanged(const QPoint position_hint);
|
||||
|
||||
protected:
|
||||
/** @brief Set various configurations
|
||||
*
|
||||
@@ -33,9 +93,12 @@ protected:
|
||||
void config();
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
QWidget *m_nodeeditor = nullptr;
|
||||
|
||||
// Properties
|
||||
QString m_name = "Undefined";
|
||||
QPoint m_position_hint = QPoint(0, 0);
|
||||
|
||||
QList<Interface> m_interfaces;
|
||||
static QMap<QString, int> instance_counter;
|
||||
};
|
||||
|
||||
@@ -3,22 +3,20 @@
|
||||
Q_DECLARE_LOGGING_CATEGORY(visual)
|
||||
Q_LOGGING_CATEGORY(visual, "VISUAL")
|
||||
|
||||
|
||||
Visual::Visual(QObject *parent)
|
||||
: Node(parent)
|
||||
{
|
||||
qDebug() << this->metaObject()->className();
|
||||
}
|
||||
|
||||
void Visual::setPanel(QWidget *panel_widget, QPoint position)
|
||||
void Visual::setWidget(QWidget *widget)
|
||||
{
|
||||
if (panel_widget) {
|
||||
m_visual_container = new VisualContainer(panel_widget);
|
||||
m_visual_container->move(position);
|
||||
m_visual_container->show();
|
||||
m_visual_widget = paintWidget(m_visual_container);
|
||||
m_visual_widget->show();
|
||||
if (m_widget == widget) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_widget = widget;
|
||||
emit widgetChanged(widget);
|
||||
}
|
||||
|
||||
QWidget *Visual::paintWidget(VisualContainer *visual_container)
|
||||
@@ -29,4 +27,3 @@ QWidget *Visual::paintWidget(VisualContainer *visual_container)
|
||||
widget->setStyleSheet("background-color: orange; border: 1px solid gray;");
|
||||
return widget;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,18 +9,68 @@
|
||||
class Visual : public Node
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QWidget *widget READ widget WRITE setWidget NOTIFY widgetChanged MEMBER m_widget)
|
||||
|
||||
public:
|
||||
explicit Visual(QObject *parent = nullptr);
|
||||
virtual ~Visual() {};
|
||||
|
||||
void setPanel(QWidget *panel_widget, QPoint position = QPoint(0, 0));
|
||||
void setPanelPosition(QPoint);
|
||||
/** @brief Gets the widget associated with this visual node.
|
||||
*
|
||||
* This method returns the QWidget that is associated with this visual node.
|
||||
* The QWidget is a VisualContainer and is managed by the panel.
|
||||
*
|
||||
* @return The QWidget associated with this visual node.
|
||||
* @see setWidget()
|
||||
* @see VisualContainer
|
||||
* @see Panel::addVisual()
|
||||
*/
|
||||
QWidget *widget() const { return m_widget; }
|
||||
|
||||
/** @brief Sets the widget associated with this visual node.
|
||||
*
|
||||
* This method sets the QWidget that is associated with this visual node.
|
||||
* The QWidget is a VisualContainer and is managed by the panel.
|
||||
*
|
||||
* @param widget The QWidget to associate with this visual node.
|
||||
* @see widget()
|
||||
* @see VisualContainer
|
||||
* @see Panel::addVisual()
|
||||
*/
|
||||
void setWidget(QWidget *widget);
|
||||
|
||||
/** @brief Paints the visual node onto a VisualContainer.
|
||||
*
|
||||
* This method creates and returns a QWidget that represents the visual node.
|
||||
* It is the entry point for rendering content to the panel.
|
||||
* The QWidget is a child of the given VisualContainer and is styled to visually represent the node.
|
||||
*
|
||||
* @param parent The VisualContainer to which the visual node's widget will be added as a child.
|
||||
* @return A QWidget that visually represents the node, styled and ready to be displayed within the panel.
|
||||
* @see Panel
|
||||
* @see VisualContainer
|
||||
*/
|
||||
virtual QWidget *paintWidget(VisualContainer *parent);
|
||||
|
||||
/**
|
||||
* @brief Checks if the node is a visual node
|
||||
*
|
||||
* This method returns true.
|
||||
*
|
||||
* @return True, since this is a visual node.
|
||||
* @see Node::isVisual()
|
||||
*/
|
||||
const bool isVisual() const override { return true; }
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @see widget()
|
||||
* @see setWidget()
|
||||
*/
|
||||
void widgetChanged(QWidget *widget);
|
||||
|
||||
private:
|
||||
VisualContainer *m_visual_container = nullptr;
|
||||
QWidget *m_visual_widget = nullptr;
|
||||
QWidget *m_widget = nullptr;
|
||||
};
|
||||
|
||||
#endif // VISUAL_H
|
||||
@@ -3,7 +3,7 @@ qt_add_library(nodeeditor STATIC
|
||||
nodeeditor_scene.h nodeeditor_scene.cpp
|
||||
graphicsitems/node_graphicsitem.h graphicsitems/node_graphicsitem.cpp
|
||||
graphicsitems/pad.h graphicsitems/pad.cpp
|
||||
graphicsitems/cable.h graphicsitems/cable.cpp
|
||||
graphicsitems/cable.h graphicsitems/cable.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(nodeeditor PRIVATE Qt6::Widgets)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "nodeeditor.h"
|
||||
#include "../app/context_menu.h"
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(ne_view)
|
||||
Q_LOGGING_CATEGORY(ne_view, "NE_VIEW")
|
||||
@@ -21,7 +22,21 @@ NodeEditor::NodeEditor(QWidget *parent)
|
||||
|
||||
void NodeEditor::addNode(Node *node)
|
||||
{
|
||||
m_scene->addNode(node);
|
||||
QPoint relative_position_hint = mapFromGlobal(node->positionHint());
|
||||
m_scene->addNode(node, relative_position_hint);
|
||||
}
|
||||
|
||||
// We need to use the items method and cannot use itemAt() because
|
||||
// the top level item might be the active cable, because
|
||||
// Cabel have a maximum bounding box. This is because they can route "everywhere"
|
||||
NodeGraphicsItem *NodeEditor::getTopLevelNode(QPoint pos)
|
||||
{
|
||||
for (QGraphicsItem *item : items(pos)) {
|
||||
if (NodeGraphicsItem *node = qgraphicsitem_cast<NodeGraphicsItem *>(item)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NodeEditor::mousePressEvent(QMouseEvent *event)
|
||||
@@ -34,19 +49,20 @@ void NodeEditor::mousePressEvent(QMouseEvent *event)
|
||||
if (deselect_others) {
|
||||
scene()->clearSelection();
|
||||
}
|
||||
|
||||
// We need to use the items method and cannot use itemAt() because
|
||||
// the top level item might be the active cable, because
|
||||
// Cabel have a maximum bounding box. This is because they can route "everywhere"
|
||||
for (QGraphicsItem *item : items(event->pos())) {
|
||||
if (NodeGraphicsItem *node = qgraphicsitem_cast<NodeGraphicsItem *>(item)) {
|
||||
m_dragging = true;
|
||||
m_last_drag_pos = event->pos();
|
||||
node->setSelected(true);
|
||||
return;
|
||||
}
|
||||
if (NodeGraphicsItem *node = getTopLevelNode(event->pos())) {
|
||||
m_dragging = true;
|
||||
m_last_drag_pos = event->pos();
|
||||
node->setSelected(true);
|
||||
return;
|
||||
}
|
||||
scene()->clearSelection();
|
||||
} else if (event->button() == Qt::RightButton) {
|
||||
const Node *node = nullptr;
|
||||
if (NodeGraphicsItem *node_item = getTopLevelNode(event->pos())) {
|
||||
node = node_item->getNode();
|
||||
}
|
||||
ContextMenu context_menu(this, node, mapToGlobal(event->pos()));
|
||||
return;
|
||||
}
|
||||
|
||||
event->ignore();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "../node/node.h"
|
||||
#include "graphicsitems/node_graphicsitem.h"
|
||||
#include "nodeeditor_scene.h"
|
||||
|
||||
class NodeEditor : public QGraphicsView
|
||||
@@ -22,9 +23,9 @@ protected:
|
||||
void mouseReleaseEvent(QMouseEvent *) override;
|
||||
|
||||
private:
|
||||
void selectOrDrag(NodeGraphicsItem *node, QPoint current_pos);
|
||||
NodeEditorScene *m_scene;
|
||||
NodeGraphicsItem *getTopLevelNode(QPoint pos);
|
||||
|
||||
NodeEditorScene *m_scene;
|
||||
bool m_dragging = false;
|
||||
QPoint m_last_drag_pos;
|
||||
};
|
||||
|
||||
@@ -10,13 +10,13 @@ NodeEditorScene::NodeEditorScene(QObject *parent)
|
||||
setBackgroundBrush(Qt::white);
|
||||
}
|
||||
|
||||
void NodeEditorScene::addNode(Node *node)
|
||||
void NodeEditorScene::addNode(Node *node, QPoint relative_position_hint)
|
||||
{
|
||||
m_nodes.append(node);
|
||||
m_debug_x = m_debug_x + 200;
|
||||
NodeGraphicsItem *node_graphicitem = new NodeGraphicsItem(nullptr, node);
|
||||
node_graphicitem->setFlag(QGraphicsItem::ItemIsMovable, true);
|
||||
node_graphicitem->setPos(m_debug_x, 100);
|
||||
node_graphicitem->setPos(relative_position_hint);
|
||||
addItem(node_graphicitem);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ class NodeEditorScene : public QGraphicsScene
|
||||
public:
|
||||
explicit NodeEditorScene(QObject *parent = nullptr);
|
||||
|
||||
void addNode(Node *);
|
||||
void addNode(Node *node, QPoint relative_position_hint);
|
||||
|
||||
/** @brief Checks if currently a cable gets connected
|
||||
*
|
||||
|
||||
@@ -11,6 +11,18 @@ Panel::Panel(QWidget *parent)
|
||||
m_rubber_band = new QRubberBand(QRubberBand::Rectangle, this);
|
||||
}
|
||||
|
||||
void Panel::addVisual(Visual *visual)
|
||||
{
|
||||
QPoint mapped_position_hint = mapFromGlobal(visual->positionHint());
|
||||
VisualContainer *container = new VisualContainer(this);
|
||||
container->setGeometry(QRect(mapped_position_hint, QSize(100, 100)));
|
||||
container->setNode(visual);
|
||||
QWidget *visual_widget = visual->paintWidget(container);
|
||||
visual->setWidget(visual_widget);
|
||||
visual_widget->show();
|
||||
container->show();
|
||||
}
|
||||
|
||||
QList<QWidget *> Panel::childIn(QRect section)
|
||||
{
|
||||
QList<QWidget *> contained_widgets;
|
||||
@@ -243,11 +255,25 @@ bool Panel::inMouseWiggleTolerance(QSize size)
|
||||
|
||||
void Panel::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (m_display_mode == DisplayMode::Edit) {
|
||||
bool edit_mode = m_display_mode == DisplayMode::Edit;
|
||||
bool left_button = event->button() == Qt::LeftButton;
|
||||
bool right_button = event->button() == Qt::RightButton;
|
||||
|
||||
if (edit_mode && left_button) {
|
||||
m_origin = event->pos();
|
||||
m_rubber_band->setGeometry(QRect(m_origin, QSize(1, 1)));
|
||||
m_rubber_band->show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (edit_mode && right_button) {
|
||||
VisualContainer *container = qobject_cast<VisualContainer *>(childAt(event->pos()));
|
||||
Node *node = container ? container->node() : nullptr;
|
||||
ContextMenu context_menu(this, node, mapToGlobal(event->pos()));
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void Panel::mouseMoveEvent(QMouseEvent *event)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <QRubberBand>
|
||||
#include <QWidget>
|
||||
|
||||
#include "../app/context_menu.h"
|
||||
#include "../node/nodes/visual.h"
|
||||
#include "propertywindow.h"
|
||||
#include "resizeboundingbox.h"
|
||||
@@ -26,6 +27,16 @@ class Panel : public QWidget
|
||||
public:
|
||||
explicit Panel(QWidget *parent = nullptr);
|
||||
|
||||
/** @brief Adds a Visual to the Panel.
|
||||
*
|
||||
* This method adds the given Visual element to the Panel.
|
||||
* By doing so, it also creates a VisualContainer for the Visual and sets the Visual's parent to the container.
|
||||
*
|
||||
* @param visual The Visual element to be added.
|
||||
* @see Visual
|
||||
*/
|
||||
void addVisual(Visual *visual);
|
||||
|
||||
public slots:
|
||||
/** @brief Sets the display mode of the panel.
|
||||
*
|
||||
@@ -36,6 +47,7 @@ public slots:
|
||||
* @param display_mode The desired display mode (Run or Edit).
|
||||
*/
|
||||
void setMode(DisplayMode display_mode);
|
||||
|
||||
/** @brief Align selected to direction.
|
||||
*
|
||||
* This method aligns selected children and aligns them to a direction.
|
||||
|
||||
@@ -18,4 +18,13 @@ void VisualContainer::childEvent(QChildEvent *event)
|
||||
}
|
||||
}
|
||||
QWidget::childEvent(event);
|
||||
}
|
||||
|
||||
void VisualContainer::setNode(Node *node)
|
||||
{
|
||||
if (m_node == node) {
|
||||
return;
|
||||
}
|
||||
m_node = node;
|
||||
emit nodeChanged(node);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef VISUAL_CONTAINER_H
|
||||
#define VISUAL_CONTAINER_H
|
||||
|
||||
#include "../node/node.h"
|
||||
#include <QChildEvent>
|
||||
#include <QLayout>
|
||||
#include <QWidget>
|
||||
@@ -8,11 +9,21 @@
|
||||
class VisualContainer : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(Node *node READ node WRITE setNode NOTIFY nodeChanged MEMBER m_node)
|
||||
public:
|
||||
explicit VisualContainer(QWidget *parent = nullptr);
|
||||
|
||||
Node *node() const { return m_node; }
|
||||
void setNode(Node *node);
|
||||
|
||||
signals:
|
||||
void nodeChanged(Node *node);
|
||||
|
||||
protected:
|
||||
void childEvent(QChildEvent *) override;
|
||||
|
||||
private:
|
||||
Node *m_node = nullptr;
|
||||
};
|
||||
|
||||
#endif // VISUAL_CONTAINER_H
|
||||
Reference in New Issue
Block a user