diff options
-rw-r--r-- | src/widgets/widgets/qmainwindow.cpp | 171 | ||||
-rw-r--r-- | src/widgets/widgets/qmainwindowlayout.cpp | 58 | ||||
-rw-r--r-- | src/widgets/widgets/qmainwindowlayout_p.h | 263 |
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 |