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.cpp203
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);