summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier Goffart <ogoffart@woboq.com>2017-02-28 16:03:30 +0100
committerOlivier Goffart (Woboq GmbH) <ogoffart@woboq.com>2017-04-13 17:44:33 +0000
commit60be2fb6a13315f074c3c0b7793c38632f291e8b (patch)
tree08abce1c5f4240205776e00936df8160d90af8d8
parent46458ce3ef4aeb01fef97348dcd317f0edd7e5fb (diff)
QMainWindow: move the separator handling in another class
So it will be re-used by QDockWidgetGroupWindow The Layout template argument can be the QMainWindowLayout, or the QDockWidgetGroupLayout. They have a function dockAreaLayoutInfo which return a QDockAreaLayout* or a QDockAreaLayoutInfo*, respectively. These two class have the same interface as far as QMainWindowLayoutSeparatorHelper is concerned. (QDockAreaLayout forward most of its call to the relevant QDockAreaLayoutInfo) The code is mostly moved without modification, but there is a change in startSeparatorMove, because we don't have access to the layoutState to set the fallbackToSizeHints variable, so instead, we do that from QMainWindowLayout::hover. Change-Id: Ic5fa3ee2def3d0155195f751d4770b207732139f Reviewed-by: Sérgio Martins <sergio.martins@kdab.com>
-rw-r--r--src/widgets/widgets/qmainwindow.cpp171
-rw-r--r--src/widgets/widgets/qmainwindowlayout.cpp58
-rw-r--r--src/widgets/widgets/qmainwindowlayout_p.h263
3 files changed, 254 insertions, 238 deletions
diff --git a/src/widgets/widgets/qmainwindow.cpp b/src/widgets/widgets/qmainwindow.cpp
index 8eb5669f1c..e47efb50b3 100644
--- a/src/widgets/widgets/qmainwindow.cpp
+++ b/src/widgets/widgets/qmainwindow.cpp
@@ -73,9 +73,6 @@ public:
#ifdef Q_OS_OSX
, useUnifiedToolBar(false)
#endif
-#if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR)
- , hasOldCursor(false) , cursorAdjusted(false)
-#endif
{ }
QMainWindowLayout *layout;
QSize iconSize;
@@ -85,17 +82,6 @@ public:
bool useUnifiedToolBar;
#endif
void init();
- QList<int> hoverSeparator;
- QPoint hoverPos;
-
-#if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR)
- QCursor separatorCursor(const QList<int> &path) const;
- void adjustCursor(const QPoint &pos);
- QCursor oldCursor;
- QCursor adjustedCursor;
- uint hasOldCursor : 1;
- uint cursorAdjusted : 1;
-#endif
static inline QMainWindowLayout *mainWindowLayout(const QMainWindow *mainWindow)
{
@@ -1310,153 +1296,14 @@ bool QMainWindow::restoreState(const QByteArray &state, int version)
return restored;
}
-#if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR)
-QCursor QMainWindowPrivate::separatorCursor(const QList<int> &path) const
-{
- QDockAreaLayoutInfo *info = layout->layoutState.dockAreaLayout.info(path);
- Q_ASSERT(info != 0);
- if (path.size() == 1) { // is this the "top-level" separator which separates a dock area
- // from the central widget?
- switch (path.first()) {
- case QInternal::LeftDock:
- case QInternal::RightDock:
- return Qt::SplitHCursor;
- case QInternal::TopDock:
- case QInternal::BottomDock:
- return Qt::SplitVCursor;
- default:
- break;
- }
- }
-
- // no, it's a splitter inside a dock area, separating two dock widgets
-
- return info->o == Qt::Horizontal
- ? Qt::SplitHCursor : Qt::SplitVCursor;
-}
-
-void QMainWindowPrivate::adjustCursor(const QPoint &pos)
-{
- Q_Q(QMainWindow);
-
- hoverPos = pos;
-
- if (pos == QPoint(0, 0)) {
- if (!hoverSeparator.isEmpty())
- q->update(layout->layoutState.dockAreaLayout.separatorRect(hoverSeparator));
- hoverSeparator.clear();
-
- if (cursorAdjusted) {
- cursorAdjusted = false;
- if (hasOldCursor)
- q->setCursor(oldCursor);
- else
- q->unsetCursor();
- }
- } else if (layout->movingSeparator.isEmpty()) { // Don't change cursor when moving separator
- QList<int> pathToSeparator
- = layout->layoutState.dockAreaLayout.findSeparator(pos);
-
- if (pathToSeparator != hoverSeparator) {
- if (!hoverSeparator.isEmpty())
- q->update(layout->layoutState.dockAreaLayout.separatorRect(hoverSeparator));
-
- hoverSeparator = pathToSeparator;
-
- if (hoverSeparator.isEmpty()) {
- if (cursorAdjusted) {
- cursorAdjusted = false;
- if (hasOldCursor)
- q->setCursor(oldCursor);
- else
- q->unsetCursor();
- }
- } else {
- q->update(layout->layoutState.dockAreaLayout.separatorRect(hoverSeparator));
- if (!cursorAdjusted) {
- oldCursor = q->cursor();
- hasOldCursor = q->testAttribute(Qt::WA_SetCursor);
- }
- adjustedCursor = separatorCursor(hoverSeparator);
- q->setCursor(adjustedCursor);
- cursorAdjusted = true;
- }
- }
- }
-}
-#endif
-
/*! \reimp */
bool QMainWindow::event(QEvent *event)
{
Q_D(QMainWindow);
+ if (d->layout && d->layout->windowEvent(event))
+ return true;
switch (event->type()) {
-#ifndef QT_NO_DOCKWIDGET
- case QEvent::Paint: {
- QPainter p(this);
- QRegion r = static_cast<QPaintEvent*>(event)->region();
- d->layout->layoutState.dockAreaLayout.paintSeparators(&p, this, r, d->hoverPos);
- break;
- }
-
-#ifndef QT_NO_CURSOR
- case QEvent::HoverMove: {
- d->adjustCursor(static_cast<QHoverEvent*>(event)->pos());
- break;
- }
-
- // We don't want QWidget to call update() on the entire QMainWindow
- // on HoverEnter and HoverLeave, hence accept the event (return true).
- case QEvent::HoverEnter:
- return true;
- case QEvent::HoverLeave:
- d->adjustCursor(QPoint(0, 0));
- return true;
- case QEvent::ShortcutOverride: // when a menu pops up
- d->adjustCursor(QPoint(0, 0));
- break;
-#endif // QT_NO_CURSOR
-
- case QEvent::MouseButtonPress: {
- QMouseEvent *e = static_cast<QMouseEvent*>(event);
- if (e->button() == Qt::LeftButton && d->layout->startSeparatorMove(e->pos())) {
- // The click was on a separator, eat this event
- e->accept();
- return true;
- }
- break;
- }
-
- case QEvent::MouseMove: {
- QMouseEvent *e = static_cast<QMouseEvent*>(event);
-
-#ifndef QT_NO_CURSOR
- d->adjustCursor(e->pos());
-#endif
- if (e->buttons() & Qt::LeftButton) {
- if (d->layout->separatorMove(e->pos())) {
- // We're moving a separator, eat this event
- e->accept();
- return true;
- }
- }
-
- break;
- }
-
- case QEvent::MouseButtonRelease: {
- QMouseEvent *e = static_cast<QMouseEvent*>(event);
- if (d->layout->endSeparatorMove(e->pos())) {
- // We've released a separator, eat this event
- e->accept();
- return true;
- }
- break;
- }
-
-#endif
-
#ifndef QT_NO_TOOLBAR
case QEvent::ToolBarChange: {
d->layout->toggleToolBarsVisible();
@@ -1482,20 +1329,6 @@ bool QMainWindow::event(QEvent *event)
if (!d->explicitIconSize)
setIconSize(QSize());
break;
-#if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR)
- case QEvent::CursorChange:
- // CursorChange events are triggered as mouse moves to new widgets even
- // if the cursor doesn't actually change, so do not change oldCursor if
- // the "changed" cursor has same shape as adjusted cursor.
- if (d->cursorAdjusted && d->adjustedCursor.shape() != cursor().shape()) {
- d->oldCursor = cursor();
- d->hasOldCursor = testAttribute(Qt::WA_SetCursor);
-
- // Ensure our adjusted cursor stays visible
- setCursor(d->adjustedCursor);
- }
- break;
-#endif
default:
break;
}
diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp
index 98421588a7..30217733cf 100644
--- a/src/widgets/widgets/qmainwindowlayout.cpp
+++ b/src/widgets/widgets/qmainwindowlayout.cpp
@@ -1689,39 +1689,6 @@ void QMainWindowLayout::tabMoved(int from, int to)
}
#endif // QT_NO_TABBAR
-bool QMainWindowLayout::startSeparatorMove(const QPoint &pos)
-{
- movingSeparator = layoutState.dockAreaLayout.findSeparator(pos);
-
- if (movingSeparator.isEmpty())
- return false;
-
- layoutState.dockAreaLayout.fallbackToSizeHints = false;
-
- savedState = layoutState;
- movingSeparatorPos = movingSeparatorOrigin = pos;
-
- return true;
-}
-
-bool QMainWindowLayout::separatorMove(const QPoint &pos)
-{
- if (movingSeparator.isEmpty())
- return false;
- movingSeparatorPos = pos;
- separatorMoveTimer.start(0, this);
- return true;
-}
-
-bool QMainWindowLayout::endSeparatorMove(const QPoint&)
-{
- if (movingSeparator.isEmpty())
- return false;
- movingSeparator.clear();
- savedState.clear();
- return true;
-}
-
void QMainWindowLayout::raise(QDockWidget *widget)
{
#ifndef QT_NO_TABBAR
@@ -2424,6 +2391,7 @@ void QMainWindowLayout::hover(QLayoutItem *widgetItem, const QPoint &mousePos)
}
}
setCurrentHoveredFloat(nullptr);
+ layoutState.dockAreaLayout.fallbackToSizeHints = false;
#endif //QT_NO_DOCKWIDGET
QPoint pos = parentWidget()->mapFromGlobal(mousePos);
@@ -2575,30 +2543,6 @@ bool QMainWindowLayout::restoreState(QDataStream &stream)
return true;
}
-void QMainWindowLayout::timerEvent(QTimerEvent *e)
-{
-#ifndef QT_NO_DOCKWIDGET
- if (e->timerId() == separatorMoveTimer.timerId()) {
- //let's move the separators
- separatorMoveTimer.stop();
- if (movingSeparator.isEmpty())
- return;
- if (movingSeparatorOrigin == movingSeparatorPos)
- return;
-
- //when moving the separator, we need to update the previous position
- parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
-
- layoutState = savedState;
- layoutState.dockAreaLayout.separatorMove(movingSeparator, movingSeparatorOrigin,
- movingSeparatorPos);
- movingSeparatorPos = movingSeparatorOrigin;
- }
-#endif
- QLayout::timerEvent(e);
-}
-
-
QT_END_NAMESPACE
#include "moc_qmainwindowlayout_p.cpp"
diff --git a/src/widgets/widgets/qmainwindowlayout_p.h b/src/widgets/widgets/qmainwindowlayout_p.h
index 507759fe96..dcd94e3617 100644
--- a/src/widgets/widgets/qmainwindowlayout_p.h
+++ b/src/widgets/widgets/qmainwindowlayout_p.h
@@ -58,6 +58,8 @@
#include "QtWidgets/qlayout.h"
#include "QtWidgets/qtabbar.h"
+#include "QtGui/qpainter.h"
+#include "QtGui/qevent.h"
#include "QtCore/qvector.h"
#include "QtCore/qset.h"
#include "QtCore/qbasictimer.h"
@@ -72,6 +74,251 @@ QT_BEGIN_NAMESPACE
class QToolBar;
class QRubberBand;
+template <typename Layout> // Make use of the "Curiously recurring template pattern"
+class QMainWindowLayoutSeparatorHelper
+{
+ Layout *layout() { return static_cast<Layout *>(this); }
+ const Layout *layout() const { return static_cast<const Layout *>(this); }
+ QWidget *window() { return layout()->parentWidget(); }
+
+public:
+ QList<int> hoverSeparator;
+ QPoint hoverPos;
+
+#if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR)
+ QCursor separatorCursor(const QList<int> &path);
+ void adjustCursor(const QPoint &pos);
+ QCursor oldCursor;
+ QCursor adjustedCursor;
+ bool hasOldCursor = false;
+ bool cursorAdjusted = false;
+
+ QList<int> movingSeparator;
+ QPoint movingSeparatorOrigin, movingSeparatorPos;
+ QBasicTimer separatorMoveTimer;
+
+ bool startSeparatorMove(const QPoint &pos);
+ bool separatorMove(const QPoint &pos);
+ bool endSeparatorMove(const QPoint &pos);
+
+#endif
+
+ bool windowEvent(QEvent *e);
+};
+
+#if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR)
+template <typename Layout>
+QCursor QMainWindowLayoutSeparatorHelper<Layout>::separatorCursor(const QList<int> &path)
+{
+ const QDockAreaLayoutInfo *info = layout()->dockAreaLayoutInfo()->info(path);
+ Q_ASSERT(info != 0);
+ if (path.size() == 1) { // is this the "top-level" separator which separates a dock area
+ // from the central widget?
+ switch (path.first()) {
+ case QInternal::LeftDock:
+ case QInternal::RightDock:
+ return Qt::SplitHCursor;
+ case QInternal::TopDock:
+ case QInternal::BottomDock:
+ return Qt::SplitVCursor;
+ default:
+ break;
+ }
+ }
+
+ // no, it's a splitter inside a dock area, separating two dock widgets
+
+ return info->o == Qt::Horizontal ? Qt::SplitHCursor : Qt::SplitVCursor;
+}
+
+template <typename Layout>
+void QMainWindowLayoutSeparatorHelper<Layout>::adjustCursor(const QPoint &pos)
+{
+ QWidget *w = layout()->window();
+ hoverPos = pos;
+
+ if (pos == QPoint(0, 0)) {
+ if (!hoverSeparator.isEmpty())
+ w->update(layout()->dockAreaLayoutInfo()->separatorRect(hoverSeparator));
+ hoverSeparator.clear();
+
+ if (cursorAdjusted) {
+ cursorAdjusted = false;
+ if (hasOldCursor)
+ w->setCursor(oldCursor);
+ else
+ w->unsetCursor();
+ }
+ } else if (movingSeparator.isEmpty()) { // Don't change cursor when moving separator
+ QList<int> pathToSeparator = layout()->dockAreaLayoutInfo()->findSeparator(pos);
+
+ if (pathToSeparator != hoverSeparator) {
+ if (!hoverSeparator.isEmpty())
+ w->update(layout()->dockAreaLayoutInfo()->separatorRect(hoverSeparator));
+
+ hoverSeparator = pathToSeparator;
+
+ if (hoverSeparator.isEmpty()) {
+ if (cursorAdjusted) {
+ cursorAdjusted = false;
+ if (hasOldCursor)
+ w->setCursor(oldCursor);
+ else
+ w->unsetCursor();
+ }
+ } else {
+ w->update(layout()->dockAreaLayoutInfo()->separatorRect(hoverSeparator));
+ if (!cursorAdjusted) {
+ oldCursor = w->cursor();
+ hasOldCursor = w->testAttribute(Qt::WA_SetCursor);
+ }
+ adjustedCursor = separatorCursor(hoverSeparator);
+ w->setCursor(adjustedCursor);
+ cursorAdjusted = true;
+ }
+ }
+ }
+}
+
+template <typename Layout>
+bool QMainWindowLayoutSeparatorHelper<Layout>::windowEvent(QEvent *event)
+{
+ QWidget *w = window();
+ switch (event->type()) {
+ case QEvent::Paint: {
+ QPainter p(w);
+ QRegion r = static_cast<QPaintEvent *>(event)->region();
+ layout()->dockAreaLayoutInfo()->paintSeparators(&p, w, r, hoverPos);
+ break;
+ }
+
+#ifndef QT_NO_CURSOR
+ case QEvent::HoverMove: {
+ adjustCursor(static_cast<QHoverEvent *>(event)->pos());
+ break;
+ }
+
+ // We don't want QWidget to call update() on the entire QMainWindow
+ // on HoverEnter and HoverLeave, hence accept the event (return true).
+ case QEvent::HoverEnter:
+ return true;
+ case QEvent::HoverLeave:
+ adjustCursor(QPoint(0, 0));
+ return true;
+ case QEvent::ShortcutOverride: // when a menu pops up
+ adjustCursor(QPoint(0, 0));
+ break;
+#endif // QT_NO_CURSOR
+
+ case QEvent::MouseButtonPress: {
+ QMouseEvent *e = static_cast<QMouseEvent *>(event);
+ if (e->button() == Qt::LeftButton && startSeparatorMove(e->pos())) {
+ // The click was on a separator, eat this event
+ e->accept();
+ return true;
+ }
+ break;
+ }
+
+ case QEvent::MouseMove: {
+ QMouseEvent *e = static_cast<QMouseEvent *>(event);
+
+#ifndef QT_NO_CURSOR
+ adjustCursor(e->pos());
+#endif
+ if (e->buttons() & Qt::LeftButton) {
+ if (separatorMove(e->pos())) {
+ // We're moving a separator, eat this event
+ e->accept();
+ return true;
+ }
+ }
+
+ break;
+ }
+
+ case QEvent::MouseButtonRelease: {
+ QMouseEvent *e = static_cast<QMouseEvent *>(event);
+ if (endSeparatorMove(e->pos())) {
+ // We've released a separator, eat this event
+ e->accept();
+ return true;
+ }
+ break;
+ }
+
+#if !defined(QT_NO_CURSOR)
+ case QEvent::CursorChange:
+ // CursorChange events are triggered as mouse moves to new widgets even
+ // if the cursor doesn't actually change, so do not change oldCursor if
+ // the "changed" cursor has same shape as adjusted cursor.
+ if (cursorAdjusted && adjustedCursor.shape() != w->cursor().shape()) {
+ oldCursor = w->cursor();
+ hasOldCursor = w->testAttribute(Qt::WA_SetCursor);
+
+ // Ensure our adjusted cursor stays visible
+ w->setCursor(adjustedCursor);
+ }
+ break;
+#endif
+ case QEvent::Timer:
+ if (static_cast<QTimerEvent *>(event)->timerId() == separatorMoveTimer.timerId()) {
+ // let's move the separators
+ separatorMoveTimer.stop();
+ if (movingSeparator.isEmpty())
+ return true;
+ if (movingSeparatorOrigin == movingSeparatorPos)
+ return true;
+
+ // when moving the separator, we need to update the previous position
+ window()->update(layout()->dockAreaLayoutInfo()->separatorRegion());
+
+ layout()->layoutState = layout()->savedState;
+ layout()->dockAreaLayoutInfo()->separatorMove(movingSeparator, movingSeparatorOrigin,
+ movingSeparatorPos);
+ movingSeparatorPos = movingSeparatorOrigin;
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+template <typename Layout>
+bool QMainWindowLayoutSeparatorHelper<Layout>::startSeparatorMove(const QPoint &pos)
+{
+ movingSeparator = layout()->dockAreaLayoutInfo()->findSeparator(pos);
+
+ if (movingSeparator.isEmpty())
+ return false;
+
+ layout()->savedState = layout()->layoutState;
+ movingSeparatorPos = movingSeparatorOrigin = pos;
+
+ return true;
+}
+template <typename Layout>
+bool QMainWindowLayoutSeparatorHelper<Layout>::separatorMove(const QPoint &pos)
+{
+ if (movingSeparator.isEmpty())
+ return false;
+ movingSeparatorPos = pos;
+ separatorMoveTimer.start(0, window());
+ return true;
+}
+template <typename Layout>
+bool QMainWindowLayoutSeparatorHelper<Layout>::endSeparatorMove(const QPoint &)
+{
+ if (movingSeparator.isEmpty())
+ return false;
+ movingSeparator.clear();
+ layout()->savedState.clear();
+ return true;
+}
+#endif
+
#ifndef QT_NO_DOCKWIDGET
class QDockWidgetGroupWindow : public QWidget
{
@@ -168,7 +415,9 @@ public:
bool restoreState(QDataStream &stream, const QMainWindowLayoutState &oldState);
};
-class Q_AUTOTEST_EXPORT QMainWindowLayout : public QLayout
+class Q_AUTOTEST_EXPORT QMainWindowLayout
+ : public QLayout,
+ public QMainWindowLayoutSeparatorHelper<QMainWindowLayout>
{
Q_OBJECT
@@ -181,8 +430,6 @@ public:
QMainWindow::DockOptions dockOptions;
void setDockOptions(QMainWindow::DockOptions opts);
- void timerEvent(QTimerEvent *e) Q_DECL_OVERRIDE;
-
// status bar
QLayoutItem *statusbar;
@@ -260,15 +507,7 @@ public:
#endif // QT_NO_TABWIDGET
#endif // QT_NO_TABBAR
- // separators
-
- QList<int> movingSeparator;
- QPoint movingSeparatorOrigin, movingSeparatorPos;
- QBasicTimer separatorMoveTimer;
-
- bool startSeparatorMove(const QPoint &pos);
- bool separatorMove(const QPoint &pos);
- bool endSeparatorMove(const QPoint &pos);
+ QDockAreaLayout *dockAreaLayoutInfo() { return &layoutState.dockAreaLayout; }
void keepSize(QDockWidget *w);
#endif // QT_NO_DOCKWIDGET