diff options
Diffstat (limited to 'src/widgets/widgets/qmenu.cpp')
-rw-r--r-- | src/widgets/widgets/qmenu.cpp | 149 |
1 files changed, 81 insertions, 68 deletions
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index cf306e63bd..57d7fb1bc8 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -77,6 +77,7 @@ #include <private/qaction_p.h> #include <private/qguiapplication_p.h> #include <qpa/qplatformtheme.h> +#include <private/qdesktopwidget_p.h> QT_BEGIN_NAMESPACE @@ -102,7 +103,7 @@ class QTornOffMenu : public QMenu Q_Q(QTornOffMenu); QSize size = menuSize; const QPoint p = (!initialized) ? causedMenu->pos() : q->pos(); - QRect screen = popupGeometry(QApplication::desktop()->screenNumber(p)); + QRect screen = popupGeometry(QDesktopWidgetPrivate::screenNumber(p)); const int desktopFrame = q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q); const int titleBarHeight = q->style()->pixelMetric(QStyle::PM_TitleBarHeight, 0, q); if (scroll && (size.height() > screen.height() - titleBarHeight || size.width() > screen.width())) { @@ -233,9 +234,6 @@ void QMenuPrivate::setPlatformMenu(QPlatformMenu *menu) } } -// forward declare function -static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item, QPlatformMenu *itemsMenu); - void QMenuPrivate::syncPlatformMenu() { Q_Q(QMenu); @@ -245,47 +243,92 @@ void QMenuPrivate::syncPlatformMenu() QPlatformMenuItem *beforeItem = Q_NULLPTR; const QList<QAction*> actions = q->actions(); for (QList<QAction*>::const_reverse_iterator it = actions.rbegin(), end = actions.rend(); it != end; ++it) { - QPlatformMenuItem *menuItem = platformMenu->createMenuItem(); - QAction *action = *it; - menuItem->setTag(reinterpret_cast<quintptr>(action)); - QObject::connect(menuItem, SIGNAL(activated()), action, SLOT(trigger()), Qt::QueuedConnection); - QObject::connect(menuItem, SIGNAL(hovered()), action, SIGNAL(hovered()), Qt::QueuedConnection); - copyActionToPlatformItem(action, menuItem, platformMenu.data()); - platformMenu->insertMenuItem(menuItem, beforeItem); + QPlatformMenuItem *menuItem = insertActionInPlatformMenu(*it, beforeItem); beforeItem = menuItem; } platformMenu->syncSeparatorsCollapsible(collapsibleSeparators); platformMenu->setEnabled(q->isEnabled()); } +void QMenuPrivate::copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item) +{ + item->setText(action->text()); + item->setIsSeparator(action->isSeparator()); + if (action->isIconVisibleInMenu()) { + item->setIcon(action->icon()); + if (QWidget *w = action->parentWidget()) { + QStyleOption opt; + opt.init(w); + item->setIconSize(w->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, w)); + } else { + QStyleOption opt; + item->setIconSize(qApp->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, 0)); + } + } else { + item->setIcon(QIcon()); + } + item->setVisible(action->isVisible()); +#if QT_CONFIG(shortcut) + item->setShortcut(action->shortcut()); +#endif + item->setCheckable(action->isCheckable()); + item->setChecked(action->isChecked()); + item->setHasExclusiveGroup(action->actionGroup() && action->actionGroup()->isExclusive()); + item->setFont(action->font()); + item->setRole((QPlatformMenuItem::MenuRole) action->menuRole()); + item->setEnabled(action->isEnabled()); + + if (action->menu()) { + if (!action->menu()->platformMenu()) + action->menu()->setPlatformMenu(platformMenu->createSubMenu()); + item->setMenu(action->menu()->platformMenu()); + } else { + item->setMenu(0); + } +} + +QPlatformMenuItem * QMenuPrivate::insertActionInPlatformMenu(const QAction *action, QPlatformMenuItem *beforeItem) +{ + QPlatformMenuItem *menuItem = platformMenu->createMenuItem(); + Q_ASSERT(menuItem); + + menuItem->setTag(reinterpret_cast<quintptr>(action)); + QObject::connect(menuItem, &QPlatformMenuItem::activated, action, &QAction::trigger, Qt::QueuedConnection); + QObject::connect(menuItem, &QPlatformMenuItem::hovered, action, &QAction::hovered, Qt::QueuedConnection); + copyActionToPlatformItem(action, menuItem); + platformMenu->insertMenuItem(menuItem, beforeItem); + + return menuItem; +} + int QMenuPrivate::scrollerHeight() const { Q_Q(const QMenu); return qMax(QApplication::globalStrut().height(), q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q)); } -//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't +//Windows and KDE allow menus to cover the taskbar, while GNOME and Mac don't QRect QMenuPrivate::popupGeometry() const { Q_Q(const QMenu); if (!tornoff && // Torn-off menus are different QGuiApplicationPrivate::platformTheme() && QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool()) { - return QApplication::desktop()->screenGeometry(q); + return QDesktopWidgetPrivate::screenGeometry(q); } else { - return QApplication::desktop()->availableGeometry(q); + return QDesktopWidgetPrivate::availableGeometry(q); } } -//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't +//Windows and KDE allow menus to cover the taskbar, while GNOME and Mac don't QRect QMenuPrivate::popupGeometry(int screen) const { if (!tornoff && // Torn-off menus are different QGuiApplicationPrivate::platformTheme() && QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool()) { - return QApplication::desktop()->screenGeometry(screen); + return QDesktopWidgetPrivate::screenGeometry(screen); } else { - return QApplication::desktop()->availableGeometry(screen); + return QDesktopWidgetPrivate::availableGeometry(screen); } } @@ -304,6 +347,11 @@ QVector<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const return ret; } +bool QMenuPrivate::isContextMenu() const +{ + return qobject_cast<const QMenuBar *>(topCausedWidget()) == nullptr; +} + void QMenuPrivate::updateActionRects() const { updateActionRects(popupGeometry()); @@ -358,6 +406,7 @@ void QMenuPrivate::updateActionRects(const QRect &screen) const //calculate size QFontMetrics qfm = q->fontMetrics(); bool previousWasSeparator = true; // this is true to allow removing the leading separators + const bool contextMenu = isContextMenu(); for(int i = 0; i <= lastVisibleAction; i++) { QAction *action = actions.at(i); const bool isSection = action->isSeparator() && (!action->text().isEmpty() || !action->icon().isNull()); @@ -389,7 +438,7 @@ void QMenuPrivate::updateActionRects(const QRect &screen) const tabWidth = qMax(int(tabWidth), qfm.width(s.mid(t+1))); s = s.left(t); #ifndef QT_NO_SHORTCUT - } else { + } else if (action->isShortcutVisibleInContextMenu() || !contextMenu) { QKeySequence seq = action->shortcut(); if (!seq.isEmpty()) tabWidth = qMax(int(tabWidth), qfm.width(seq.toString(QKeySequence::NativeText))); @@ -1536,7 +1585,8 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) option->icon = action->icon(); QString textAndAccel = action->text(); #ifndef QT_NO_SHORTCUT - if (textAndAccel.indexOf(QLatin1Char('\t')) == -1) { + if ((action->isShortcutVisibleInContextMenu() || !d->isContextMenu()) + && textAndAccel.indexOf(QLatin1Char('\t')) == -1) { QKeySequence seq = action->shortcut(); if (!seq.isEmpty()) textAndAccel += QLatin1Char('\t') + seq.toString(QKeySequence::NativeText); @@ -2330,6 +2380,12 @@ void QMenu::popup(const QPoint &p, QAction *atAction) d->updateLayoutDirection(); d->adjustMenuScreen(p); + const bool contextMenu = d->isContextMenu(); + if (d->lastContextMenu != contextMenu) { + d->itemsDirty = true; + d->lastContextMenu = contextMenu; + } + #if QT_CONFIG(menubar) // if this menu is part of a chain attached to a QMenuBar, set the // _NET_WM_WINDOW_TYPE_DROPDOWN_MENU X11 window type @@ -2347,7 +2403,7 @@ void QMenu::popup(const QPoint &p, QAction *atAction) screen = d->popupGeometry(); else #endif - screen = d->popupGeometry(QApplication::desktop()->screenNumber(p)); + screen = d->popupGeometry(QDesktopWidgetPrivate::screenNumber(p)); d->updateActionRects(screen); QPoint pos; @@ -2447,8 +2503,6 @@ void QMenu::popup(const QPoint &p, QAction *atAction) pos.setY(qMin(mouse.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1)); else pos.setY(qMax(p.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1)); - } else if (pos.y() < screen.top() + desktopFrame) { - pos.setY(screen.top() + desktopFrame); } if (pos.y() < screen.top() + desktopFrame) @@ -2680,7 +2734,8 @@ void QMenu::hideEvent(QHideEvent *) if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget)) mb->d_func()->setCurrentAction(0); #endif - d->mouseDown = 0; + if (d->mouseDown == this) + d->mouseDown = 0; d->hasHadMouse = false; if (d->activeMenu) d->hideMenu(d->activeMenu); @@ -3469,43 +3524,6 @@ QMenu::timerEvent(QTimerEvent *e) } } -static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item, QPlatformMenu *itemsMenu) -{ - item->setText(action->text()); - item->setIsSeparator(action->isSeparator()); - if (action->isIconVisibleInMenu()) { - item->setIcon(action->icon()); - if (QWidget *w = action->parentWidget()) { - QStyleOption opt; - opt.init(w); - item->setIconSize(w->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, w)); - } else { - QStyleOption opt; - item->setIconSize(qApp->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, 0)); - } - } else { - item->setIcon(QIcon()); - } - item->setVisible(action->isVisible()); -#ifndef QT_NO_SHORTCUT - item->setShortcut(action->shortcut()); -#endif - item->setCheckable(action->isCheckable()); - item->setChecked(action->isChecked()); - item->setHasExclusiveGroup(action->actionGroup() && action->actionGroup()->isExclusive()); - item->setFont(action->font()); - item->setRole((QPlatformMenuItem::MenuRole) action->menuRole()); - item->setEnabled(action->isEnabled()); - - if (action->menu()) { - if (!action->menu()->platformMenu()) - action->menu()->setPlatformMenu(itemsMenu->createSubMenu()); - item->setMenu(action->menu()->platformMenu()); - } else { - item->setMenu(0); - } -} - /*! \reimp */ @@ -3559,15 +3577,10 @@ void QMenu::actionEvent(QActionEvent *e) if (!d->platformMenu.isNull()) { if (e->type() == QEvent::ActionAdded) { - QPlatformMenuItem *menuItem = d->platformMenu->createMenuItem(); - menuItem->setTag(reinterpret_cast<quintptr>(e->action())); - QObject::connect(menuItem, SIGNAL(activated()), e->action(), SLOT(trigger())); - QObject::connect(menuItem, SIGNAL(hovered()), e->action(), SIGNAL(hovered())); - copyActionToPlatformItem(e->action(), menuItem, d->platformMenu); QPlatformMenuItem *beforeItem = e->before() ? d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->before())) : nullptr; - d->platformMenu->insertMenuItem(menuItem, beforeItem); + d->insertActionInPlatformMenu(e->action(), beforeItem); } else if (e->type() == QEvent::ActionRemoved) { QPlatformMenuItem *menuItem = d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->action())); d->platformMenu->removeMenuItem(menuItem); @@ -3575,7 +3588,7 @@ void QMenu::actionEvent(QActionEvent *e) } else if (e->type() == QEvent::ActionChanged) { QPlatformMenuItem *menuItem = d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->action())); if (menuItem) { - copyActionToPlatformItem(e->action(), menuItem, d->platformMenu); + d->copyActionToPlatformItem(e->action(), menuItem); d->platformMenu->syncMenuItem(menuItem); } } @@ -3617,7 +3630,7 @@ void QMenu::internalDelayedPopup() screen = d->popupGeometry(); else #endif - screen = d->popupGeometry(QApplication::desktop()->screenNumber(pos())); + screen = d->popupGeometry(QDesktopWidgetPrivate::screenNumber(pos())); int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this); const QRect actionRect(d->actionRect(d->currentAction)); |