Notice to GitKraken users: A vulnerability has been found in the SSH key generation of GitKraken versions 7.6.0 to 8.0.0 (https://www.gitkraken.com/blog/weak-ssh-key-fix). If you use GitKraken and have generated a SSH key using one of these versions, please remove it both from your local workstation and from your LRZ GitLab profile.

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

Commit 0c73f0f7 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Merge branch 'main-menu' of /mnt/bigone/git/repositories/berge/campvis into development

parents 7c9beba2 6d4262de
......@@ -38,6 +38,7 @@ SET(CampvisApplicationToBeMocced
gui/logviewerwidget.h
gui/loghighlighter.h
gui/mdi/mdidockarea.h
gui/mdi/mdidockablewindow.h
gui/mdi/mdidockedwindow.h
gui/mdi/mdifloatingwindow.h
gui/adjusterwidgets/doubleadjusterwidget.h
......
......@@ -33,6 +33,7 @@
#include "application/campvisapplication.h"
#include "application/gui/datacontainerinspectorwidget.h"
#include "application/gui/datacontainerinspectorcanvas.h"
#include "application/gui/mdi/mdidockablewindow.h"
#include "application/gui/qtdatahandle.h"
#include "core/datastructures/datacontainer.h"
#include "core/pipeline/abstractpipeline.h"
......@@ -40,7 +41,6 @@
#include "core/tools/stringutils.h"
#include "modules/pipelinefactory.h"
#include <QMdiSubWindow>
#include <QScrollBar>
......@@ -136,6 +136,7 @@ namespace campvis {
ui.logViewerDock->setWidget(_logViewer);
_dcInspectorWidget = new DataContainerInspectorWidget();
this->populateMainMenu();
connect(
this, SIGNAL(updatePipelineWidget(const std::vector<DataContainer*>&, const std::vector<AbstractPipeline*>&)),
......@@ -160,6 +161,24 @@ namespace campvis {
_application->s_DataContainersChanged.connect(this, &MainWindow::onDataContainersChanged);
}
void MainWindow::populateMainMenu() {
// Populate the file menu
QMenuBar* menuBar = this->menuBar();
QMenu* fileMenu = menuBar->addMenu(tr("&File"));
fileMenu->addAction(tr("&Quit"), qApp, SLOT(closeAllWindows()), QKeySequence(Qt::CTRL + Qt::Key_Q));
// Populate the visualizations menu
QMenu* visualizationsMenu = _mdiArea->menu();
visualizationsMenu->setTitle(tr("&Visualizations"));
menuBar->addMenu(visualizationsMenu);
// Populate the tools menu
QMenu* toolsMenu = menuBar->addMenu(tr("&Tools"));
toolsMenu->addAction(ui.pipelineTreeDock->toggleViewAction());
toolsMenu->addAction(ui.pipelinePropertiesDock->toggleViewAction());
toolsMenu->addAction(ui.logViewerDock->toggleViewAction());
}
bool MainWindow::eventFilter(QObject* watched, QEvent* event) {
if (watched == _pipelinePropertiesWidget && event->type() == QEvent::Resize) {
_pipelinePropertiesScrollArea->setMinimumWidth(_pipelinePropertiesWidget->minimumSizeHint().width() +
......@@ -259,9 +278,10 @@ namespace campvis {
}
void MainWindow::addVisualizationPipelineWidget(const std::string& name, QWidget* canvas) {
QMdiSubWindow* mdiSubWindow = _mdiArea->addSubWindow(canvas);
MdiDockableWindow* dockableWindow = _mdiArea->addWidget(canvas);
const QString& windowTitle = QString::fromStdString(name);
mdiSubWindow->setWindowTitle(windowTitle);
dockableWindow->setWindowTitle(windowTitle);
dockableWindow->show();
}
QDockWidget* MainWindow::dockPrimaryWidget(const std::string& name, QWidget* widget) {
......
......@@ -141,12 +141,16 @@ namespace campvis {
*/
void onDataContainersChanged();
/**
* Setup Qt GUI stuff
*/
void setup();
/**
* Create and populate the application's main menu.
*/
void populateMainMenu();
/**
* Adds a widget to the top docking area of the main window.
* This method creates a new dock with the specified name,
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, Germany
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// The licensing of this softare is not yet resolved. Until then, redistribution in source or
// binary forms outside the CAMP chair is not permitted, unless explicitly stated in legal form.
// However, the names of the original authors and the above copyright notice must retain in its
// original state in any case.
//
// Legal disclaimer provided by the BSD license:
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// ================================================================================================
#include "mdidockablewindow.h"
#include "mdidockarea.h"
#include <QAction>
namespace campvis {
MdiDockableWindow::MdiDockableWindow(QWidget* widget, MdiDockArea* mdiArea, Qt::WindowFlags windowFlags /*= 0*/)
: QWidget(mdiArea)
, _docked(true)
, _mdiArea(mdiArea)
, _dockedWindow(0)
, _floatingWindow(0)
, _toggleViewAction(0)
{
_dockedWindow = this->newDockedWindow(widget);
_dockedWindow->setWindowFlags(windowFlags);
_toggleViewAction = new QAction(this);
_toggleViewAction->setCheckable(true);
_toggleViewAction->setChecked(false);
this->connect(_toggleViewAction, SIGNAL(toggled(bool)), SLOT(toggleWindowVisibility(bool)));
}
void MdiDockableWindow::setWindowTitle(const QString& title) {
QWidget::setWindowTitle(title);
_toggleViewAction->setText(title);
if (_docked)
_dockedWindow->setWindowTitle(title);
else
_floatingWindow->setWindowTitle(title);
}
QAction* MdiDockableWindow::toggleViewAction() const {
return _toggleViewAction;
}
void MdiDockableWindow::setVisible(bool visible) {
_toggleViewAction->setChecked(visible);
}
MdiDockedWindow* MdiDockableWindow::newDockedWindow(QWidget* widget) {
MdiDockedWindow* dockedWindow = new MdiDockedWindow(_mdiArea);
dockedWindow->setWidget(widget);
this->connect(dockedWindow, SIGNAL(s_positionChanged(const QPoint&)), SLOT(trackDockedWindowPosition(QPoint)));
this->connect(dockedWindow, SIGNAL(s_closed()), SLOT(handleWindowClosing()));
return dockedWindow;
}
void MdiDockableWindow::toggleWindowVisibility(bool on) {
if (on) {
if (_docked)
_mdiArea->addSubWindow(_dockedWindow);
else
_floatingWindow->show();
}
else {
if (_docked)
_mdiArea->removeSubWindow(_dockedWindow);
else
_floatingWindow->hide();
}
}
void MdiDockableWindow::handleWindowClosing() {
_toggleViewAction->setChecked(false);
}
void MdiDockableWindow::trackFloatingWindowPosition(const QPoint& /*newPos*/) {
const QRect& widgetGeometry = _floatingWindow->frameGeometry();
const QRect& mdiAreaRect = _mdiArea->contentsRect();
const QRect mdiAreaGeometry(_mdiArea->mapToGlobal(mdiAreaRect.topLeft()),
_mdiArea->mapToGlobal(mdiAreaRect.bottomRight()));
const QRect& intersection = widgetGeometry & mdiAreaGeometry;
// Dock the floating window's widget if at least 60% of it is over the MDI area
if (widgetGeometry.width() * widgetGeometry.height() * 3 <
intersection.width() * intersection.height() * 5) {
_floatingWindow->stopWindowDrag();
_floatingWindow->hide();
QWidget* widget = _floatingWindow->widget();
_dockedWindow = this->newDockedWindow(widget);
_dockedWindow->setWindowTitle(this->windowTitle());
_floatingWindow->deleteLater();
_floatingWindow = 0;
_docked = true;
_mdiArea->addSubWindow(_dockedWindow);
// Dragging the window doesn't make sense in tabbed mode
if (_mdiArea->viewMode() == QMdiArea::SubWindowView)
_dockedWindow->forceWindowDrag();
}
}
void MdiDockableWindow::trackDockedWindowPosition(const QPoint& /*newPos*/) {
const QRect& subWindowGeometry = _dockedWindow->frameGeometry();
const QRect& mdiAreaGeometry = _mdiArea->contentsRect();
const QRect& intersection = subWindowGeometry & mdiAreaGeometry;
// Detach the docked window's widget if at least 60% of it has left the MDI area
if (subWindowGeometry.width() * subWindowGeometry.height() * 2 >
intersection.width() * intersection.height() * 5) {
QWidget* widget = _dockedWindow->widget();
_dockedWindow->stopWindowDrag();
_dockedWindow->setWidget(0);
_mdiArea->removeSubWindow(_dockedWindow);
_floatingWindow = new MdiFloatingWindow(widget);
_floatingWindow->setWindowTitle(this->windowTitle());
_floatingWindow->forceWindowDrag();
this->connect(_floatingWindow, SIGNAL(s_positionChanged(const QPoint&)),
SLOT(trackFloatingWindowPosition(const QPoint&)));
this->connect(_floatingWindow, SIGNAL(s_closed()), SLOT(handleWindowClosing()));
_dockedWindow->deleteLater();
_dockedWindow = 0;
_docked = false;
_floatingWindow->show();
}
}
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, Germany
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// The licensing of this softare is not yet resolved. Until then, redistribution in source or
// binary forms outside the CAMP chair is not permitted, unless explicitly stated in legal form.
// However, the names of the original authors and the above copyright notice must retain in its
// original state in any case.
//
// Legal disclaimer provided by the BSD license:
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// ================================================================================================
#ifndef MDIDOCKABLEWINDOW_H__
#define MDIDOCKABLEWINDOW_H__
#include "mdidockedwindow.h"
#include "mdifloatingwindow.h"
#include <QWidget>
namespace campvis {
class MdiDockArea;
/**
* MDI window that be docked and undocked.
*
* MdiDockableWindow takes care of creating all necessary representations (docked and floating
* window) of the widget it's passed and seamlessly switching between them in response to the
* user's actions (window dragging, key presses, etc).
*/
class MdiDockableWindow : public QWidget {
Q_OBJECT
public:
/**
* Construct a new MdiDockableWindow.
*
* \param widget the widget this window is to wrap
* \param mdiArea the MDI area the window should dock in
* \param windowFlags flags used to customize the frame of the window
*/
MdiDockableWindow(QWidget* widget, MdiDockArea* mdiArea, Qt::WindowFlags windowFlags = 0);
/**
* Set the title of this window.
*
* \param title the window's new title
*/
void setWindowTitle(const QString& title);
/**
* Change the window's visibility.
*
* \param visible should the window be visible?
*/
virtual void setVisible(bool visible);
/**
* Returns a checkable action that can be used to show or hide this window.
*
* The action's text is set to this window's title.
*/
QAction* toggleViewAction() const;
private slots:
/**
* Track the position of the associated floating MDI window and dock it if necessary.
*
* This slot is invoked when the position of the floating MDI window changes.
*/
void trackFloatingWindowPosition(const QPoint& newPos);
/**
* Track the position of the associated docked MDI window and detach it if necessary.
*
* This slot is invoked when the position of the docked MDI window changes.
*/
void trackDockedWindowPosition(const QPoint& newPos);
/**
* Depending on the state of _toggleViewAction, show or hide the window.
*
* \param on true if _toggleViewAction is checked, false otherwise
*/
void toggleWindowVisibility(bool on);
/**
* Hide the closed MdiDockedWindow/MdiFloatingWindow and update the visibility action.
*/
void handleWindowClosing();
private:
/**
* Create and return an MdiDockedWindow wrapping the \p widget.
*
* \param widget the widget the new docked window should wrap
*/
MdiDockedWindow* newDockedWindow(QWidget* widget);
bool _docked; ///< Is the window currently docked?
MdiDockArea* _mdiArea; ///< The MDI this window docks in.
MdiDockedWindow* _dockedWindow; ///< The window's docked representation.
MdiFloatingWindow* _floatingWindow; ///< The window's floating representation.
QAction* _toggleViewAction; ///< A checkable action that can be used to show or hide this window.
};
}
#endif // MDIDOCKABLEWINDOW_H__
......@@ -5,8 +5,8 @@
// If not explicitly stated otherwise: Copyright (C) 2012, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitt Mnchen
// Boltzmannstr. 3, 85748 Garching b. Mnchen, Germany
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, Germany
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// The licensing of this softare is not yet resolved. Until then, redistribution in source or
......@@ -29,67 +29,76 @@
#include "mdidockarea.h"
#include <QMenu>
namespace campvis {
MdiDockedWindow* MdiDockArea::addSubWindow(QWidget* widget, Qt::WindowFlags windowFlags /*= 0*/) {
MdiDockedWindow* dockedWindow = new MdiDockedWindow();
MdiDockArea::MdiDockArea(QWidget* parent /*= 0*/)
: QMdiArea(parent)
, _menu(0)
{
this->setTabsClosable(true);
this->setTabsMovable(true);
this->setDocumentMode(true);
dockedWindow->setWidget(widget);
QMdiArea::addSubWindow(dockedWindow, windowFlags);
widget->show();
this->tileSubWindows();
// Menu setup
_menu = new QMenu(this);
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()));
connect(dockedWindow, SIGNAL(s_positionChanged(MdiDockedWindow*, const QPoint&)),
this, SLOT(trackMdiSubWindowsPosition(MdiDockedWindow*, const QPoint&)));
QAction* displayTabbedAction = displayStyleActions->addAction(tr("Display tabbed"));
displayTabbedAction->setCheckable(true);
_menu->addAction(displayTabbedAction);
this->connect(displayTabbedAction, SIGNAL(triggered()), SLOT(switchToTabbedDisplay()));
return dockedWindow;
_menu->addSeparator();
}
void MdiDockArea::trackFloatingWindowsPosition(MdiFloatingWindow* floatingWindow, const QPoint& newPos) {
const QRect& widgetGeometry = floatingWindow->frameGeometry();
const QRect& mdiAreaRect = this->contentsRect();
const QRect mdiAreaGeometry(this->mapToGlobal(mdiAreaRect.topLeft()),
this->mapToGlobal(mdiAreaRect.bottomRight()));
const QRect& intersection = widgetGeometry & mdiAreaGeometry;
// Dock the floating window's widget if at least 60% of it is over the MDI area
if (widgetGeometry.width() * widgetGeometry.height() * 3 <
intersection.width() * intersection.height() * 5) {
floatingWindow->stopWindowDrag();
QWidget* widget = floatingWindow->widget();
MdiDockedWindow* dockedWindow = this->addSubWindow(widget);
dockedWindow->setWindowTitle(floatingWindow->windowTitle());
widget->show();
floatingWindow->deleteLater();
dockedWindow->forceWindowDrag();
MdiDockableWindow* MdiDockArea::addWidget(QWidget* widget, Qt::WindowFlags windowFlags /*= 0*/) {
MdiDockableWindow* dockableWindow = new MdiDockableWindow(widget, this, windowFlags);
_menu->addAction(dockableWindow->toggleViewAction());
return dockableWindow;
}
QMdiSubWindow* MdiDockArea::addSubWindow(QMdiSubWindow* mdiSubWindow) {
QMdiArea::addSubWindow(mdiSubWindow);
mdiSubWindow->show();
// Calling tileSubWindows() in TabbedView mode breaks the tabbed display
if (this->viewMode() == QMdiArea::SubWindowView)
this->tileSubWindows();
return mdiSubWindow;
}
void MdiDockArea::trackMdiSubWindowsPosition(MdiDockedWindow *dockedWindow, const QPoint& /*newPos*/) {
const QRect& subWindowGeometry = dockedWindow->frameGeometry();
const QRect& mdiAreaGeometry = contentsRect();
const QRect& intersection = subWindowGeometry & mdiAreaGeometry;
// Detach the docked window's widget if at least 60% of it has left the MDI area
if (subWindowGeometry.width() * subWindowGeometry.height() * 2 >
intersection.width() * intersection.height() * 5) {
QWidget* widget = dockedWindow->widget();
dockedWindow->stopWindowDrag();
dockedWindow->setWidget(0);
removeSubWindow(dockedWindow);
dockedWindow->deleteLater();
tileSubWindows();
MdiFloatingWindow* floatingWindow = new MdiFloatingWindow(widget);
floatingWindow->setWindowTitle(dockedWindow->windowTitle());
floatingWindow->show();
floatingWindow->forceWindowDrag();
connect(floatingWindow, SIGNAL(s_positionChanged(MdiFloatingWindow*, const QPoint&)),
this, SLOT(trackFloatingWindowsPosition(MdiFloatingWindow*, const QPoint&)));
void MdiDockArea::removeSubWindow(QMdiSubWindow* mdiSubWindow) {
if (this->activeSubWindow() == mdiSubWindow)
this->activateNextSubWindow();
QMdiArea::removeSubWindow(mdiSubWindow);
// Calling tileSubWindows() in TabbedView mode breaks the tabbed display
if (this->viewMode() == QMdiArea::SubWindowView)
this->tileSubWindows();
}
QMenu* MdiDockArea::menu() const {
return _menu;
}
void MdiDockArea::switchToTiledDisplay() {
this->setViewMode(QMdiArea::SubWindowView);
this->tileSubWindows();
}
void MdiDockArea::switchToTabbedDisplay() {
this->setViewMode(QMdiArea::TabbedView);
}
}
......@@ -30,8 +30,7 @@
#ifndef MDIDOCKAREA_H__
#define MDIDOCKAREA_H__
#include "mdidockedwindow.h"
#include "mdifloatingwindow.h"
#include "mdidockablewindow.h"
#include <QMdiArea>
......@@ -40,9 +39,12 @@ namespace campvis {
/**
* MDI area whose subwindows can be docked and undocked.
*
* MdiDockArea takes care of creating all necessary representations (docked and floating window)
* of the widgets passed to \ref addSubWindow and seamlessly switching between them in response
* to the user's actions (window dragging, key presses, etc).
* MdiDockArea extends QMdiArea's functionality by adding support for dockable MDI windows. It
* provides 2 APIs:
* - addSubWindow and removeSubWindow are much like their QMdiArea's counterparts; they operate
* on MDI sub-windows only, which don't support docking/undocking
* - dockable windows can be created using the addWidget method, which returns an
* MdiDockableWindow instance
*/
class MdiDockArea : public QMdiArea {
......@@ -50,30 +52,59 @@ namespace campvis {
public:
/**
* Wrap \p widget in an MDI window and dock it in the MDI area.
* Constructs an empty MDI area.
*
* This method creates a MdiDockedWindow wrapping the widget, and adds it to the MDI area.
* \param parent the area's parent widget (passed to QMdiArea's constructor)
*/
explicit MdiDockArea(QWidget* parent = 0);
/**
* Wrap \p widget in a dockable MDI window and add it to the MDI area.
*
* This method creates a MdiDockableWindow wrapping the widget, and adds it to the MDI area.
*
* \param widget the widget to add to the MDI area
* \param windowFlags flags used to customize the frame of the created subwindow
* \return the PipelineMdiSubWindow instance that was added to the MDI area
* \return the MdiDockableWindow instance that was added to the MDI area
*/
MdiDockedWindow* addSubWindow(QWidget* widget, Qt::WindowFlags windowFlags = 0);
MdiDockableWindow* addWidget(QWidget* widget, Qt::WindowFlags windowFlags = 0);
/**
* Add \p mdiSubWindow to the MDI area.
*
* \param mdiSubWindow the MDI sub-window to be added to the MDI area
* \return the MDI sub-window that was passed in
*/
QMdiSubWindow* addSubWindow(QMdiSubWindow* mdiSubWindow);
private slots:
/**
* Track the position of a floating MDI window and dock it if necessary.
* Remove \p mdiSubWindow from the MDI area.
*
* This slot is invoked when the position of a floating MDI window changes.
* \param mdiSubWindow the MDI sub-window to be removed from the MDI area
*/
void trackFloatingWindowsPosition(MdiFloatingWindow* floatingWindow, const QPoint& newPos);
void removeSubWindow(QMdiSubWindow* mdiSubWindow);
/**
* Track the position of a docked MDI window and detach it if necessary.
* Return a menu that lets the user control how the area's contents are displayed.
*
* This slot is invoked when the position of an MDI subwindow changes.
* The menu contains actions that make it possible to change the layout and visibility of
* the area's subwindows.
*/
void trackMdiSubWindowsPosition(MdiDockedWindow* mdiSubWindow, const QPoint& newPos);
QMenu* menu() const;
private slots:
/**
* Display docked windows as sub-windows with window frames.
*/
void switchToTiledDisplay();
/**
* Display docked windows with tabs in a tab bar.
*/
void switchToTabbedDisplay();
private:
QMenu* _menu; ///< Menu with actions for controlling the MDI area and its subwindows.
};
}
......
......@@ -45,6 +45,7 @@ namespace campvis {
_dragActive = true;
_lastMousePos = QCursor::pos();