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

Commit 6d4262de authored by Artur Grunau's avatar Artur Grunau
Browse files

MdiDockableWindow: new MDI helper class

MdiDockableWindow has been extracted from MdiDockArea to simplify and
better structure our MDI implementation. The new class takes care of
creating all necessary representations (docked and floating window) of
widgets added to MdiDockArea and seamlessly switching between them in
response to the user's actions (window dragging, key presses, etc).

MdiDockableWindow improves our MDI implementation in two ways:
- MdiFloatingWindow and MdiDockedWindow instances shouldn't be
  interacted with directly; they're created and disposed of as needed,
  and therefore can't be used as a handle to access and modify an MDI
  window's state; MdiDockableWindow, in contrast, fits this role
  perfectly; it manages both representations of an MDI window, and as
  a result stays around as long as at least one of them is needed
- managing state transitions of many sub-windows directly in MdiDockArea
  was becoming clumsy as signal mapping and dynamic properties were
  required; having a separate widget that only has to control the state
  of one sub-window makes the code related to state transitions much
  simpler
parent 8126df4d
...@@ -38,6 +38,7 @@ SET(CampvisApplicationToBeMocced ...@@ -38,6 +38,7 @@ SET(CampvisApplicationToBeMocced
gui/logviewerwidget.h gui/logviewerwidget.h
gui/loghighlighter.h gui/loghighlighter.h
gui/mdi/mdidockarea.h gui/mdi/mdidockarea.h
gui/mdi/mdidockablewindow.h
gui/mdi/mdidockedwindow.h gui/mdi/mdidockedwindow.h
gui/mdi/mdifloatingwindow.h gui/mdi/mdifloatingwindow.h
gui/adjusterwidgets/doubleadjusterwidget.h gui/adjusterwidgets/doubleadjusterwidget.h
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "application/campvisapplication.h" #include "application/campvisapplication.h"
#include "application/gui/datacontainerinspectorwidget.h" #include "application/gui/datacontainerinspectorwidget.h"
#include "application/gui/datacontainerinspectorcanvas.h" #include "application/gui/datacontainerinspectorcanvas.h"
#include "application/gui/mdi/mdidockablewindow.h"
#include "application/gui/qtdatahandle.h" #include "application/gui/qtdatahandle.h"
#include "core/datastructures/datacontainer.h" #include "core/datastructures/datacontainer.h"
#include "core/pipeline/abstractpipeline.h" #include "core/pipeline/abstractpipeline.h"
...@@ -40,7 +41,6 @@ ...@@ -40,7 +41,6 @@
#include "core/tools/stringutils.h" #include "core/tools/stringutils.h"
#include "modules/pipelinefactory.h" #include "modules/pipelinefactory.h"
#include <QMdiSubWindow>
#include <QScrollBar> #include <QScrollBar>
...@@ -278,9 +278,10 @@ namespace campvis { ...@@ -278,9 +278,10 @@ namespace campvis {
} }
void MainWindow::addVisualizationPipelineWidget(const std::string& name, QWidget* canvas) { 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); const QString& windowTitle = QString::fromStdString(name);
mdiSubWindow->setWindowTitle(windowTitle); dockableWindow->setWindowTitle(windowTitle);
dockableWindow->show();
} }
QDockWidget* MainWindow::dockPrimaryWidget(const std::string& name, QWidget* widget) { QDockWidget* MainWindow::dockPrimaryWidget(const std::string& name, QWidget* widget) {
......
// ================================================================================================
//
// 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__
...@@ -28,21 +28,15 @@ ...@@ -28,21 +28,15 @@
// ================================================================================================ // ================================================================================================
#include "mdidockarea.h" #include "mdidockarea.h"
#include "tgt/assert.h"
#include <QMenu> #include <QMenu>
#include <QSignalMapper>
namespace campvis { namespace campvis {
MdiDockArea::MdiDockArea(QWidget* parent /*= 0*/) MdiDockArea::MdiDockArea(QWidget* parent /*= 0*/)
: QMdiArea(parent) : QMdiArea(parent)
, _menu(0) , _menu(0)
, _signalMapper(0)
{ {
_signalMapper = new QSignalMapper(this);
connect(_signalMapper, SIGNAL(mapped(QObject*)), SLOT(toggleSubWindowVisibility(QObject*)));
this->setTabsClosable(true); this->setTabsClosable(true);
this->setTabsMovable(true); this->setTabsMovable(true);
this->setDocumentMode(true); this->setDocumentMode(true);
...@@ -65,76 +59,37 @@ namespace campvis { ...@@ -65,76 +59,37 @@ namespace campvis {
_menu->addSeparator(); _menu->addSeparator();
} }
MdiDockedWindow* MdiDockArea::addSubWindow(QWidget* widget, Qt::WindowFlags windowFlags /*= 0*/) { MdiDockableWindow* MdiDockArea::addWidget(QWidget* widget, Qt::WindowFlags windowFlags /*= 0*/) {
MdiDockedWindow* dockedWindow = new MdiDockedWindow(this, windowFlags); MdiDockableWindow* dockableWindow = new MdiDockableWindow(widget, this, windowFlags);
_menu->addAction(dockableWindow->toggleViewAction());
return dockableWindow;
}
dockedWindow->setWidget(widget); QMdiSubWindow* MdiDockArea::addSubWindow(QMdiSubWindow* mdiSubWindow) {
this->addDockedWindow(dockedWindow); QMdiArea::addSubWindow(mdiSubWindow);
mdiSubWindow->show();
// Calling tileSubWindows() in TabbedView mode breaks the tabbed display // Calling tileSubWindows() in TabbedView mode breaks the tabbed display
if (this->viewMode() == QMdiArea::SubWindowView) if (this->viewMode() == QMdiArea::SubWindowView)
this->tileSubWindows(); this->tileSubWindows();
QAction* visibilityAction = _menu->addAction(widget->windowTitle()); return mdiSubWindow;
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);
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&)));
connect(dockedWindow, SIGNAL(s_closed(MdiDockedWindow*)), SLOT(handleDockedWindowClosing(MdiDockedWindow*)));
} }
void MdiDockArea::toggleSubWindowVisibility(QObject* actionObject) { void MdiDockArea::removeSubWindow(QMdiSubWindow* mdiSubWindow) {
/* if (this->activeSubWindow() == mdiSubWindow)
* 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 {
if (this->activeSubWindow() == dockedWindow)
this->activateNextSubWindow(); this->activateNextSubWindow();
this->removeSubWindow(dockedWindow); QMdiArea::removeSubWindow(mdiSubWindow);
}
// Calling tileSubWindows() in TabbedView mode breaks the tabbed display // Calling tileSubWindows() in TabbedView mode breaks the tabbed display
if (this->viewMode() == QMdiArea::SubWindowView) if (this->viewMode() == QMdiArea::SubWindowView)
this->tileSubWindows(); 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::handleDockedWindowClosing(MdiDockedWindow* dockedWindow) { QMenu* MdiDockArea::menu() const {
if (this->activeSubWindow() == dockedWindow) return _menu;
this->activateNextSubWindow();
this->removeSubWindow(dockedWindow);
} }
void MdiDockArea::switchToTiledDisplay() { void MdiDockArea::switchToTiledDisplay() {
...@@ -146,54 +101,4 @@ namespace campvis { ...@@ -146,54 +101,4 @@ namespace campvis {
this->setViewMode(QMdiArea::TabbedView); this->setViewMode(QMdiArea::TabbedView);
} }
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();
floatingWindow->hide();
QWidget* widget = floatingWindow->widget();
MdiDockedWindow* dockedWindow = new MdiDockedWindow();
dockedWindow->setWidget(widget);
dockedWindow->setWindowTitle(floatingWindow->windowTitle());
this->addDockedWindow(dockedWindow);
widget->show();
floatingWindow->deleteLater();
dockedWindow->forceWindowDrag();
}
}
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);
MdiFloatingWindow* floatingWindow = new MdiFloatingWindow(widget);
floatingWindow->setWindowTitle(dockedWindow->windowTitle());
floatingWindow->forceWindowDrag();
connect(floatingWindow, SIGNAL(s_positionChanged(MdiFloatingWindow*, const QPoint&)),
this, SLOT(trackFloatingWindowsPosition(MdiFloatingWindow*, const QPoint&)));
dockedWindow->deleteLater();
tileSubWindows();
floatingWindow->show();
}
}
} }
...@@ -30,21 +30,21 @@ ...@@ -30,21 +30,21 @@
#ifndef MDIDOCKAREA_H__ #ifndef MDIDOCKAREA_H__
#define MDIDOCKAREA_H__ #define MDIDOCKAREA_H__
#include "mdidockedwindow.h" #include "mdidockablewindow.h"
#include "mdifloatingwindow.h"
#include <QMdiArea> #include <QMdiArea>
class QSignalMapper;
namespace campvis { namespace campvis {
/** /**
* MDI area whose subwindows can be docked and undocked. * MDI area whose subwindows can be docked and undocked.
* *
* MdiDockArea takes care of creating all necessary representations (docked and floating window) * MdiDockArea extends QMdiArea's functionality by adding support for dockable MDI windows. It
* of the widgets passed to \ref addSubWindow and seamlessly switching between them in response * provides 2 APIs:
* to the user's actions (window dragging, key presses, etc). * - 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 { class MdiDockArea : public QMdiArea {
...@@ -59,39 +59,40 @@ namespace campvis { ...@@ -59,39 +59,40 @@ namespace campvis {
explicit MdiDockArea(QWidget* parent = 0); explicit MdiDockArea(QWidget* parent = 0);
/** /**
* Wrap \p widget in an MDI window and dock it in the MDI area. * Wrap \p widget in a dockable MDI window and add it to the MDI area.
* *
* This method creates a MdiDockedWindow wrapping the widget, and adds 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 widget the widget to add to the MDI area
* \param windowFlags flags used to customize the frame of the created subwindow * \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);
/** /**
* Return a menu that lets the user control how the area's contents are displayed. * Add \p mdiSubWindow to the MDI area.
* *
* The menu contains actions that make it possible to change the layout and visibility of * \param mdiSubWindow the MDI sub-window to be added to the MDI area
* the area's subwindows. * \return the MDI sub-window that was passed in
*/