summaryrefslogtreecommitdiffstats
path: root/src/widgets/widgets/qmenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/widgets/qmenu.cpp')
-rw-r--r--src/widgets/widgets/qmenu.cpp233
1 files changed, 177 insertions, 56 deletions
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp
index eba17783ec..36a8a96b79 100644
--- a/src/widgets/widgets/qmenu.cpp
+++ b/src/widgets/widgets/qmenu.cpp
@@ -153,12 +153,19 @@ void QMenuPrivate::init()
scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
}
- setPlatformMenu(QGuiApplicationPrivate::platformTheme()->createPlatformMenu());
sloppyState.initialize(q);
delayState.initialize(q);
mousePopupDelay = q->style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, q);
}
+QPlatformMenu *QMenuPrivate::createPlatformMenu()
+{
+ Q_Q(QMenu);
+ if (platformMenu.isNull())
+ q->setPlatformMenu(QGuiApplicationPrivate::platformTheme()->createPlatformMenu());
+ return platformMenu.data();
+}
+
void QMenuPrivate::setPlatformMenu(QPlatformMenu *menu)
{
Q_Q(QMenu);
@@ -809,6 +816,93 @@ void QMenuPrivate::updateLayoutDirection()
}
}
+void QMenuPrivate::drawScroller(QPainter *painter, QMenuPrivate::ScrollerTearOffItem::Type type, const QRect &rect)
+{
+ if (!painter || rect.isEmpty())
+ return;
+
+ if (!scroll || !(scroll->scrollFlags & (QMenuPrivate::QMenuScroller::ScrollUp
+ | QMenuPrivate::QMenuScroller::ScrollDown)))
+ return;
+
+ Q_Q(QMenu);
+ QStyleOptionMenuItem menuOpt;
+ menuOpt.initFrom(q);
+ menuOpt.state = QStyle::State_None;
+ menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
+ menuOpt.maxIconWidth = 0;
+ menuOpt.tabWidth = 0;
+ menuOpt.rect = rect;
+ menuOpt.menuItemType = QStyleOptionMenuItem::Scroller;
+ menuOpt.state |= QStyle::State_Enabled;
+ if (type == QMenuPrivate::ScrollerTearOffItem::ScrollDown)
+ menuOpt.state |= QStyle::State_DownArrow;
+
+ painter->setClipRect(menuOpt.rect);
+ q->style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, painter, q);
+}
+
+void QMenuPrivate::drawTearOff(QPainter *painter, const QRect &rect)
+{
+ if (!painter || rect.isEmpty())
+ return;
+
+ if (!tearoff)
+ return;
+
+ Q_Q(QMenu);
+ QStyleOptionMenuItem menuOpt;
+ menuOpt.initFrom(q);
+ menuOpt.state = QStyle::State_None;
+ menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
+ menuOpt.maxIconWidth = 0;
+ menuOpt.tabWidth = 0;
+ menuOpt.rect = rect;
+ menuOpt.menuItemType = QStyleOptionMenuItem::TearOff;
+ if (tearoffHighlighted)
+ menuOpt.state |= QStyle::State_Selected;
+
+ painter->setClipRect(menuOpt.rect);
+ q->style()->drawControl(QStyle::CE_MenuTearoff, &menuOpt, painter, q);
+}
+
+QMenuPrivate::ScrollerTearOffItem::ScrollerTearOffItem(QMenuPrivate::ScrollerTearOffItem::Type type, QMenuPrivate *mPrivate, QWidget *parent, Qt::WindowFlags f)
+ : QWidget(parent, f), menuPrivate(mPrivate), scrollType(type)
+{
+ if (parent)
+ setMouseTracking(parent->style()->styleHint(QStyle::SH_Menu_MouseTracking, 0, parent));
+}
+
+void QMenuPrivate::ScrollerTearOffItem::paintEvent(QPaintEvent *e)
+{
+ if (!e->rect().intersects(rect()))
+ return;
+
+ QPainter p(this);
+ QWidget *parent = parentWidget();
+
+ //paint scroll up / down arrows
+ menuPrivate->drawScroller(&p, scrollType, QRect(0, 0, width(), menuPrivate->scrollerHeight()));
+ //paint the tear off
+ if (scrollType == QMenuPrivate::ScrollerTearOffItem::ScrollUp) {
+ QRect rect(0, 0, width(), parent->style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, parent));
+ if (menuPrivate->scroll && menuPrivate->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
+ rect.translate(0, menuPrivate->scrollerHeight());
+ menuPrivate->drawTearOff(&p, rect);
+ }
+}
+
+void QMenuPrivate::ScrollerTearOffItem::updateScrollerRects(const QRect &rect)
+{
+ if (rect.isEmpty())
+ setVisible(false);
+ else {
+ setGeometry(rect);
+ raise();
+ setVisible(true);
+ }
+}
+
/*!
Returns the action associated with this menu.
@@ -1479,10 +1573,9 @@ QMenu::QMenu(QWidget *parent)
\sa title
*/
QMenu::QMenu(const QString &title, QWidget *parent)
- : QWidget(*new QMenuPrivate, parent, Qt::Popup)
+ : QMenu(parent)
{
Q_D(QMenu);
- d->init();
d->menuAction->setText(title);
}
@@ -2533,58 +2626,78 @@ void QMenu::paintEvent(QPaintEvent *e)
menuOpt.tabWidth = 0;
style()->drawPrimitive(QStyle::PE_PanelMenu, &menuOpt, &p, this);
+ //calculate the scroll up / down rect
+ const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this);
+ QRect scrollUpRect, scrollDownRect;
+ if (d->scroll) {
+ if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
+ scrollUpRect.setRect(fw, fw, width() - (fw * 2), d->scrollerHeight());
+
+ if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
+ scrollDownRect.setRect(fw, height() - d->scrollerHeight() - fw, width() - (fw * 2),
+ d->scrollerHeight());
+ }
+
+ //calculate the tear off rect
+ QRect tearOffRect;
+ if (d->tearoff) {
+ tearOffRect.setRect(fw, fw, width() - (fw * 2),
+ style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this));
+ if (d->scroll && d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
+ tearOffRect.translate(0, d->scrollerHeight());
+ }
+
//draw the items that need updating..
+ QRect scrollUpTearOffRect = scrollUpRect.united(tearOffRect);
for (int i = 0; i < d->actions.count(); ++i) {
QAction *action = d->actions.at(i);
- QRect adjustedActionRect = d->actionRects.at(i);
- if (!e->rect().intersects(adjustedActionRect)
+ QRect actionRect = d->actionRects.at(i);
+ if (!e->rect().intersects(actionRect)
|| d->widgetItems.value(action))
continue;
//set the clip region to be extra safe (and adjust for the scrollers)
+ emptyArea -= QRegion(actionRect);
+
+ QRect adjustedActionRect = actionRect;
+ if (adjustedActionRect.intersects(scrollUpTearOffRect)) {
+ if (adjustedActionRect.bottom() <= scrollUpTearOffRect.bottom())
+ continue;
+ else
+ adjustedActionRect.setTop(scrollUpTearOffRect.bottom()+1);
+ }
+
+ if (adjustedActionRect.intersects(scrollDownRect)) {
+ if (adjustedActionRect.top() >= scrollDownRect.top())
+ continue;
+ else
+ adjustedActionRect.setBottom(scrollDownRect.top()-1);
+ }
+
QRegion adjustedActionReg(adjustedActionRect);
- emptyArea -= adjustedActionReg;
p.setClipRegion(adjustedActionReg);
QStyleOptionMenuItem opt;
initStyleOption(&opt, action);
- opt.rect = adjustedActionRect;
+ opt.rect = actionRect;
style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this);
}
- const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this);
- //draw the scroller regions..
- if (d->scroll) {
- menuOpt.menuItemType = QStyleOptionMenuItem::Scroller;
- menuOpt.state |= QStyle::State_Enabled;
- if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) {
- menuOpt.rect.setRect(fw, fw, width() - (fw * 2), d->scrollerHeight());
- emptyArea -= QRegion(menuOpt.rect);
- p.setClipRect(menuOpt.rect);
- style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this);
- }
- if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown) {
- menuOpt.rect.setRect(fw, height() - d->scrollerHeight() - fw, width() - (fw * 2),
- d->scrollerHeight());
- emptyArea -= QRegion(menuOpt.rect);
- menuOpt.state |= QStyle::State_DownArrow;
- p.setClipRect(menuOpt.rect);
- style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this);
- }
- }
- //paint the tear off..
- if (d->tearoff) {
- menuOpt.menuItemType = QStyleOptionMenuItem::TearOff;
- menuOpt.rect.setRect(fw, fw, width() - (fw * 2),
- style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this));
- if (d->scroll && d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
- menuOpt.rect.translate(0, d->scrollerHeight());
- emptyArea -= QRegion(menuOpt.rect);
- p.setClipRect(menuOpt.rect);
- menuOpt.state = QStyle::State_None;
- if (d->tearoffHighlighted)
- menuOpt.state |= QStyle::State_Selected;
- style()->drawControl(QStyle::CE_MenuTearoff, &menuOpt, &p, this);
+ emptyArea -= QRegion(scrollUpTearOffRect);
+ emptyArea -= QRegion(scrollDownRect);
+
+ if (d->scrollUpTearOffItem || d->scrollDownItem) {
+ if (d->scrollUpTearOffItem)
+ d->scrollUpTearOffItem->updateScrollerRects(scrollUpTearOffRect);
+ if (d->scrollDownItem)
+ d->scrollDownItem->updateScrollerRects(scrollDownRect);
+ } else {
+ //paint scroll up /down
+ d->drawScroller(&p, QMenuPrivate::ScrollerTearOffItem::ScrollUp, scrollUpRect);
+ d->drawScroller(&p, QMenuPrivate::ScrollerTearOffItem::ScrollDown, scrollDownRect);
+ //paint the tear off..
+ d->drawTearOff(&p, tearOffRect);
}
+
//draw border
if (fw) {
QRegion borderReg;
@@ -2603,7 +2716,7 @@ void QMenu::paintEvent(QPaintEvent *e)
style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, &p, this);
}
- //finally the rest of the space
+ //finally the rest of the spaces
p.setClipRegion(emptyArea);
menuOpt.state = QStyle::State_None;
menuOpt.menuItemType = QStyleOptionMenuItem::EmptyArea;
@@ -2730,7 +2843,10 @@ QMenu::event(QEvent *e)
if (kev->key() == Qt::Key_Up || kev->key() == Qt::Key_Down
|| kev->key() == Qt::Key_Left || kev->key() == Qt::Key_Right
|| kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return
- || kev->matches(QKeySequence::Cancel)) {
+#ifndef QT_NO_SHORTCUT
+ || kev->matches(QKeySequence::Cancel)
+#endif
+ ) {
e->accept();
return true;
}
@@ -2978,7 +3094,7 @@ void QMenu::keyPressEvent(QKeyEvent *e)
key_consumed = true;
break;
}
- //FALL THROUGH
+ Q_FALLTHROUGH();
case Qt::Key_Left: {
if (d->currentAction && !d->scroll) {
QAction *nextAction = 0;
@@ -3025,6 +3141,7 @@ void QMenu::keyPressEvent(QKeyEvent *e)
if (!style()->styleHint(QStyle::SH_Menu_SpaceActivatesItem, 0, this))
break;
// for motif, fall through
+ Q_FALLTHROUGH();
#ifdef QT_KEYPAD_NAVIGATION
case Qt::Key_Select:
#endif
@@ -3057,7 +3174,11 @@ void QMenu::keyPressEvent(QKeyEvent *e)
key_consumed = false;
}
- if (!key_consumed && (e->matches(QKeySequence::Cancel)
+ if (!key_consumed && (
+ false
+#ifndef QT_NO_SHORTCUT
+ || e->matches(QKeySequence::Cancel)
+#endif
#ifdef QT_KEYPAD_NAVIGATION
|| e->key() == Qt::Key_Back
#endif
@@ -3271,7 +3392,9 @@ static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *i
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());
@@ -3305,8 +3428,17 @@ void QMenu::actionEvent(QActionEvent *e)
}
if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
QWidget *widget = wa->requestWidget(this);
- if (widget)
+ if (widget) {
d->widgetItems.insert(wa, widget);
+ if (d->scroll) {
+ if (!d->scrollUpTearOffItem)
+ d->scrollUpTearOffItem =
+ new QMenuPrivate::ScrollerTearOffItem(QMenuPrivate::ScrollerTearOffItem::ScrollUp, d, this);
+ if (!d->scrollDownItem)
+ d->scrollDownItem =
+ new QMenuPrivate::ScrollerTearOffItem(QMenuPrivate::ScrollerTearOffItem::ScrollDown, d, this);
+ }
+ }
}
} else if (e->type() == QEvent::ActionRemoved) {
e->action()->disconnect(this);
@@ -3354,17 +3486,6 @@ void QMenu::actionEvent(QActionEvent *e)
d->platformMenu->syncSeparatorsCollapsible(d->collapsibleSeparators);
}
-#if defined(Q_OS_WINCE) && !defined(QT_NO_MENUBAR)
- if (!d->wce_menu)
- d->wce_menu = new QMenuPrivate::QWceMenuPrivate;
- if (e->type() == QEvent::ActionAdded)
- d->wce_menu->addAction(e->action(), d->wce_menu->findAction(e->before()));
- else if (e->type() == QEvent::ActionRemoved)
- d->wce_menu->removeAction(e->action());
- else if (e->type() == QEvent::ActionChanged)
- d->wce_menu->syncAction(e->action());
-#endif
-
if (isVisible()) {
d->updateActionRects();
resize(sizeHint());