diff options
Diffstat (limited to 'src/widgets/widgets/qmenubar.cpp')
-rw-r--r-- | src/widgets/widgets/qmenubar.cpp | 85 |
1 files changed, 52 insertions, 33 deletions
diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 15c6f521b3..c9c9191c17 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -168,7 +168,7 @@ void QMenuBarPrivate::updateGeometries() for(int j = 0; j < shortcutIndexMap.size(); ++j) q->releaseShortcut(shortcutIndexMap.value(j)); shortcutIndexMap.clear(); - const int actionsCount = actions.count(); + const int actionsCount = actions.size(); shortcutIndexMap.reserve(actionsCount); for (int i = 0; i < actionsCount; i++) shortcutIndexMap.append(q->grabShortcut(QKeySequence::mnemonic(actions.at(i)->text()))); @@ -182,7 +182,7 @@ void QMenuBarPrivate::updateGeometries() //we try to see if the actions will fit there bool hasHiddenActions = false; - for (int i = 0; i < actions.count(); ++i) { + for (int i = 0; i < actions.size(); ++i) { const QRect &rect = actionRects.at(i); if (rect.isValid() && !menuRect.contains(rect)) { hasHiddenActions = true; @@ -193,7 +193,7 @@ void QMenuBarPrivate::updateGeometries() //...and if not, determine the ones that fit on the menu with the extension visible if (hasHiddenActions) { menuRect = this->menuRect(true); - for (int i = 0; i < actions.count(); ++i) { + for (int i = 0; i < actions.size(); ++i) { const QRect &rect = actionRects.at(i); if (rect.isValid() && !menuRect.contains(rect)) { hiddenActions.append(actions.at(i)); @@ -201,7 +201,7 @@ void QMenuBarPrivate::updateGeometries() } } - if (hiddenActions.count() > 0) { + if (hiddenActions.size() > 0) { QMenu *pop = extension->menu(); if (!pop) { pop = new QMenu(q); @@ -229,7 +229,7 @@ QRect QMenuBarPrivate::actionRect(QAction *act) const //makes sure the geometries are up-to-date const_cast<QMenuBarPrivate*>(this)->updateGeometries(); - if (index < 0 || index >= actionRects.count()) + if (index < 0 || index >= actionRects.size()) return QRect(); // that can happen in case of native menubar return actionRects.at(index); @@ -240,8 +240,8 @@ void QMenuBarPrivate::focusFirstAction() if (!currentAction) { updateGeometries(); int index = 0; - while (index < actions.count() && actionRects.at(index).isNull()) ++index; - if (index < actions.count()) + while (index < actions.size() && actionRects.at(index).isNull()) ++index; + if (index < actions.size()) setCurrentAction(actions.at(index)); } } @@ -281,17 +281,28 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) if (action->isEnabled() && action->menu()->isEnabled()) { closePopupMode = 0; activeMenu = action->menu(); - activeMenu->d_func()->causedPopup.widget = q; - activeMenu->d_func()->causedPopup.action = action; + auto *activeMenuPriv = activeMenu->d_func(); + activeMenuPriv->causedPopup.widget = q; + activeMenuPriv->causedPopup.action = action; QRect adjustedActionRect = actionRect(action); - QPoint pos(q->mapToGlobal(QPoint(adjustedActionRect.left(), adjustedActionRect.bottom() + 1))); - QSize popup_size = activeMenu->sizeHint(); + QPoint popupPos = adjustedActionRect.bottomLeft() + QPoint(0, 1); + //we put the popup menu on the screen containing the bottom-center of the action rect QScreen *menubarScreen = q->window()->windowHandle()->screen(); - QScreen *popupScreen = menubarScreen->virtualSiblingAt(pos + QPoint(adjustedActionRect.width() / 2, 0)); + QPoint screenTestPos = q->mapToGlobal(popupPos + QPoint(adjustedActionRect.width() / 2, 0)); + QPointer<QScreen> popupScreen = menubarScreen->virtualSiblingAt(screenTestPos); if (!popupScreen) popupScreen = menubarScreen; + std::swap(popupScreen, activeMenuPriv->popupScreen); + const QSize popup_size = activeMenu->sizeHint(); + std::swap(popupScreen, activeMenuPriv->popupScreen); + + // Use screenTestPos.y() for the popup y position. This is the correct global y + // consistent with the selected screen in cases where the action rect spans + // multiple screens with different scale factors. + QPoint pos(q->mapToGlobal(popupPos).x(), screenTestPos.y()); + QRect screenRect = popupScreen->geometry(); pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y())); const bool fitUp = (pos.y() - popup_size.height() >= screenRect.top()); @@ -378,7 +389,7 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const return; //let's reinitialize the buffer - actionRects.resize(actions.count()); + actionRects.resize(actions.size()); actionRects.fill(QRect()); const QStyle *style = q->style(); @@ -391,7 +402,7 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const const int hmargin = style->pixelMetric(QStyle::PM_MenuBarHMargin, nullptr, q), vmargin = style->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, q), icone = style->pixelMetric(QStyle::PM_SmallIconSize, nullptr, q); - for(int i = 0; i < actions.count(); i++) { + for(int i = 0; i < actions.size(); i++) { QAction *action = actions.at(i); if (!action->isVisible()) continue; @@ -437,7 +448,7 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const const int fw = q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, q); int x = fw + ((start == -1) ? hmargin : start) + itemSpacing; int y = fw + vmargin; - for(int i = 0; i < actions.count(); i++) { + for(int i = 0; i < actions.size(); i++) { QRect &rect = actionRects[i]; if (rect.isNull()) continue; @@ -596,11 +607,13 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti Qt for \macos also provides a menu bar merging feature to make QMenuBar conform more closely to accepted \macos menu bar layout. - The merging functionality is based on string matching the title of - a QMenu entry. These strings are translated (using QObject::tr()) - in the "QMenuBar" context. If an entry is moved its slots will still - fire as if it was in the original place. The table below outlines - the strings looked for and where the entry is placed if matched: + If an entry is moved its slots will still fire as if it was in the + original place. + + The merging functionality is based on the QAction::menuRole() of + the menu entries. If an item has QAction::TextHeuristicRole, + the role is determined by string matching the title using the + following heuristics: \table \header \li String matches \li Placement \li Notes @@ -618,8 +631,8 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti created to call QCoreApplication::quit() \endtable - You can override this behavior by using the QAction::menuRole() - property. + You can override this behavior by setting the QAction::menuRole() + property to QAction::NoRole. If you want all windows in a Mac application to share one menu bar, you must create a menu bar that does not have a parent. @@ -680,8 +693,8 @@ QAction *QMenuBarPrivate::getNextAction(const int _start, const int increment) c Q_Q(const QMenuBar); const_cast<QMenuBarPrivate*>(this)->updateGeometries(); bool allowActiveAndDisabled = q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, nullptr, q); - const int start = (_start == -1 && increment == -1) ? actions.count() : _start; - const int end = increment == -1 ? 0 : actions.count() - 1; + const int start = (_start == -1 && increment == -1) ? actions.size() : _start; + const int end = increment == -1 ? 0 : actions.size() - 1; for (int i = start; i != end;) { i += increment; @@ -884,7 +897,7 @@ void QMenuBar::paintEvent(QPaintEvent *e) QRegion emptyArea(rect()); //draw the items - for (int i = 0; i < d->actions.count(); ++i) { + for (int i = 0; i < d->actions.size(); ++i) { QAction *action = d->actions.at(i); QRect adjustedActionRect = d->actionRect(action); if (adjustedActionRect.isEmpty() || !d->isVisible(action)) @@ -912,7 +925,7 @@ void QMenuBar::paintEvent(QPaintEvent *e) frame.rect = rect(); frame.palette = palette(); frame.state = QStyle::State_None; - frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, &frame); + frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, &frame, this); frame.midLineWidth = 0; style()->drawPrimitive(QStyle::PE_PanelMenuBar, &frame, &p, this); } @@ -1060,7 +1073,7 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) if (!key_consumed && (!e->modifiers() || - (e->modifiers()&(Qt::MetaModifier|Qt::AltModifier))) && e->text().length()==1 && !d->popupState) { + (e->modifiers()&(Qt::MetaModifier|Qt::AltModifier))) && e->text().size()==1 && !d->popupState) { int clashCount = 0; QAction *first = nullptr, *currentSelected = nullptr, *firstAfterCurrent = nullptr; { @@ -1285,7 +1298,12 @@ void QMenuBarPrivate::handleReparent() QList<QPointer<QWidget>> newParents; // Remove event filters on ex-parents, keep them on still-parents // The parents are always ordered in the vector - foreach (const QPointer<QWidget> &w, oldParents) { + // + // Take a copy because this method is called from changeEvent() and eventFilter(), + // which might cause recursion into the class due to event processing, which might + // modify oldParents. + const auto copy = oldParents; + for (const QPointer<QWidget> &w : copy) { if (w) { if (newParent == w) { newParents.append(w); @@ -1356,7 +1374,7 @@ bool QMenuBar::event(QEvent *e) Q_D(QMenuBar); switch (e->type()) { case QEvent::KeyPress: { - QKeyEvent *ke = (QKeyEvent*)e; + QKeyEvent *ke = static_cast<QKeyEvent *>(e); #if 0 if (!d->keyboardState) { //all keypresses.. d->setCurrentAction(0); @@ -1384,7 +1402,7 @@ bool QMenuBar::event(QEvent *e) break; #ifndef QT_NO_SHORTCUT case QEvent::ShortcutOverride: { - QKeyEvent *kev = static_cast<QKeyEvent*>(e); + QKeyEvent *kev = static_cast<QKeyEvent *>(e); //we only filter out escape if there is a current action if (kev->matches(QKeySequence::Cancel) && d->currentAction) { e->accept(); @@ -1525,7 +1543,7 @@ QSize QMenuBar::minimumSizeHint() const if (as_gui_menubar) { int w = parentWidget() ? parentWidget()->width() : QGuiApplication::primaryScreen()->virtualGeometry().width(); d->calcActionRects(w - (2 * fw), 0); - for (int i = 0; ret.isNull() && i < d->actions.count(); ++i) + for (int i = 0; ret.isNull() && i < d->actions.size(); ++i) ret = d->actionRects.at(i).size(); if (!d->extension->isHidden()) ret += QSize(d->extension->sizeHint().width(), 0); @@ -1575,7 +1593,7 @@ QSize QMenuBar::sizeHint() const if (as_gui_menubar) { const int w = parentWidget() ? parentWidget()->width() : QGuiApplication::primaryScreen()->virtualGeometry().width(); d->calcActionRects(w - (2 * fw), 0); - for (int i = 0; i < d->actionRects.count(); ++i) { + for (int i = 0; i < d->actionRects.size(); ++i) { const QRect &actionRect = d->actionRects.at(i); ret = ret.expandedTo(QSize(actionRect.x() + actionRect.width(), actionRect.y() + actionRect.height())); } @@ -1622,7 +1640,7 @@ int QMenuBar::heightForWidth(int) const int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, this); int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, nullptr, this); if (as_gui_menubar) { - for (int i = 0; i < d->actionRects.count(); ++i) + for (int i = 0; i < d->actionRects.size(); ++i) height = qMax(height, d->actionRects.at(i).height()); if (height) //there is at least one non-null item height += spaceBelowMenuBar; @@ -1772,6 +1790,7 @@ void QMenuBar::setNativeMenuBar(bool nativeMenuBar) if (!nativeMenuBar) { delete d->platformMenuBar; d->platformMenuBar = nullptr; + d->itemsDirty = true; } else { if (!d->platformMenuBar) d->platformMenuBar = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar(); |