From 7f0d43fd332519e2689ffbff8198590d768864bc Mon Sep 17 00:00:00 2001 From: Dongmei Wang Date: Fri, 30 Sep 2016 12:01:02 -0700 Subject: Don't overlap the menu scrollers with QAction items The QAction items overlap with the menu scrollers. The patch is to set correct clip regions for QAction items in order not to overlap with the scroll arrows. Change-Id: Ie724bd2be522daf5935fb489523b5d5f32bb7f71 Reviewed-by: Gabriel de Dietrich --- src/widgets/widgets/qmenu.cpp | 89 ++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 27 deletions(-) diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index a983dc6fde..b0c9512344 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -2539,51 +2539,85 @@ 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) { + if (!scrollUpRect.isEmpty()) { 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); - } + menuOpt.rect = scrollUpRect; + emptyArea -= QRegion(menuOpt.rect); + p.setClipRect(menuOpt.rect); + style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this); + } + + if (!scrollDownRect.isEmpty()) { + menuOpt.menuItemType = QStyleOptionMenuItem::Scroller; + menuOpt.state |= QStyle::State_Enabled; + menuOpt.state |= QStyle::State_DownArrow; + menuOpt.rect = scrollDownRect; + emptyArea -= QRegion(menuOpt.rect); + p.setClipRect(menuOpt.rect); + style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this); } + //paint the tear off.. - if (d->tearoff) { + if (!tearOffRect.isEmpty()) { 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()); + menuOpt.rect = tearOffRect; emptyArea -= QRegion(menuOpt.rect); p.setClipRect(menuOpt.rect); menuOpt.state = QStyle::State_None; @@ -2591,6 +2625,7 @@ void QMenu::paintEvent(QPaintEvent *e) menuOpt.state |= QStyle::State_Selected; style()->drawControl(QStyle::CE_MenuTearoff, &menuOpt, &p, this); } + //draw border if (fw) { QRegion borderReg; @@ -2609,7 +2644,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; -- cgit v1.2.3