diff options
Diffstat (limited to 'src/widgets/widgets/qmenu.cpp')
-rw-r--r-- | src/widgets/widgets/qmenu.cpp | 203 |
1 files changed, 163 insertions, 40 deletions
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index d957dda162..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. @@ -2532,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; @@ -2602,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; @@ -3314,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); |