summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/widgets/widgets/qmenu.cpp139
-rw-r--r--src/widgets/widgets/qmenu_p.h21
2 files changed, 130 insertions, 30 deletions
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp
index b0c9512344..36a8a96b79 100644
--- a/src/widgets/widgets/qmenu.cpp
+++ b/src/widgets/widgets/qmenu.cpp
@@ -816,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.
@@ -2595,35 +2682,20 @@ void QMenu::paintEvent(QPaintEvent *e)
style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this);
}
- if (!scrollUpRect.isEmpty()) {
- menuOpt.menuItemType = QStyleOptionMenuItem::Scroller;
- menuOpt.state |= QStyle::State_Enabled;
- 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);
- }
+ emptyArea -= QRegion(scrollUpTearOffRect);
+ emptyArea -= QRegion(scrollDownRect);
- //paint the tear off..
- if (!tearOffRect.isEmpty()) {
- menuOpt.menuItemType = QStyleOptionMenuItem::TearOff;
- menuOpt.rect = tearOffRect;
- 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);
+ 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
@@ -3356,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);
diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h
index 3166e6f6cd..64291e842f 100644
--- a/src/widgets/widgets/qmenu_p.h
+++ b/src/widgets/widgets/qmenu_p.h
@@ -276,7 +276,8 @@ public:
cancelAction(0),
#endif
scroll(0), eventLoop(0), tearoff(0), tornoff(0), tearoffHighlighted(0),
- hasCheckableItems(0), doChildEffects(false), platformMenu(0)
+ hasCheckableItems(0), doChildEffects(false), platformMenu(0),
+ scrollUpTearOffItem(nullptr), scrollDownItem(nullptr)
{ }
~QMenuPrivate()
@@ -445,6 +446,24 @@ public:
QPointer<QAction> actionAboutToTrigger;
QPointer<QWidget> noReplayFor;
+
+ class ScrollerTearOffItem : public QWidget {
+ public:
+ enum Type { ScrollUp, ScrollDown };
+ ScrollerTearOffItem(Type type, QMenuPrivate *mPrivate,
+ QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
+ void paintEvent(QPaintEvent *e) Q_DECL_OVERRIDE;
+ void updateScrollerRects(const QRect &rect);
+
+ private:
+ QMenuPrivate *menuPrivate;
+ Type scrollType;
+ };
+ ScrollerTearOffItem *scrollUpTearOffItem;
+ ScrollerTearOffItem *scrollDownItem;
+
+ void drawScroller(QPainter *painter, ScrollerTearOffItem::Type type, const QRect &rect);
+ void drawTearOff(QPainter *painter, const QRect &rect);
};
#endif // QT_NO_MENU