2.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit c8ef752b authored by Artur Grunau's avatar Artur Grunau
Browse files

Initial implementation of a main menu

This commit adds a simple main menu to the application. For the time being
it only has 2 submenus, "File" and "Visualizations". The latter is created
by MdiDockArea and lets users manage the visibility and placement of
canvas windows.
parent 348c710e
...@@ -136,6 +136,7 @@ namespace campvis { ...@@ -136,6 +136,7 @@ namespace campvis {
ui.logViewerDock->setWidget(_logViewer); ui.logViewerDock->setWidget(_logViewer);
_dcInspectorWidget = new DataContainerInspectorWidget(); _dcInspectorWidget = new DataContainerInspectorWidget();
this->populateMainMenu();
connect( connect(
this, SIGNAL(updatePipelineWidget(const std::vector<DataContainer*>&, const std::vector<AbstractPipeline*>&)), this, SIGNAL(updatePipelineWidget(const std::vector<DataContainer*>&, const std::vector<AbstractPipeline*>&)),
...@@ -160,6 +161,14 @@ namespace campvis { ...@@ -160,6 +161,14 @@ namespace campvis {
_application->s_DataContainersChanged.connect(this, &MainWindow::onDataContainersChanged); _application->s_DataContainersChanged.connect(this, &MainWindow::onDataContainersChanged);
} }
void MainWindow::populateMainMenu() {
QMenuBar* menuBar = this->menuBar();
QMenu* fileMenu = menuBar->addMenu(tr("&File"));
fileMenu->addAction(tr("&Quit"), qApp, SLOT(closeAllWindows()), QKeySequence(Qt::CTRL + Qt::Key_Q));
menuBar->addMenu(_mdiArea->menu());
}
bool MainWindow::eventFilter(QObject* watched, QEvent* event) { bool MainWindow::eventFilter(QObject* watched, QEvent* event) {
if (watched == _pipelinePropertiesWidget && event->type() == QEvent::Resize) { if (watched == _pipelinePropertiesWidget && event->type() == QEvent::Resize) {
_pipelinePropertiesScrollArea->setMinimumWidth(_pipelinePropertiesWidget->minimumSizeHint().width() + _pipelinePropertiesScrollArea->setMinimumWidth(_pipelinePropertiesWidget->minimumSizeHint().width() +
......
...@@ -141,12 +141,16 @@ namespace campvis { ...@@ -141,12 +141,16 @@ namespace campvis {
*/ */
void onDataContainersChanged(); void onDataContainersChanged();
/** /**
* Setup Qt GUI stuff * Setup Qt GUI stuff
*/ */
void setup(); void setup();
/**
* Create and populate the application's main menu.
*/
void populateMainMenu();
/** /**
* Adds a widget to the top docking area of the main window. * Adds a widget to the top docking area of the main window.
* This method creates a new dock with the specified name, * This method creates a new dock with the specified name,
......
...@@ -28,23 +28,111 @@ ...@@ -28,23 +28,111 @@
// ================================================================================================ // ================================================================================================
#include "mdidockarea.h" #include "mdidockarea.h"
#include "tgt/assert.h"
#include <QMenu>
#include <QSignalMapper>
namespace campvis { namespace campvis {
MdiDockArea::MdiDockArea(QWidget* parent /*= 0*/)
: QMdiArea(parent)
, _menu(0)
, _signalMapper(0)
{
_signalMapper = new QSignalMapper(this);
this->setTabsClosable(true);
this->setTabsMovable(true);
this->setDocumentMode(true);
// Menu setup
_menu = new QMenu(tr("&Visualizations"));
QActionGroup* displayStyleActions = new QActionGroup(this);
QAction* displayTiledAction = displayStyleActions->addAction(tr("Display tiled"));
displayTiledAction->setCheckable(true);
displayTiledAction->setChecked(true);
_menu->addAction(displayTiledAction);
this->connect(displayTiledAction, SIGNAL(triggered()), SLOT(switchToTiledDisplay()));
QAction* displayTabbedAction = displayStyleActions->addAction(tr("Display tabbed"));
displayTabbedAction->setCheckable(true);
_menu->addAction(displayTabbedAction);
this->connect(displayTabbedAction, SIGNAL(triggered()), SLOT(switchToTabbedDisplay()));
_menu->addSeparator();
}
MdiDockedWindow* MdiDockArea::addSubWindow(QWidget* widget, Qt::WindowFlags windowFlags /*= 0*/) { MdiDockedWindow* MdiDockArea::addSubWindow(QWidget* widget, Qt::WindowFlags windowFlags /*= 0*/) {
MdiDockedWindow* dockedWindow = new MdiDockedWindow(); MdiDockedWindow* dockedWindow = new MdiDockedWindow(this, windowFlags);
dockedWindow->setWidget(widget); dockedWindow->setWidget(widget);
QMdiArea::addSubWindow(dockedWindow, windowFlags); this->addDockedWindow(dockedWindow);
widget->show();
// Calling tileSubWindows() in TabbedView mode breaks the tabbed display
if (this->viewMode() == QMdiArea::SubWindowView)
this->tileSubWindows(); this->tileSubWindows();
connect(dockedWindow, SIGNAL(s_positionChanged(MdiDockedWindow*, const QPoint&)), QAction* visibilityAction = _menu->addAction(widget->windowTitle());
this, SLOT(trackMdiSubWindowsPosition(MdiDockedWindow*, const QPoint&))); visibilityAction->setCheckable(true);
visibilityAction->setChecked(true);
visibilityAction->setData(QVariant::fromValue(dynamic_cast<QWidget*>(widget)));
connect(visibilityAction, SIGNAL(triggered()), _signalMapper, SLOT(map()));
_signalMapper->setMapping(visibilityAction, visibilityAction);
connect(_signalMapper, SIGNAL(mapped(QObject*)), SLOT(toggleSubWindowVisibility(QObject*)));
return dockedWindow; return dockedWindow;
} }
QMenu* MdiDockArea::menu() {
return _menu;
}
void MdiDockArea::addDockedWindow(MdiDockedWindow* dockedWindow) {
QMdiArea::addSubWindow(dockedWindow);
dockedWindow->show();
connect(dockedWindow, SIGNAL(s_positionChanged(MdiDockedWindow*, const QPoint&)),
SLOT(trackMdiSubWindowsPosition(MdiDockedWindow*, const QPoint&)));
}
void MdiDockArea::toggleSubWindowVisibility(QObject* actionObject) {
/*
* This static_cast is safe as toggleSubWindowVisibility() is a private slot to which only
* MdiDockArea creates connections, always passing a QAction instance.
*/
QAction* visibilityAction = static_cast<QAction*>(actionObject);
QWidget* windowWidget = visibilityAction->data().value<QWidget*>()->parentWidget();
if (MdiDockedWindow* dockedWindow = dynamic_cast<MdiDockedWindow*>(windowWidget)) {
if (visibilityAction->isChecked())
this->addDockedWindow(dockedWindow);
else
this->removeSubWindow(dockedWindow);
// Calling tileSubWindows() in TabbedView mode breaks the tabbed display
if (this->viewMode() == QMdiArea::SubWindowView)
this->tileSubWindows();
} else if (MdiFloatingWindow* floatingWindow = dynamic_cast<MdiFloatingWindow*>(windowWidget)) {
if (visibilityAction->isChecked())
floatingWindow->show();
else
floatingWindow->hide();
}
else
tgtAssert(false, "Widget's parent is of unsupported type.");
}
void MdiDockArea::switchToTiledDisplay() {
this->setViewMode(QMdiArea::SubWindowView);
this->tileSubWindows();
}
void MdiDockArea::switchToTabbedDisplay() {
this->setViewMode(QMdiArea::TabbedView);
}
void MdiDockArea::trackFloatingWindowsPosition(MdiFloatingWindow* floatingWindow, const QPoint& newPos) { void MdiDockArea::trackFloatingWindowsPosition(MdiFloatingWindow* floatingWindow, const QPoint& newPos) {
const QRect& widgetGeometry = floatingWindow->frameGeometry(); const QRect& widgetGeometry = floatingWindow->frameGeometry();
const QRect& mdiAreaRect = this->contentsRect(); const QRect& mdiAreaRect = this->contentsRect();
...@@ -56,13 +144,16 @@ namespace campvis { ...@@ -56,13 +144,16 @@ namespace campvis {
if (widgetGeometry.width() * widgetGeometry.height() * 3 < if (widgetGeometry.width() * widgetGeometry.height() * 3 <
intersection.width() * intersection.height() * 5) { intersection.width() * intersection.height() * 5) {
floatingWindow->stopWindowDrag(); floatingWindow->stopWindowDrag();
floatingWindow->hide();
QWidget* widget = floatingWindow->widget(); QWidget* widget = floatingWindow->widget();
MdiDockedWindow* dockedWindow = this->addSubWindow(widget); MdiDockedWindow* dockedWindow = new MdiDockedWindow();
dockedWindow->setWidget(widget);
dockedWindow->setWindowTitle(floatingWindow->windowTitle()); dockedWindow->setWindowTitle(floatingWindow->windowTitle());
this->addDockedWindow(dockedWindow);
widget->show(); widget->show();
floatingWindow->deleteLater(); floatingWindow->deleteLater();
dockedWindow->forceWindowDrag(); dockedWindow->forceWindowDrag();
} }
} }
...@@ -79,16 +170,16 @@ namespace campvis { ...@@ -79,16 +170,16 @@ namespace campvis {
dockedWindow->stopWindowDrag(); dockedWindow->stopWindowDrag();
dockedWindow->setWidget(0); dockedWindow->setWidget(0);
removeSubWindow(dockedWindow); removeSubWindow(dockedWindow);
dockedWindow->deleteLater();
tileSubWindows();
MdiFloatingWindow* floatingWindow = new MdiFloatingWindow(widget); MdiFloatingWindow* floatingWindow = new MdiFloatingWindow(widget);
floatingWindow->setWindowTitle(dockedWindow->windowTitle()); floatingWindow->setWindowTitle(dockedWindow->windowTitle());
floatingWindow->show();
floatingWindow->forceWindowDrag(); floatingWindow->forceWindowDrag();
connect(floatingWindow, SIGNAL(s_positionChanged(MdiFloatingWindow*, const QPoint&)), connect(floatingWindow, SIGNAL(s_positionChanged(MdiFloatingWindow*, const QPoint&)),
this, SLOT(trackFloatingWindowsPosition(MdiFloatingWindow*, const QPoint&))); this, SLOT(trackFloatingWindowsPosition(MdiFloatingWindow*, const QPoint&)));
dockedWindow->deleteLater();
tileSubWindows();
floatingWindow->show();
} }
} }
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include <QMdiArea> #include <QMdiArea>
class QSignalMapper;
namespace campvis { namespace campvis {
/** /**
...@@ -49,6 +51,13 @@ namespace campvis { ...@@ -49,6 +51,13 @@ namespace campvis {
Q_OBJECT Q_OBJECT
public: public:
/**
* Constructs an empty MDI area.
*
* \param parent the area's parent widget (passed to QMdiArea's constructor)
*/
explicit MdiDockArea(QWidget* parent = 0);
/** /**
* Wrap \p widget in an MDI window and dock it in the MDI area. * Wrap \p widget in an MDI window and dock it in the MDI area.
* *
...@@ -60,6 +69,8 @@ namespace campvis { ...@@ -60,6 +69,8 @@ namespace campvis {
*/ */
MdiDockedWindow* addSubWindow(QWidget* widget, Qt::WindowFlags windowFlags = 0); MdiDockedWindow* addSubWindow(QWidget* widget, Qt::WindowFlags windowFlags = 0);
QMenu* menu();
private slots: private slots:
/** /**
* Track the position of a floating MDI window and dock it if necessary. * Track the position of a floating MDI window and dock it if necessary.
...@@ -75,6 +86,34 @@ namespace campvis { ...@@ -75,6 +86,34 @@ namespace campvis {
*/ */
void trackMdiSubWindowsPosition(MdiDockedWindow* mdiSubWindow, const QPoint& newPos); void trackMdiSubWindowsPosition(MdiDockedWindow* mdiSubWindow, const QPoint& newPos);
/**
* Display docked windows as sub-windows with window frames.
*/
void switchToTiledDisplay();
/**
* Display docked windows with tabs in a tab bar.
*/
void switchToTabbedDisplay();
/**
* Depending on the state of \p actionObject, show or hide its associated sub-window.
*
* \param actionObject the visibility action whose corresponding sub-window should be shown or hidden
*/
void toggleSubWindowVisibility(QObject* actionObject);
private:
/**
* Add the given MdiDockedWindow to the MDI area.
*
* \param dockedWindow the docked window to add
*/
void addDockedWindow(MdiDockedWindow* dockedWindow);
QMenu* _menu; ///< Menu with actions for controlling the MDI area and its subwindows.
QSignalMapper* _signalMapper; ///< Helper used to pass extra information to toggleSubWindowVisibility.
}; };
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment