diff options
Diffstat (limited to 'src/widgets/widgets/qtoolbar.cpp')
-rw-r--r-- | src/widgets/widgets/qtoolbar.cpp | 352 |
1 files changed, 113 insertions, 239 deletions
diff --git a/src/widgets/widgets/qtoolbar.cpp b/src/widgets/widgets/qtoolbar.cpp index 4af71c126e..5e5ef8e8d5 100644 --- a/src/widgets/widgets/qtoolbar.cpp +++ b/src/widgets/widgets/qtoolbar.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWidgets module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qtoolbar.h" @@ -43,6 +7,9 @@ #if QT_CONFIG(combobox) #include <qcombobox.h> #endif +#if QT_CONFIG(draganddrop) +#include <qdrag.h> +#endif #include <qevent.h> #include <qlayout.h> #include <qmainwindow.h> @@ -50,10 +17,10 @@ #if QT_CONFIG(menubar) #include <qmenubar.h> #endif +#include <qmimedata.h> #if QT_CONFIG(rubberband) #include <qrubberband.h> #endif -#include <qsignalmapper.h> #include <qstylepainter.h> #include <qstyleoption.h> #include <qtoolbutton.h> @@ -61,8 +28,9 @@ #include <qtimer.h> #include <private/qwidgetaction_p.h> #include <private/qmainwindowlayout_p.h> +#include <private/qhighdpiscaling_p.h> -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS #include <qpa/qplatformnativeinterface.h> #endif @@ -76,6 +44,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + // qmainwindow.cpp extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window); @@ -92,7 +62,7 @@ void QToolBarPrivate::init() q->setAttribute(Qt::WA_X11NetWmWindowTypeToolBar); QStyle *style = q->style(); - int e = style->pixelMetric(QStyle::PM_ToolBarIconSize, 0, q); + int e = style->pixelMetric(QStyle::PM_ToolBarIconSize, nullptr, q); iconSize = QSize(e, e); layout = new QToolBarLayout(q); @@ -100,7 +70,7 @@ void QToolBarPrivate::init() toggleViewAction = new QAction(q); toggleViewAction->setCheckable(true); - q->setMovable(q->style()->styleHint(QStyle::SH_ToolBar_Movable, 0, q )); + q->setMovable(q->style()->styleHint(QStyle::SH_ToolBar_Movable, nullptr, q )); QObject::connect(toggleViewAction, SIGNAL(triggered(bool)), q, SLOT(_q_toggleView(bool))); } @@ -141,8 +111,12 @@ void QToolBarPrivate::updateWindowFlags(bool floating, bool unplug) flags |= Qt::FramelessWindowHint; - if (unplug) +#if QT_CONFIG(draganddrop) + // If we are performing a platform drag the flag is not needed and we want to avoid recreating + // the platform window when it would be removed later + if (unplug && !QMainWindowLayout::needsPlatformDrag()) flags |= Qt::X11BypassWindowManagerHint; +#endif q->setWindowFlags(flags); } @@ -153,8 +127,6 @@ void QToolBarPrivate::setWindowState(bool floating, bool unplug, const QRect &re bool visible = !q->isHidden(); bool wasFloating = q->isFloating(); // ...is also currently using popup menus - q->hide(); - updateWindowFlags(floating, unplug); if (floating != wasFloating) @@ -174,21 +146,21 @@ void QToolBarPrivate::initDrag(const QPoint &pos) { Q_Q(QToolBar); - if (state != 0) + if (state != nullptr) return; QMainWindow *win = qobject_cast<QMainWindow*>(parent); - Q_ASSERT(win != 0); + Q_ASSERT(win != nullptr); QMainWindowLayout *layout = qt_mainwindow_layout(win); - Q_ASSERT(layout != 0); - if (layout->pluggingWidget != 0) // the main window is animating a docking operation + Q_ASSERT(layout != nullptr); + if (layout->pluggingWidget != nullptr) // the main window is animating a docking operation return; state = new DragState; state->pressPos = pos; state->dragging = false; state->moving = false; - state->widgetItem = 0; + state->widgetItem = nullptr; if (q->isRightToLeft()) state->pressPos = QPoint(q->width() - state->pressPos.x(), state->pressPos.y()); @@ -198,34 +170,51 @@ void QToolBarPrivate::startDrag(bool moving) { Q_Q(QToolBar); - Q_ASSERT(state != 0); + Q_ASSERT(state != nullptr); if ((moving && state->moving) || state->dragging) return; QMainWindow *win = qobject_cast<QMainWindow*>(parent); - Q_ASSERT(win != 0); + Q_ASSERT(win != nullptr); QMainWindowLayout *layout = qt_mainwindow_layout(win); - Q_ASSERT(layout != 0); + Q_ASSERT(layout != nullptr); + +#if QT_CONFIG(draganddrop) + const bool wasFloating = q->isFloating(); +#endif if (!moving) { - state->widgetItem = layout->unplug(q); - Q_ASSERT(state->widgetItem != 0); + state->widgetItem = layout->unplug(q, QDockWidgetPrivate::DragScope::Group); + Q_ASSERT(state->widgetItem != nullptr); } state->dragging = !moving; state->moving = moving; + +#if QT_CONFIG(draganddrop) + if (QMainWindowLayout::needsPlatformDrag() && state->dragging) { + auto result = layout->performPlatformWidgetDrag(state->widgetItem, state->pressPos); + if (result == Qt::IgnoreAction && !wasFloating) { + layout->revert(state->widgetItem); + delete state; + state = nullptr; + } else { + endDrag(); + } + } +#endif } void QToolBarPrivate::endDrag() { Q_Q(QToolBar); - Q_ASSERT(state != 0); + Q_ASSERT(state != nullptr); q->releaseMouse(); if (state->dragging) { QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget())); - Q_ASSERT(layout != 0); + Q_ASSERT(layout != nullptr); if (!layout->plug(state->widgetItem)) { if (q->isFloatable()) { @@ -240,7 +229,7 @@ void QToolBarPrivate::endDrag() } delete state; - state = 0; + state = nullptr; } bool QToolBarPrivate::mousePressEvent(QMouseEvent *event) @@ -248,8 +237,8 @@ bool QToolBarPrivate::mousePressEvent(QMouseEvent *event) Q_Q(QToolBar); QStyleOptionToolBar opt; q->initStyleOption(&opt); - if (q->style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, q).contains(event->pos()) == false) { -#ifdef Q_OS_OSX + if (q->style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, q).contains(event->position().toPoint()) == false) { +#ifdef Q_OS_MACOS // When using the unified toolbar on OS X, the user can click and // drag between toolbar contents to move the window. Make this work by // implementing the standard mouse-dragging code and then call @@ -273,17 +262,24 @@ bool QToolBarPrivate::mousePressEvent(QMouseEvent *event) if (!layout->movable()) return true; - initDrag(event->pos()); + initDrag(event->position().toPoint()); return true; } bool QToolBarPrivate::mouseReleaseEvent(QMouseEvent*) { - if (state != 0) { +#if QT_CONFIG(draganddrop) + // if we are peforming a platform drag ignore the release here and end the drag when the actual + // drag ends. + if (QMainWindowLayout::needsPlatformDrag()) + return false; +#endif + + if (state != nullptr) { endDrag(); return true; } else { -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS if (!macWindowDragging) return false; macWindowDragging = false; @@ -299,7 +295,7 @@ bool QToolBarPrivate::mouseMoveEvent(QMouseEvent *event) Q_Q(QToolBar); if (!state) { -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS if (!macWindowDragging) return false; QWidget *w = q->window(); @@ -311,31 +307,31 @@ bool QToolBarPrivate::mouseMoveEvent(QMouseEvent *event) } QMainWindow *win = qobject_cast<QMainWindow*>(parent); - if (win == 0) + if (win == nullptr) return true; QMainWindowLayout *layout = qt_mainwindow_layout(win); - Q_ASSERT(layout != 0); + Q_ASSERT(layout != nullptr); - if (layout->pluggingWidget == 0 - && (event->pos() - state->pressPos).manhattanLength() > QApplication::startDragDistance()) { + if (layout->pluggingWidget == nullptr + && (event->position().toPoint() - state->pressPos).manhattanLength() > QApplication::startDragDistance()) { const bool wasDragging = state->dragging; const bool moving = !q->isWindow() && (orientation == Qt::Vertical ? - event->x() >= 0 && event->x() < q->width() : - event->y() >= 0 && event->y() < q->height()); + event->position().toPoint().x() >= 0 && event->position().toPoint().x() < q->width() : + event->position().toPoint().y() >= 0 && event->position().toPoint().y() < q->height()); startDrag(moving); - if (!moving && !wasDragging) { -#if 0 // Used to be included in Qt4 for Q_WS_WIN - grabMouseWhileInWindow(); -#else + if (!moving && !wasDragging) q->grabMouse(); -#endif - } + } + + if (!state) { + q->releaseMouse(); + return true; } if (state->dragging) { - QPoint pos = event->globalPos(); + QPoint pos = event->globalPosition().toPoint(); // if we are right-to-left, we move so as to keep the right edge the same distance // from the mouse if (q->isLeftToRight()) @@ -344,14 +340,19 @@ bool QToolBarPrivate::mouseMoveEvent(QMouseEvent *event) pos += QPoint(state->pressPos.x() - q->width(), -state->pressPos.y()); q->move(pos); - layout->hover(state->widgetItem, event->globalPos()); + layout->hover(state->widgetItem, event->globalPosition().toPoint()); } else if (state->moving) { const QPoint rtl(q->width() - state->pressPos.x(), state->pressPos.y()); //for RTL const QPoint globalPressPos = q->mapToGlobal(q->isRightToLeft() ? rtl : state->pressPos); int pos = 0; - QPoint delta = event->globalPos() - globalPressPos; + const QWindow *handle = q->window() ? q->window()->windowHandle() : nullptr; + const QPoint delta = handle + ? QHighDpi::fromNativePixels(event->globalPosition(), handle).toPoint() + - QHighDpi::fromNativePixels(globalPressPos, handle) + : event->globalPosition().toPoint() - globalPressPos; + if (orientation == Qt::Vertical) { pos = q->y() + delta.y(); } else { @@ -394,6 +395,10 @@ void QToolBarPrivate::plug(const QRect &r) \ingroup mainwindow-classes \inmodule QtWidgets + A toolbar is typically created by calling + \l QMainWindow::addToolBar(const QString &title), but it can also + be added as the first widget in a QVBoxLayout, for example. + Toolbar buttons are added by adding \e actions, using addAction() or insertAction(). Groups of buttons can be separated using addSeparator() or insertSeparator(). If a toolbar button is not @@ -417,7 +422,7 @@ void QToolBarPrivate::plug(const QRect &r) addWidget(). Please use widget actions created by inheriting QWidgetAction and implementing QWidgetAction::createWidget() instead. - \sa QToolButton, QMenu, QAction, {Application Example} + \sa QToolButton, QMenu, QAction */ /*! @@ -509,7 +514,7 @@ void QToolBarPrivate::plug(const QRect &r) Constructs a QToolBar with the given \a parent. */ QToolBar::QToolBar(QWidget *parent) - : QWidget(*new QToolBarPrivate, parent, 0) + : QWidget(*new QToolBarPrivate, parent, { }) { Q_D(QToolBar); d->init(); @@ -679,16 +684,16 @@ void QToolBar::setIconSize(const QSize &iconSize) if (mw && mw->layout()) { QLayout *layout = mw->layout(); int i = 0; - QLayoutItem *item = 0; + QLayoutItem *item = nullptr; do { item = layout->itemAt(i++); if (item && (item->widget() == this)) sz = mw->iconSize(); - } while (!sz.isValid() && item != 0); + } while (!sz.isValid() && item != nullptr); } } if (!sz.isValid()) { - const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, 0, this); + const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, nullptr, this); sz = QSize(metric, metric); } if (d->iconSize != sz) { @@ -743,139 +748,6 @@ void QToolBar::clear() } /*! - Creates a new action with the given \a text. This action is added to - the end of the toolbar. -*/ -QAction *QToolBar::addAction(const QString &text) -{ - QAction *action = new QAction(text, this); - addAction(action); - return action; -} - -/*! - \overload - - Creates a new action with the given \a icon and \a text. This - action is added to the end of the toolbar. -*/ -QAction *QToolBar::addAction(const QIcon &icon, const QString &text) -{ - QAction *action = new QAction(icon, text, this); - addAction(action); - return action; -} - -/*! - \overload - - Creates a new action with the given \a text. This action is added to - the end of the toolbar. The action's \l{QAction::triggered()}{triggered()} - signal is connected to \a member in \a receiver. -*/ -QAction *QToolBar::addAction(const QString &text, - const QObject *receiver, const char* member) -{ - QAction *action = new QAction(text, this); - QObject::connect(action, SIGNAL(triggered(bool)), receiver, member); - addAction(action); - return action; -} - -/*! - \overload - - Creates a new action with the given \a icon and \a text. This - action is added to the end of the toolbar. The action's - \l{QAction::triggered()}{triggered()} signal is connected to \a - member in \a receiver. -*/ -QAction *QToolBar::addAction(const QIcon &icon, const QString &text, - const QObject *receiver, const char* member) -{ - QAction *action = new QAction(icon, text, this); - QObject::connect(action, SIGNAL(triggered(bool)), receiver, member); - addAction(action); - return action; -} - -/*!\fn template<typename PointerToMemberFunction> QAction *QToolBar::addAction(const QString &text, const QObject *receiver, PointerToMemberFunction method) - - \since 5.6 - - \overload - - Creates a new action with the given \a text. This action is added to - the end of the toolbar. The action's - \l{QAction::triggered()}{triggered()} signal is connected to the - \a method of the \a receiver. -*/ - -/*!\fn template<typename Functor> QAction *QToolBar::addAction(const QString &text, Functor functor) - - \since 5.6 - - \overload - - Creates a new action with the given \a text. This action is added to - the end of the toolbar. The action's - \l{QAction::triggered()}{triggered()} signal is connected to the - \a functor. -*/ - -/*!\fn template<typename Functor> QAction *QToolBar::addAction(const QString &text, const QObject *context, Functor functor) - - \since 5.6 - - \overload - - Creates a new action with the given \a text. This action is added to - the end of the toolbar. The action's - \l{QAction::triggered()}{triggered()} signal is connected to the - \a functor. - - If \a context is destroyed, the functor will not be called. -*/ - -/*!\fn template<typename PointerToMemberFunction> QAction *QToolBar::addAction(const QIcon &icon, const QString &text, const QObject *receiver, PointerToMemberFunction method) - - \since 5.6 - - \overload - - Creates a new action with the given \a icon and \a text. This - action is added to the end of the toolbar. The action's - \l{QAction::triggered()}{triggered()} signal is connected to the - \a method of the \a receiver. -*/ - -/*!\fn template<typename Functor> QAction *QToolBar::addAction(const QIcon &icon, const QString &text, Functor functor) - - \since 5.6 - - \overload - - Creates a new action with the given \a icon and \a text. This - action is added to the end of the toolbar. The action's - \l{QAction::triggered()}{triggered()} signal is connected to the - \a functor. -*/ - -/*!\fn template<typename Functor> QAction *QToolBar::addAction(const QIcon &icon, const QString &text, const QObject *context, Functor functor) - - \since 5.6 - - \overload - - Creates a new action with the given \a icon and \a text. This - action is added to the end of the toolbar. The action's - \l{QAction::triggered()}{triggered()} signal is connected to the - \a functor. - - If \a context is destroyed, the functor will not be called. -*/ - -/*! Adds a separator to the end of the toolbar. \sa insertSeparator() @@ -973,7 +845,7 @@ QAction *QToolBar::actionAt(const QPoint &p) const QWidget *widget = childAt(p); int index = d->layout->indexOf(widget); if (index == -1) - return 0; + return nullptr; QLayoutItem *item = d->layout->itemAt(index); return static_cast<QToolBarItem*>(item)->action; } @@ -989,12 +861,12 @@ QAction *QToolBar::actionAt(const QPoint &p) const void QToolBar::actionEvent(QActionEvent *event) { Q_D(QToolBar); - QAction *action = event->action(); + auto action = static_cast<QAction *>(event->action()); QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(action); switch (event->type()) { case QEvent::ActionAdded: { - Q_ASSERT_X(widgetAction == 0 || d->layout->indexOf(widgetAction) == -1, + Q_ASSERT_X(widgetAction == nullptr || d->layout->indexOf(widgetAction) == -1, "QToolBar", "widgets cannot be inserted multiple times"); // reparent the action to this toolbar if it has been created @@ -1002,7 +874,7 @@ void QToolBar::actionEvent(QActionEvent *event) // preserve Qt 4.1.x behavior. The widget is already // reparented to us due to the createWidget call inside // createItem() - if (widgetAction != 0 && widgetAction->d_func()->autoCreated) + if (widgetAction != nullptr && widgetAction->d_func()->autoCreated) widgetAction->setParent(this); int index = d->layout->count(); @@ -1067,7 +939,7 @@ void QToolBar::paintEvent(QPaintEvent *) if (d->layout->expanded || d->layout->animating || isWindow()) { //if the toolbar is expended, we need to fill the background with the window color //because some styles may expects that. - p.fillRect(opt.rect, palette().background()); + p.fillRect(opt.rect, palette().window()); style->drawControl(QStyle::CE_ToolBar, &opt, &p, this); style->drawPrimitive(QStyle::PE_FrameMenu, &opt, &p, this); } else { @@ -1087,31 +959,32 @@ void QToolBar::paintEvent(QPaintEvent *) */ static bool waitForPopup(QToolBar *tb, QWidget *popup) { - if (popup == 0 || popup->isHidden()) + if (popup == nullptr || popup->isHidden()) return false; QWidget *w = popup; - while (w != 0) { + while (w != nullptr) { if (w == tb) return true; w = w->parentWidget(); } QMenu *menu = qobject_cast<QMenu*>(popup); - if (menu == 0) + if (menu == nullptr) return false; - QAction *action = menu->menuAction(); - QList<QWidget*> widgets = action->associatedWidgets(); - for (int i = 0; i < widgets.count(); ++i) { - if (waitForPopup(tb, widgets.at(i))) - return true; + const QAction *action = menu->menuAction(); + for (auto object : action->associatedObjects()) { + if (QWidget *widget = qobject_cast<QWidget*>(object)) { + if (waitForPopup(tb, widget)) + return true; + } } return false; } -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS static void enableMacToolBar(QToolBar *toolbar, bool enable) { QPlatformNativeInterface *nativeInterface = QApplication::platformNativeInterface(); @@ -1150,7 +1023,7 @@ bool QToolBar::event(QEvent *event) Q_FALLTHROUGH(); case QEvent::Show: d->toggleViewAction->setChecked(event->type() == QEvent::Show); -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS enableMacToolBar(this, event->type() == QEvent::Show); #endif emit visibilityChanged(event->type() == QEvent::Show); @@ -1177,7 +1050,7 @@ bool QToolBar::event(QEvent *event) QHoverEvent *e = static_cast<QHoverEvent*>(event); QStyleOptionToolBar opt; initStyleOption(&opt); - if (style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, this).contains(e->pos())) + if (style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, this).contains(e->position().toPoint())) setCursor(Qt::SizeAllCursor); else unsetCursor(); @@ -1189,12 +1062,12 @@ bool QToolBar::event(QEvent *event) return true; break; case QEvent::Leave: - if (d->state != 0 && d->state->dragging) { + if (d->state != nullptr && d->state->dragging) { #ifdef Q_OS_WIN - // This is a workaround for loosing the mouse on Vista. + // This is a workaround for losing the mouse on Vista. QPoint pos = QCursor::pos(); QMouseEvent fake(QEvent::MouseMove, mapFromGlobal(pos), pos, Qt::NoButton, - QApplication::mouseButtons(), QApplication::keyboardModifiers()); + QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); d->mouseMoveEvent(&fake); #endif } else { @@ -1211,6 +1084,7 @@ bool QToolBar::event(QEvent *event) d->layout->setExpanded(false); break; } + break; default: break; } @@ -1241,7 +1115,7 @@ QWidget *QToolBar::widgetForAction(QAction *action) const int index = d->layout->indexOf(action); if (index == -1) - return 0; + return nullptr; return d->layout->itemAt(index)->widget(); } @@ -1261,7 +1135,7 @@ void QToolBar::initStyleOption(QStyleOptionToolBar *option) const option->initFrom(this); if (orientation() == Qt::Horizontal) option->state |= QStyle::State_Horizontal; - option->lineWidth = style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, 0, this); + option->lineWidth = style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, nullptr, this); option->features = d->layout->movable() ? QStyleOptionToolBar::Movable : QStyleOptionToolBar::None; @@ -1275,7 +1149,7 @@ void QToolBar::initStyleOption(QStyleOptionToolBar *option) const return; QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow); - Q_ASSERT_X(layout != 0, "QToolBar::initStyleOption()", + Q_ASSERT_X(layout != nullptr, "QToolBar::initStyleOption()", "QMainWindow->layout() != QMainWindowLayout"); layout->getStyleOptionInfo(option, const_cast<QToolBar *>(this)); |