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:
2026-04-04 17:39:00 +02:00
parent f6b885e644
commit d31fcb4ff3
20 changed files with 390 additions and 149 deletions

View File

@@ -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
View 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
View 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

View File

@@ -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!";
}
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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();

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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
*

View File

@@ -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)

View File

@@ -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.

View File

@@ -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);
}

View File

@@ -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