summaryrefslogtreecommitdiffstats
path: root/src/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets')
-rw-r--r--src/widgets/effects/qpixmapfilter.cpp7
-rw-r--r--src/widgets/graphicsview/qgraphicslayout_p.h2
-rw-r--r--src/widgets/graphicsview/qgraphicsscene.cpp2
-rw-r--r--src/widgets/itemviews/qabstractitemview.cpp1
-rw-r--r--src/widgets/itemviews/qabstractitemview.h4
-rw-r--r--src/widgets/itemviews/qtreeview.cpp4
-rw-r--r--src/widgets/itemviews/qtreeview_p.h2
-rw-r--r--src/widgets/kernel/qapplication.cpp8
-rw-r--r--src/widgets/kernel/qdesktopwidget_p.h4
-rw-r--r--src/widgets/kernel/qgesture.cpp77
-rw-r--r--src/widgets/kernel/qgesture.h5
-rw-r--r--src/widgets/kernel/qwidget.cpp8
-rw-r--r--src/widgets/kernel/qwidget_p.h4
-rw-r--r--src/widgets/kernel/qwidgetbackingstore.cpp18
-rw-r--r--src/widgets/styles/qcommonstyle.cpp19
-rw-r--r--src/widgets/styles/qfusionstyle.cpp5
-rw-r--r--src/widgets/styles/qmacstyle_mac.mm33
-rw-r--r--src/widgets/styles/qstyle.cpp26
-rw-r--r--src/widgets/styles/qstyle.h6
-rw-r--r--src/widgets/styles/qstyleoption.cpp3
-rw-r--r--src/widgets/styles/qstyleoption.h2
-rw-r--r--src/widgets/styles/qwindowsstyle.cpp11
-rw-r--r--src/widgets/widgets/qlineedit.cpp2
-rw-r--r--src/widgets/widgets/qmenu.cpp298
-rw-r--r--src/widgets/widgets/qmenu.h1
-rw-r--r--src/widgets/widgets/qmenu_p.h251
-rw-r--r--src/widgets/widgets/qprogressbar.cpp2
27 files changed, 657 insertions, 148 deletions
diff --git a/src/widgets/effects/qpixmapfilter.cpp b/src/widgets/effects/qpixmapfilter.cpp
index 6f618b8914..e4e409a542 100644
--- a/src/widgets/effects/qpixmapfilter.cpp
+++ b/src/widgets/effects/qpixmapfilter.cpp
@@ -705,7 +705,8 @@ void expblur(QImage &img, qreal radius, bool improvedQuality = false, int transp
Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied
|| img.format() == QImage::Format_RGB32
- || img.format() == QImage::Format_Indexed8);
+ || img.format() == QImage::Format_Indexed8
+ || img.format() == QImage::Format_Grayscale8);
// choose the alpha such that pixels at radius distance from a fully
// saturated pixel will have an alpha component of no greater than
@@ -780,7 +781,7 @@ Q_WIDGETS_EXPORT QImage qt_halfScaled(const QImage &source)
QImage srcImage = source;
- if (source.format() == QImage::Format_Indexed8) {
+ if (source.format() == QImage::Format_Indexed8 || source.format() == QImage::Format_Grayscale8) {
// assumes grayscale
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
@@ -890,7 +891,7 @@ Q_WIDGETS_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius,
Q_WIDGETS_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0)
{
- if (blurImage.format() == QImage::Format_Indexed8)
+ if (blurImage.format() == QImage::Format_Indexed8 || blurImage.format() == QImage::Format_Grayscale8)
expblur<12, 10, true>(blurImage, radius, quality, transposed);
else
expblur<12, 10, false>(blurImage, radius, quality, transposed);
diff --git a/src/widgets/graphicsview/qgraphicslayout_p.h b/src/widgets/graphicsview/qgraphicslayout_p.h
index a45cb31b28..698118eb75 100644
--- a/src/widgets/graphicsview/qgraphicslayout_p.h
+++ b/src/widgets/graphicsview/qgraphicslayout_p.h
@@ -65,7 +65,7 @@ inline bool qt_graphicsLayoutDebug()
{
static int checked_env = -1;
if(checked_env == -1)
- checked_env = !!qgetenv("QT_GRAPHICSLAYOUT_DEBUG").toInt();
+ checked_env = !!qEnvironmentVariableIntValue("QT_GRAPHICSLAYOUT_DEBUG");
return checked_env;
}
#endif
diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp
index 988152da9d..8765b8114d 100644
--- a/src/widgets/graphicsview/qgraphicsscene.cpp
+++ b/src/widgets/graphicsview/qgraphicsscene.cpp
@@ -4910,7 +4910,7 @@ void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const Q
if (painterStateProtection || restorePainterClip)
painter->restore();
- static int drawRect = qgetenv("QT_DRAW_SCENE_ITEM_RECTS").toInt();
+ static int drawRect = qEnvironmentVariableIntValue("QT_DRAW_SCENE_ITEM_RECTS");
if (drawRect) {
QPen oldPen = painter->pen();
QBrush oldBrush = painter->brush();
diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp
index 1d8be6398c..a6361bd750 100644
--- a/src/widgets/itemviews/qabstractitemview.cpp
+++ b/src/widgets/itemviews/qabstractitemview.cpp
@@ -1531,6 +1531,7 @@ void QAbstractItemView::setIconSize(const QSize &size)
return;
d->iconSize = size;
d->doDelayedItemsLayout();
+ emit iconSizeChanged(size);
}
QSize QAbstractItemView::iconSize() const
diff --git a/src/widgets/itemviews/qabstractitemview.h b/src/widgets/itemviews/qabstractitemview.h
index f7cdcc8451..4162479194 100644
--- a/src/widgets/itemviews/qabstractitemview.h
+++ b/src/widgets/itemviews/qabstractitemview.h
@@ -68,7 +68,7 @@ class Q_WIDGETS_EXPORT QAbstractItemView : public QAbstractScrollArea
Q_PROPERTY(bool alternatingRowColors READ alternatingRowColors WRITE setAlternatingRowColors)
Q_PROPERTY(SelectionMode selectionMode READ selectionMode WRITE setSelectionMode)
Q_PROPERTY(SelectionBehavior selectionBehavior READ selectionBehavior WRITE setSelectionBehavior)
- Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize)
+ Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize NOTIFY iconSizeChanged)
Q_PROPERTY(Qt::TextElideMode textElideMode READ textElideMode WRITE setTextElideMode)
Q_PROPERTY(ScrollMode verticalScrollMode READ verticalScrollMode WRITE setVerticalScrollMode)
Q_PROPERTY(ScrollMode horizontalScrollMode READ horizontalScrollMode WRITE setHorizontalScrollMode)
@@ -255,6 +255,8 @@ Q_SIGNALS:
void entered(const QModelIndex &index);
void viewportEntered();
+ void iconSizeChanged(const QSize &size);
+
protected:
QAbstractItemView(QAbstractItemViewPrivate &, QWidget *parent = 0);
diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp
index 2c5f4b7c72..71bf92f321 100644
--- a/src/widgets/itemviews/qtreeview.cpp
+++ b/src/widgets/itemviews/qtreeview.cpp
@@ -3094,8 +3094,6 @@ void QTreeViewPrivate::expand(int item, bool emitSignal)
void QTreeViewPrivate::insertViewItems(int pos, int count, const QTreeViewItem &viewItem)
{
- Q_Q(QTreeView);
- Q_UNUSED(q)
viewItems.insert(pos, count, viewItem);
QTreeViewItem *items = viewItems.data();
for (int i = pos + count; i < viewItems.count(); i++)
@@ -3105,8 +3103,6 @@ void QTreeViewPrivate::insertViewItems(int pos, int count, const QTreeViewItem &
void QTreeViewPrivate::removeViewItems(int pos, int count)
{
- Q_Q(QTreeView);
- Q_UNUSED(q)
viewItems.remove(pos, count);
QTreeViewItem *items = viewItems.data();
for (int i = pos; i < viewItems.count(); i++)
diff --git a/src/widgets/itemviews/qtreeview_p.h b/src/widgets/itemviews/qtreeview_p.h
index bc444eb37f..72cb897353 100644
--- a/src/widgets/itemviews/qtreeview_p.h
+++ b/src/widgets/itemviews/qtreeview_p.h
@@ -210,6 +210,8 @@ public:
QSet<QPersistentModelIndex> hiddenIndexes;
inline bool isRowHidden(const QModelIndex &idx) const {
+ if (hiddenIndexes.isEmpty())
+ return false;
//We first check if the idx is a QPersistentModelIndex, because creating QPersistentModelIndex is slow
return isPersistent(idx) && hiddenIndexes.contains(idx);
}
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index 8f6c5d748c..c913d83213 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -636,7 +636,7 @@ void QApplicationPrivate::initialize()
qRegisterGuiStateMachine();
#endif
- if (qgetenv("QT_USE_NATIVE_WINDOWS").toInt() > 0)
+ if (qEnvironmentVariableIntValue("QT_USE_NATIVE_WINDOWS") > 0)
QCoreApplication::setAttribute(Qt::AA_NativeWindows);
#ifdef Q_OS_WINCE
@@ -658,8 +658,12 @@ void QApplicationPrivate::initialize()
initializeMultitouch();
if (QApplication::desktopSettingsAware())
- if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
QApplicationPrivate::enabledAnimations = theme->themeHint(QPlatformTheme::UiEffects).toInt();
+#ifndef QT_NO_WHEELEVENT
+ QApplicationPrivate::wheel_scroll_lines = theme->themeHint(QPlatformTheme::WheelScrollLines).toInt();
+#endif
+ }
is_app_running = true; // no longer starting up
}
diff --git a/src/widgets/kernel/qdesktopwidget_p.h b/src/widgets/kernel/qdesktopwidget_p.h
index 62f4d8ed6f..0f3083cbb5 100644
--- a/src/widgets/kernel/qdesktopwidget_p.h
+++ b/src/widgets/kernel/qdesktopwidget_p.h
@@ -48,6 +48,8 @@
#include "QDesktopWidget"
#include "private/qwidget_p.h"
+#include <QtCore/qalgorithms.h>
+
QT_BEGIN_NAMESPACE
class QDesktopScreenWidget : public QWidget {
@@ -65,7 +67,7 @@ class QDesktopWidgetPrivate : public QWidgetPrivate {
Q_DECLARE_PUBLIC(QDesktopWidget)
public:
- ~QDesktopWidgetPrivate() {foreach(QDesktopScreenWidget *s, screens) delete s; }
+ ~QDesktopWidgetPrivate() { qDeleteAll(screens); }
void _q_updateScreens();
void _q_availableGeometryChanged();
diff --git a/src/widgets/kernel/qgesture.cpp b/src/widgets/kernel/qgesture.cpp
index 2b8f04ccdf..72faedf24e 100644
--- a/src/widgets/kernel/qgesture.cpp
+++ b/src/widgets/kernel/qgesture.cpp
@@ -36,6 +36,7 @@
#include "private/qstandardgestures_p.h"
#include "qgraphicsview.h"
+#include <QtCore/QDebug>
#ifndef QT_NO_GESTURES
QT_BEGIN_NAMESPACE
@@ -1124,7 +1125,81 @@ QPointF QGestureEvent::mapToGraphicsScene(const QPointF &gesturePoint) const
\sa QEvent::ignore()
*/
-#endif
+#endif // Q_NO_USING_KEYWORD
+
+#ifndef QT_NO_DEBUG_STREAM
+
+static void formatGestureHeader(QDebug d, const char *className, const QGesture *gesture)
+{
+ d << className << "(state=" << gesture->state();
+ if (gesture->hasHotSpot())
+ d << ",hotSpot=" << gesture->hotSpot();
+}
+
+Q_WIDGETS_EXPORT QDebug operator<<(QDebug d, const QGesture *gesture)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ switch (gesture->gestureType()) {
+ case Qt::TapGesture:
+ formatGestureHeader(d, "QTapGesture", gesture);
+ d << ",position=" << static_cast<const QTapGesture*>(gesture)->position() << ')';
+ break;
+ case Qt::TapAndHoldGesture: {
+ const QTapAndHoldGesture *tap = static_cast<const QTapAndHoldGesture*>(gesture);
+ formatGestureHeader(d, "QTapAndHoldGesture", tap);
+ d << ",position=" << tap->position() << ",timeout=" << tap->timeout() << ')';
+ }
+ break;
+ case Qt::PanGesture: {
+ const QPanGesture *pan = static_cast<const QPanGesture*>(gesture);
+ formatGestureHeader(d, "QPanGesture", pan);
+ d << ",lastOffset=" << pan->lastOffset() << ",offset=" << pan->offset()
+ << ",acceleration=" << pan->acceleration()
+ << ",delta=" << pan->delta() << ')';
+ }
+ break;
+ case Qt::PinchGesture: {
+ const QPinchGesture *pinch = static_cast<const QPinchGesture*>(gesture);
+ formatGestureHeader(d, "QPinchGesture", pinch);
+ d << ",totalChangeFlags=" << pinch->totalChangeFlags()
+ << ",changeFlags=" << pinch->changeFlags()
+ << ",startCenterPoint=" << pinch->startCenterPoint()
+ << ",lastCenterPoint=" << pinch->lastCenterPoint()
+ << ",centerPoint=" << pinch->centerPoint()
+ << ",totalScaleFactor=" << pinch->totalScaleFactor()
+ << ",lastScaleFactor=" << pinch->lastScaleFactor()
+ << ",scaleFactor=" << pinch->scaleFactor()
+ << ",totalRotationAngle=" << pinch->totalRotationAngle()
+ << ",lastRotationAngle=" << pinch->lastRotationAngle()
+ << ",rotationAngle=" << pinch->rotationAngle() << ')';
+ }
+ break;
+ case Qt::SwipeGesture: {
+ const QSwipeGesture *swipe = static_cast<const QSwipeGesture*>(gesture);
+ formatGestureHeader(d, "QSwipeGesture", swipe);
+ d << ",horizontalDirection=" << swipe->horizontalDirection()
+ << ",verticalDirection=" << swipe->verticalDirection()
+ << ",swipeAngle=" << swipe->swipeAngle() << ')';
+ }
+ break;
+ default:
+ formatGestureHeader(d, "Custom gesture", gesture);
+ d << ",type=" << gesture->gestureType() << ')';
+ break;
+ }
+ return d;
+}
+
+Q_WIDGETS_EXPORT QDebug operator<<(QDebug d, const QGestureEvent *gestureEvent)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d << "QGestureEvent(" << gestureEvent->gestures() << ')';
+ return d;
+}
+
+#endif // !QT_NO_DEBUG_STREAM
QT_END_NAMESPACE
diff --git a/src/widgets/kernel/qgesture.h b/src/widgets/kernel/qgesture.h
index 9e3ee64c87..70b1faf735 100644
--- a/src/widgets/kernel/qgesture.h
+++ b/src/widgets/kernel/qgesture.h
@@ -315,6 +315,11 @@ private:
friend class QGestureManager;
};
+# ifndef QT_NO_DEBUG_STREAM
+Q_WIDGETS_EXPORT QDebug operator<<(QDebug, const QGesture *);
+Q_WIDGETS_EXPORT QDebug operator<<(QDebug, const QGestureEvent *);
+# endif
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QGesture::GestureCancelPolicy)
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 7533cacbdc..63497ce745 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -1283,10 +1283,8 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow)
}
- static int paintOnScreenEnv = -1;
- if (paintOnScreenEnv == -1)
- paintOnScreenEnv = qgetenv("QT_ONSCREEN_PAINT").toInt() > 0 ? 1 : 0;
- if (paintOnScreenEnv == 1)
+ static const bool paintOnScreenEnv = qEnvironmentVariableIntValue("QT_ONSCREEN_PAINT") > 0;
+ if (paintOnScreenEnv)
setAttribute(Qt::WA_PaintOnScreen);
if (QApplicationPrivate::testAttribute(Qt::AA_NativeWindows))
@@ -2110,7 +2108,7 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt
bool alsoNonOpaque) const
{
Q_Q(const QWidget);
- static int disableSubtractOpaqueSiblings = qgetenv("QT_NO_SUBTRACTOPAQUESIBLINGS").toInt();
+ static int disableSubtractOpaqueSiblings = qEnvironmentVariableIntValue("QT_NO_SUBTRACTOPAQUESIBLINGS");
if (disableSubtractOpaqueSiblings || q->isWindow())
return;
diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h
index bbdbabc14b..d5a91f18d6 100644
--- a/src/widgets/kernel/qwidget_p.h
+++ b/src/widgets/kernel/qwidget_p.h
@@ -612,10 +612,10 @@ public:
{ return p + data.wrect.topLeft(); }
inline QRect mapToWS(const QRect &r) const
- { QRect rr(r); rr.translate(-data.wrect.topLeft()); return rr; }
+ { return r.translated(-data.wrect.topLeft()); }
inline QRect mapFromWS(const QRect &r) const
- { QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; }
+ { return r.translated(data.wrect.topLeft()); }
QOpenGLContext *shareContext() const;
diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp
index 00052c868f..2f2db32852 100644
--- a/src/widgets/kernel/qwidgetbackingstore.cpp
+++ b/src/widgets/kernel/qwidgetbackingstore.cpp
@@ -81,14 +81,14 @@ void QWidgetBackingStore::qt_flush(QWidget *widget, const QRegion &region, QBack
Q_ASSERT(tlw);
#if !defined(QT_NO_PAINT_DEBUG)
- static int flushUpdate = qgetenv("QT_FLUSH_UPDATE").toInt();
+ static int flushUpdate = qEnvironmentVariableIntValue("QT_FLUSH_UPDATE");
if (flushUpdate > 0)
QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false);
#endif
if (tlw->testAttribute(Qt::WA_DontShowOnScreen) || widget->testAttribute(Qt::WA_DontShowOnScreen))
return;
- static bool fpsDebug = qgetenv("QT_DEBUG_FPS").toInt();
+ static bool fpsDebug = qEnvironmentVariableIntValue("QT_DEBUG_FPS");
if (fpsDebug) {
if (!widgetBackingStore->perfFrames++)
widgetBackingStore->perfTime.start();
@@ -239,12 +239,12 @@ bool QWidgetBackingStore::flushPaint(QWidget *widget, const QRegion &rgn)
int delay = 0;
if (widget->testAttribute(Qt::WA_WState_InPaintEvent)) {
- static int flushPaintEvent = qgetenv("QT_FLUSH_PAINT_EVENT").toInt();
+ static int flushPaintEvent = qEnvironmentVariableIntValue("QT_FLUSH_PAINT_EVENT");
if (!flushPaintEvent)
return false;
delay = flushPaintEvent;
} else {
- static int flushPaint = qgetenv("QT_FLUSH_PAINT").toInt();
+ static int flushPaint = qEnvironmentVariableIntValue("QT_FLUSH_PAINT");
if (!flushPaint)
return false;
delay = flushPaint;
@@ -780,10 +780,7 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
if (x->inTopLevelResize)
return;
- static int accelEnv = -1;
- if (accelEnv == -1) {
- accelEnv = qgetenv("QT_NO_FAST_MOVE").toInt() == 0;
- }
+ static const bool accelEnv = qEnvironmentVariableIntValue("QT_NO_FAST_MOVE") == 0;
QWidget *pw = q->parentWidget();
QPoint toplevelOffset = pw->mapTo(tlw, QPoint());
@@ -862,10 +859,7 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy)
if (!wbs)
return;
- static int accelEnv = -1;
- if (accelEnv == -1) {
- accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0;
- }
+ static const bool accelEnv = qEnvironmentVariableIntValue("QT_NO_FAST_SCROLL") == 0;
QRect scrollRect = rect & clipRect();
bool overlapped = false;
diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp
index 8579308820..815b10c921 100644
--- a/src/widgets/styles/qcommonstyle.cpp
+++ b/src/widgets/styles/qcommonstyle.cpp
@@ -4923,6 +4923,25 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget
ret = true;
break;
+ case SH_Menu_SubMenuUniDirection:
+ ret = false;
+ break;
+ case SH_Menu_SubMenuUniDirectionFailCount:
+ ret = 1;
+ break;
+ case SH_Menu_SubMenuSloppySelectOtherActions:
+ ret = true;
+ break;
+ case SH_Menu_SubMenuSloppyCloseTimeout:
+ ret = 1000;
+ break;
+ case SH_Menu_SubMenuResetWhenReenteringParent:
+ ret = false;
+ break;
+ case SH_Menu_SubMenuDontStartSloppyOnLeave:
+ ret = false;
+ break;
+
case SH_ProgressDialog_TextLabelAlignment:
ret = Qt::AlignCenter;
break;
diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp
index c1d6d879a8..ef3795c9a1 100644
--- a/src/widgets/styles/qfusionstyle.cpp
+++ b/src/widgets/styles/qfusionstyle.cpp
@@ -1537,7 +1537,8 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
bool ignoreCheckMark = false;
int checkcol = qMax(menuItem->maxIconWidth, 20);
- if (qobject_cast<const QComboBox*>(widget))
+ if (qobject_cast<const QComboBox*>(widget) ||
+ (option->styleObject && option->styleObject->property("_q_isComboBoxPopupItem").toBool()))
ignoreCheckMark = true; //ignore the checkmarks provided by the QComboMenuDelegate
if (!ignoreCheckMark) {
@@ -1606,7 +1607,7 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
QRect pmr(0, 0, pixw, pixh);
pmr.moveCenter(vCheckRect.center());
painter->setPen(menuItem->palette.text().color());
- if (checkable && checked) {
+ if (!ignoreCheckMark && checkable && checked) {
QStyleOption opt = *option;
if (act) {
QColor activeColor = mergedColors(option->palette.background().color(),
diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm
index d909e13f9a..fb0bafa66d 100644
--- a/src/widgets/styles/qmacstyle_mac.mm
+++ b/src/widgets/styles/qmacstyle_mac.mm
@@ -2819,6 +2819,19 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
case SH_Menu_SubMenuPopupDelay:
ret = 100;
break;
+ case SH_Menu_SubMenuUniDirection:
+ ret = true;
+ break;
+ case SH_Menu_SubMenuSloppySelectOtherActions:
+ ret = false;
+ break;
+ case SH_Menu_SubMenuResetWhenReenteringParent:
+ ret = true;
+ break;
+ case SH_Menu_SubMenuDontStartSloppyOnLeave:
+ ret = true;
+ break;
+
case SH_ScrollBar_LeftClickAbsolutePosition: {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
bool result = [defaults boolForKey:@"AppleScrollerPagingBehavior"];
@@ -3065,8 +3078,11 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
break;
case SH_ScrollBar_Transient:
if ((qobject_cast<const QScrollBar *>(w) && w->parent() &&
- qobject_cast<QAbstractScrollArea*>(w->parent()->parent())) ||
- (opt && QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ScrollBar))) {
+ qobject_cast<QAbstractScrollArea*>(w->parent()->parent()))
+#ifndef QT_NO_ACCESSIBILITY
+ || (opt && QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ScrollBar))
+#endif
+ ) {
ret = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if (ret)
@@ -3712,6 +3728,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
QStyleOptionToolButton myTb = *tb;
myTb.state &= ~State_AutoRaise;
+#ifndef QT_NO_ACCESSIBILITY
if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
QRect cr = tb->rect;
int shiftX = 0;
@@ -3808,6 +3825,9 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
} else {
QCommonStyle::drawControl(ce, &myTb, p, w);
}
+#else
+ Q_UNUSED(tb)
+#endif
}
break;
case CE_ToolBoxTabShape:
@@ -5970,7 +5990,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
case CC_ToolButton:
if (const QStyleOptionToolButton *tb
= qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
-
+#ifndef QT_NO_ACCESSIBILITY
if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
if (tb->subControls & SC_ToolButtonMenu) {
QStyleOption arrowOpt(0);
@@ -6107,6 +6127,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget);
}
+#endif
}
break;
case CC_Dial:
@@ -6586,7 +6607,11 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
break;
case CC_ToolButton:
ret = QCommonStyle::subControlRect(cc, opt, sc, widget);
- if (sc == SC_ToolButtonMenu && !QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
+ if (sc == SC_ToolButtonMenu
+#ifndef QT_NO_ACCESSIBILITY
+ && !QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)
+#endif
+ ) {
ret.adjust(-1, 0, 0, 0);
}
break;
diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp
index 6cf61a691e..7c4d239894 100644
--- a/src/widgets/styles/qstyle.cpp
+++ b/src/widgets/styles/qstyle.cpp
@@ -1707,6 +1707,32 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
other items of the menu. This is supported on most modern
desktop platforms.
+ \value SH_Menu_SubMenuUniDirection Since Qt 5.5. If the cursor has
+ to move towards the submenu (like it is on OS X), or if the
+ cursor can move in any direction as long as it reaches the
+ submenu before the sloppy timeout.
+
+ \value SH_Menu_SubMenuUniDirectionFailCount Since Qt 5.5. When
+ SH_Menu_SubMenuUniDirection is defined this enum defines the
+ number of failed mouse moves before the sloppy submenu is
+ discarded. This can be used to control the "strictness" of the
+ uni direction algorithm.
+
+ \value SH_Menu_SubMenuSloppySelectOtherActions Since Qt 5.5. Should
+ other action items be selected when the mouse moves towards a
+ sloppy submenu.
+
+ \value SH_Menu_SubMenuSloppyCloseTimeout Since Qt 5.5. The timeout
+ used to close sloppy submenus.
+
+ \value SH_Menu_SubMenuResetWhenReenteringParent Since Qt 5.5. When
+ entering parent from child submenu, should the sloppy state be
+ reset, effectively closing the child and making the current
+ submenu active.
+
+ \value SH_Menu_SubMenuDontStartSloppyOnLeave Since Qt 5.5. Do not
+ start sloppy timers when the mouse leaves a sub-menu.
+
\value SH_ScrollView_FrameOnlyAroundContents Whether scrollviews
draw their frame only around contents (like Motif), or around
contents, scroll bars and corner widgets (like Windows).
diff --git a/src/widgets/styles/qstyle.h b/src/widgets/styles/qstyle.h
index 681f3e0468..12ada3f6e4 100644
--- a/src/widgets/styles/qstyle.h
+++ b/src/widgets/styles/qstyle.h
@@ -701,6 +701,12 @@ public:
SH_ComboBox_UseNativePopup,
SH_LineEdit_PasswordMaskDelay,
SH_TabBar_ChangeCurrentDelay,
+ SH_Menu_SubMenuUniDirection,
+ SH_Menu_SubMenuUniDirectionFailCount,
+ SH_Menu_SubMenuSloppySelectOtherActions,
+ SH_Menu_SubMenuSloppyCloseTimeout,
+ SH_Menu_SubMenuResetWhenReenteringParent,
+ SH_Menu_SubMenuDontStartSloppyOnLeave,
// Add new style hint values here
SH_CustomBase = 0xf0000000
diff --git a/src/widgets/styles/qstyleoption.cpp b/src/widgets/styles/qstyleoption.cpp
index 1d98a56063..027e36387a 100644
--- a/src/widgets/styles/qstyleoption.cpp
+++ b/src/widgets/styles/qstyleoption.cpp
@@ -1626,6 +1626,9 @@ QStyleOptionProgressBar::QStyleOptionProgressBar(int version)
\brief the progress bar's orientation (horizontal or vertical);
the default orentation is Qt::Horizontal
+ \deprecated
+ Use the QStyle::State_Horizontal flag instead (in the the QStyleOption::state member).
+
\sa QProgressBar::orientation
*/
diff --git a/src/widgets/styles/qstyleoption.h b/src/widgets/styles/qstyleoption.h
index a475f485df..4b55cf3faf 100644
--- a/src/widgets/styles/qstyleoption.h
+++ b/src/widgets/styles/qstyleoption.h
@@ -317,7 +317,7 @@ public:
QString text;
Qt::Alignment textAlignment;
bool textVisible;
- Qt::Orientation orientation;
+ Qt::Orientation orientation; // ### Qt 6: remove
bool invertedAppearance;
bool bottomToTop;
diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp
index 708014a6df..3619c3ff29 100644
--- a/src/widgets/styles/qwindowsstyle.cpp
+++ b/src/widgets/styles/qwindowsstyle.cpp
@@ -586,6 +586,17 @@ int QWindowsStyle::styleHint(StyleHint hint, const QStyleOption *opt, const QWid
break;
}
#endif // Q_OS_WIN && !Q_OS_WINRT
+ case SH_Menu_SubMenuSloppyCloseTimeout:
+ case SH_Menu_SubMenuPopupDelay: {
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+ DWORD delay;
+ if (SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &delay, 0))
+ ret = delay;
+ else
+#endif // Q_OS_WIN && !Q_OS_WINCE && !Q_OS_WINRT
+ ret = 400;
+ break;
+ }
#ifndef QT_NO_RUBBERBAND
case SH_RubberBand_Mask:
if (const QStyleOptionRubberBand *rbOpt = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp
index dfc9a8fe92..815afe85f2 100644
--- a/src/widgets/widgets/qlineedit.cpp
+++ b/src/widgets/widgets/qlineedit.cpp
@@ -1402,7 +1402,7 @@ bool QLineEdit::event(QEvent * e)
{
Q_D(QLineEdit);
if (e->type() == QEvent::Timer) {
- // should be timerEvent, is here for binary compatibility
+ // ### Qt6: move to timerEvent, is here for binary compatibility
int timerId = ((QTimerEvent*)e)->timerId();
if (false) {
#ifndef QT_NO_DRAGANDDROP
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp
index 0fd645a4d3..a4c22de15b 100644
--- a/src/widgets/widgets/qmenu.cpp
+++ b/src/widgets/widgets/qmenu.cpp
@@ -70,6 +70,22 @@
QT_BEGIN_NAMESPACE
QMenu *QMenuPrivate::mouseDown = 0;
+QPointer<QMenu> QMenuPrivate::previousMouseMenu(Q_NULLPTR);
+static void handleEnterLeaveEvents(QPointer<QMenu> *previous_ptr, QMenu *next)
+{
+ QWidget *previous = previous_ptr->data();
+ if (previous != next) {
+ if (previous) {
+ QEvent leaveEvent(QEvent::Leave);
+ QApplication::sendEvent(previous, &leaveEvent);
+ }
+ if (next) {
+ QEvent enterEvent(QEvent::Enter);
+ QApplication::sendEvent(next, &enterEvent);
+ }
+ }
+ *previous_ptr = next;
+}
/* QMenu code */
// internal class used for the torn off popup
@@ -148,6 +164,9 @@ void QMenuPrivate::init()
}
setPlatformMenu(QGuiApplicationPrivate::platformTheme()->createPlatformMenu());
+ sloppyState.initialize(q);
+ delayState.initialize(q);
+ mousePopupDelay = q->style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, q);
}
void QMenuPrivate::setPlatformMenu(QPlatformMenu *menu)
@@ -270,7 +289,6 @@ void QMenuPrivate::updateActionRects(const QRect &screen) const
maxIconWidth = 0;
hasCheckableItems = false;
ncols = 1;
- sloppyAction = 0;
for (int i = 0; i < actions.count(); ++i) {
QAction *action = actions.at(i);
@@ -482,21 +500,30 @@ void QMenuPrivate::hideMenu(QMenu *menu)
aboutToHide = false;
blocker.unblock();
#endif // QT_NO_EFFECTS
+ if (activeMenu == menu)
+ activeMenu = 0;
+ menu->d_func()->causedPopup.action = 0;
+ menu->d_func()->causedPopup.widget = 0;
menu->close();
+ if (previousMouseMenu.data() == menu)
+ handleEnterLeaveEvents(&previousMouseMenu, Q_NULLPTR);
}
void QMenuPrivate::popupAction(QAction *action, int delay, bool activateFirst)
{
Q_Q(QMenu);
- if (action && action->isEnabled()) {
- if (!delay)
- q->internalDelayedPopup();
- else if (!menuDelayTimer.isActive() && (!action->menu() || !action->menu()->isVisible()))
- menuDelayTimer.start(delay, q);
- if (activateFirst && action->menu())
- action->menu()->d_func()->setFirstActionActive();
+ if (action) {
+ if (action->isEnabled()) {
+ if (!delay)
+ q->internalDelayedPopup();
+ else if (action->menu() && !action->menu()->isVisible())
+ delayState.start(delay, action);
+ else if (!action->menu())
+ delayState.stop();
+ if (activateFirst && action->menu())
+ action->menu()->d_func()->setFirstActionActive();
+ }
} else if (QMenu *menu = activeMenu) { //hide the current item
- activeMenu = 0;
hideMenu(menu);
}
}
@@ -547,33 +574,32 @@ void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason
{
Q_Q(QMenu);
tearoffHighlighted = 0;
+
+ if (action
+ && (action->isSeparator()
+ || (!action->isEnabled() && !q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q))))
+ action = Q_NULLPTR;
+
// Reselect the currently active action in case mouse moved over other menu items when
// moving from sub menu action to sub menu (QTBUG-20094).
- if (reason != SelectedFromKeyboard && action == currentAction && !(action && action->menu() && action->menu() != activeMenu)) {
+ if (reason != SelectedFromKeyboard) {
if (QMenu *menu = qobject_cast<QMenu*>(causedPopup.widget)) {
if (causedPopup.action && menu->d_func()->activeMenu == q)
menu->d_func()->setCurrentAction(causedPopup.action, 0, reason, false);
}
- return;
}
if (currentAction)
q->update(actionRect(currentAction));
- sloppyAction = 0;
- if (!sloppyRegion.isEmpty())
- sloppyRegion = QRegion();
QMenu *hideActiveMenu = activeMenu;
-#ifndef QT_NO_STATUSTIP
QAction *previousAction = currentAction;
-#endif
currentAction = action;
if (action) {
if (!action->isSeparator()) {
activateAction(action, QAction::Hover);
if (popup != -1) {
- hideActiveMenu = 0; //will be done "later"
// if the menu is visible then activate the required action,
// otherwise we just mark the action as currentAction
// and activate it when the menu will be popuped.
@@ -596,24 +622,122 @@ void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason
}
}
}
- } else { //action is a separator
- if (popup != -1)
- hideActiveMenu = 0; //will be done "later"
}
#ifndef QT_NO_STATUSTIP
} else if (previousAction) {
previousAction->d_func()->showStatusText(topCausedWidget(), QString());
#endif
}
- if (hideActiveMenu) {
- activeMenu = 0;
+ if (hideActiveMenu && previousAction != currentAction) {
+ if (popup == -1) {
#ifndef QT_NO_EFFECTS
- // kill any running effect
- qFadeEffect(0);
- qScrollEffect(0);
+ // kill any running effect
+ qFadeEffect(0);
+ qScrollEffect(0);
#endif
- hideMenu(hideActiveMenu);
+ hideMenu(hideActiveMenu);
+ } else if (!currentAction || !currentAction->menu()) {
+ sloppyState.startTimerIfNotRunning();
+ }
+ }
+}
+
+void QMenuSloppyState::reset()
+{
+ m_enabled = false;
+ m_first_mouse = true;
+ m_init_guard = false;
+ m_uni_dir_discarded_count = 0;
+ m_time.stop();
+ m_reset_action = Q_NULLPTR;
+ m_origin_action = Q_NULLPTR;
+ m_action_rect = QRect();
+ m_previous_point = QPointF();
+ if (m_sub_menu) {
+ QMenuPrivate::get(m_sub_menu)->sloppyState.m_parent = Q_NULLPTR;
+ m_sub_menu = Q_NULLPTR;
+ }
+}
+void QMenuSloppyState::enter()
+{
+ QMenuPrivate *menuPriv = QMenuPrivate::get(m_menu);
+
+ if (m_discard_state_when_entering_parent && m_sub_menu == menuPriv->activeMenu) {
+ menuPriv->hideMenu(m_sub_menu);
+ reset();
+ }
+ if (m_parent)
+ m_parent->childEnter();
+}
+
+void QMenuSloppyState::childLeave()
+{
+ if (m_enabled && !QMenuPrivate::get(m_menu)->hasReceievedEnter) {
+ startTimer();
+ if (m_parent)
+ m_parent->childLeave();
+ }
+}
+
+void QMenuSloppyState::setSubMenuPopup(const QRect &actionRect, QAction *resetAction, QMenu *subMenu)
+{
+ m_enabled = true;
+ m_init_guard = true;
+ m_time.stop();
+ m_action_rect = actionRect;
+ m_sub_menu = subMenu;
+ QMenuPrivate::get(subMenu)->sloppyState.m_parent = this;
+ m_reset_action = resetAction;
+ m_origin_action = resetAction;
+}
+
+bool QMenuSloppyState::hasParentActiveDelayTimer() const
+{
+ return m_parent && m_parent->m_menu && QMenuPrivate::get(m_parent->m_menu)->delayState.timer.isActive();
+}
+
+class ResetOnDestroy
+{
+public:
+ ResetOnDestroy(QMenuSloppyState *sloppyState, bool *guard)
+ : toReset(sloppyState)
+ , guard(guard)
+ {
+ *guard = false;
}
+
+ ~ResetOnDestroy()
+ {
+ if (!*guard)
+ toReset->reset();
+ }
+
+ QMenuSloppyState *toReset;
+ bool *guard;
+};
+
+void QMenuSloppyState::timeout()
+{
+ QMenuPrivate *menu_priv = QMenuPrivate::get(m_menu);
+ if (menu_priv->currentAction == m_reset_action
+ && menu_priv->hasReceievedEnter
+ && (menu_priv->currentAction
+ && menu_priv->currentAction->menu() == menu_priv->activeMenu)) {
+ return;
+ }
+
+ ResetOnDestroy resetState(this, &m_init_guard);
+
+ if (hasParentActiveDelayTimer() || !m_menu || !m_menu->isVisible())
+ return;
+
+ if (m_sub_menu)
+ menu_priv->hideMenu(m_sub_menu);
+
+ if (menu_priv->hasReceievedEnter)
+ menu_priv->setCurrentAction(m_reset_action,0);
+ else
+ menu_priv->setCurrentAction(Q_NULLPTR, 0);
}
//return the top causedPopup.widget that is not a QMenu
@@ -964,8 +1088,10 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e)
tearoffHighlighted = 0;
}
- if (q->frameGeometry().contains(e->globalPos())) //otherwise if the event is in our rect we want it..
+ if (q->frameGeometry().contains(e->globalPos())) { //otherwise if the event is in our rect we want it..
+ handleEnterLeaveEvents(&previousMouseMenu, q);
return false;
+ }
for(QWidget *caused = causedPopup.widget; caused;) {
bool passOnEvent = false;
@@ -981,16 +1107,17 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e)
next_widget = m->d_func()->causedPopup.widget;
}
if (passOnEvent) {
+ handleEnterLeaveEvents(&previousMouseMenu,qobject_cast<QMenu *>(caused));
if(e->type() != QEvent::MouseButtonRelease || mouseDown == caused) {
QMouseEvent new_e(e->type(), cpos, caused->mapTo(caused->topLevelWidget(), cpos), e->screenPos(),
e->button(), e->buttons(), e->modifiers());
QApplication::sendEvent(caused, &new_e);
return true;
+ }
}
- }
- if (!next_widget)
- break;
caused = next_widget;
+ if (!caused)
+ handleEnterLeaveEvents(&previousMouseMenu, Q_NULLPTR);
}
return false;
}
@@ -2235,6 +2362,8 @@ void QMenu::hideEvent(QHideEvent *)
#endif
d->mouseDown = 0;
d->hasHadMouse = false;
+ if (d->activeMenu)
+ d->hideMenu(d->activeMenu);
d->causedPopup.widget = 0;
d->causedPopup.action = 0;
if (d->scroll)
@@ -2401,7 +2530,7 @@ void QMenu::mouseReleaseEvent(QMouseEvent *e)
#endif
d->activateAction(action, QAction::Trigger);
}
- } else if (d->hasMouseMoved(e->globalPos())) {
+ } else if ((!action || action->isEnabled()) && d->hasMouseMoved(e->globalPos())) {
d->hideUpToMenuBar();
}
}
@@ -2466,8 +2595,8 @@ QMenu::event(QEvent *e)
}
} break;
case QEvent::ContextMenu:
- if(d->menuDelayTimer.isActive()) {
- d->menuDelayTimer.stop();
+ if (d->delayState.timer.isActive()) {
+ d->delayState.stop();
internalDelayedPopup();
}
break;
@@ -2484,6 +2613,7 @@ QMenu::event(QEvent *e)
case QEvent::Show:
d->mouseDown = 0;
d->updateActionRects();
+ d->sloppyState.reset();
if (d->currentAction)
d->popupAction(d->currentAction, 0, false);
break;
@@ -2891,34 +3021,34 @@ void QMenu::mouseMoveEvent(QMouseEvent *e)
Q_D(QMenu);
if (!isVisible() || d->aboutToHide || d->mouseEventTaken(e))
return;
+
d->motions++;
- if (d->motions == 0) // ignore first mouse move event (see enterEvent())
+ if (d->motions == 0)
return;
+
d->hasHadMouse = d->hasHadMouse || rect().contains(e->pos());
QAction *action = d->actionAt(e->pos());
- if (!action || action->isSeparator()) {
+ if ((!action || action->isSeparator()) && !d->sloppyState.enabled()) {
if (d->hasHadMouse
- && d->sloppyDelayTimer == 0 // Keep things as they are while we're moving to the submenu
- && (!d->currentAction || (action && action->isSeparator())
- || !(d->currentAction->menu() && d->currentAction->menu()->isVisible())))
- d->setCurrentAction(0);
+ || (!d->currentAction || !d->currentAction->menu() || !d->currentAction->menu()->isVisible())) {
+ d->setCurrentAction(action);
+ }
return;
- } else if(e->buttons()) {
- d->mouseDown = this;
}
- if (d->sloppyRegion.contains(e->pos())) {
- // If the timer is already running then don't start a new one unless the action is the same
- if (d->sloppyAction != action && d->sloppyDelayTimer != 0) {
- killTimer(d->sloppyDelayTimer);
- d->sloppyDelayTimer = 0;
- }
- if (d->sloppyDelayTimer == 0) {
- d->sloppyAction = action;
- d->sloppyDelayTimer = startTimer(style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this) * 6);
- }
- } else if (action != d->currentAction) {
- d->setCurrentAction(action, style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this));
+
+ if (e->buttons())
+ d->mouseDown = this;
+
+ if (d->activeMenu)
+ d->activeMenu->d_func()->setCurrentAction(0);
+
+ QMenuSloppyState::MouseEventResult sloppyEventResult = d->sloppyState.processMouseEvent(e->localPos(), action, d->currentAction);
+ if (sloppyEventResult == QMenuSloppyState::EventShouldBePropogated) {
+ d->setCurrentAction(action, d->mousePopupDelay);
+ } else if (sloppyEventResult == QMenuSloppyState::EventDiscardsSloppyState) {
+ d->sloppyState.reset();
+ d->hideMenu(d->activeMenu);
}
}
@@ -2927,7 +3057,11 @@ void QMenu::mouseMoveEvent(QMouseEvent *e)
*/
void QMenu::enterEvent(QEvent *)
{
- d_func()->motions = -1; // force us to ignore the generate mouse move in mouseMoveEvent()
+ Q_D(QMenu);
+ d->hasReceievedEnter = true;
+ d->sloppyState.enter();
+ d->sloppyState.startTimer();
+ d->motions = -1; // force us to ignore the generate mouse move in mouseMoveEvent()
}
/*!
@@ -2936,9 +3070,8 @@ void QMenu::enterEvent(QEvent *)
void QMenu::leaveEvent(QEvent *)
{
Q_D(QMenu);
- d->sloppyAction = 0;
- if (!d->sloppyRegion.isEmpty())
- d->sloppyRegion = QRegion();
+ d->hasReceievedEnter = false;
+ d->sloppyState.leave();
if (!d->activeMenu && d->currentAction)
setActiveAction(0);
}
@@ -2954,13 +3087,14 @@ QMenu::timerEvent(QTimerEvent *e)
d->scrollMenu((QMenuPrivate::QMenuScroller::ScrollDirection)d->scroll->scrollDirection);
if (d->scroll->scrollFlags == QMenuPrivate::QMenuScroller::ScrollNone)
d->scroll->scrollTimer.stop();
- } else if(d->menuDelayTimer.timerId() == e->timerId()) {
- d->menuDelayTimer.stop();
+ } else if (d->delayState.timer.timerId() == e->timerId()) {
+ if (d->currentAction && !d->currentAction->menu())
+ return;
+ d->delayState.stop();
+ d->sloppyState.stopTimer();
internalDelayedPopup();
- } else if (d->sloppyDelayTimer == e->timerId()) {
- killTimer(d->sloppyDelayTimer);
- d->sloppyDelayTimer = 0;
- internalSetSloppyAction();
+ } else if (d->sloppyState.isTimerId(e->timerId())) {
+ d->sloppyState.timeout();
} else if(d->searchBufferTimer.timerId() == e->timerId()) {
d->searchBuffer.clear();
}
@@ -3083,23 +3217,13 @@ void QMenu::actionEvent(QActionEvent *e)
/*!
\internal
*/
-void QMenu::internalSetSloppyAction()
-{
- if (d_func()->sloppyAction)
- d_func()->setCurrentAction(d_func()->sloppyAction, 0);
-}
-
-/*!
- \internal
-*/
void QMenu::internalDelayedPopup()
{
Q_D(QMenu);
-
//hide the current item
if (QMenu *menu = d->activeMenu) {
- d->activeMenu = 0;
- d->hideMenu(menu);
+ if (d->activeMenu->menuAction() != d->currentAction)
+ d->hideMenu(menu);
}
if (!d->currentAction || !d->currentAction->isEnabled() || !d->currentAction->menu() ||
@@ -3113,34 +3237,12 @@ void QMenu::internalDelayedPopup()
int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this);
const QRect actionRect(d->actionRect(d->currentAction));
- const QSize menuSize(d->activeMenu->sizeHint());
const QPoint rightPos(mapToGlobal(QPoint(actionRect.right() + subMenuOffset + 1, actionRect.top())));
QPoint pos(rightPos);
- //calc sloppy focus buffer
- if (style()->styleHint(QStyle::SH_Menu_SloppySubMenus, 0, this)) {
- QPoint cur = QCursor::pos();
- if (actionRect.contains(mapFromGlobal(cur))) {
- QPoint pts[4];
- pts[0] = QPoint(cur.x(), cur.y() - 2);
- pts[3] = QPoint(cur.x(), cur.y() + 2);
- if (pos.x() >= cur.x()) {
- pts[1] = QPoint(geometry().right(), pos.y());
- pts[2] = QPoint(geometry().right(), pos.y() + menuSize.height());
- } else {
- pts[1] = QPoint(pos.x() + menuSize.width(), pos.y());
- pts[2] = QPoint(pos.x() + menuSize.width(), pos.y() + menuSize.height());
- }
- QPolygon points(4);
- for(int i = 0; i < 4; i++)
- points.setPoint(i, mapFromGlobal(pts[i]));
- d->sloppyRegion = QRegion(points);
- }
- }
-
- //do the popup
d->activeMenu->popup(pos);
+ d->sloppyState.setSubMenuPopup(actionRect, d->currentAction, d->activeMenu);
}
/*!
diff --git a/src/widgets/widgets/qmenu.h b/src/widgets/widgets/qmenu.h
index 937f6e3316..0fcbb3d29b 100644
--- a/src/widgets/widgets/qmenu.h
+++ b/src/widgets/widgets/qmenu.h
@@ -180,7 +180,6 @@ protected:
#endif
private Q_SLOTS:
- void internalSetSloppyAction();
void internalDelayedPopup();
private:
diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h
index 4a4518671c..64a728eaba 100644
--- a/src/widgets/widgets/qmenu_p.h
+++ b/src/widgets/widgets/qmenu_p.h
@@ -71,20 +71,230 @@ struct QWceMenuAction {
};
#endif
+template <typename T>
+class QSetValueOnDestroy
+{
+public:
+ QSetValueOnDestroy(T &toSet, T value)
+ : toSet(toSet)
+ , value(value)
+ { }
+
+ ~QSetValueOnDestroy() { toSet = value; }
+private:
+ T &toSet;
+ T value;
+};
+
+class QMenuSloppyState
+{
+ Q_DISABLE_COPY(QMenuSloppyState)
+public:
+ QMenuSloppyState()
+ : m_menu(Q_NULLPTR)
+ , m_enabled(false)
+ , m_uni_directional(false)
+ , m_select_other_actions(false)
+ , m_first_mouse(true)
+ , m_init_guard(false)
+ , m_uni_dir_discarded_count(0)
+ , m_uni_dir_fail_at_count(0)
+ , m_timeout(0)
+ , m_reset_action(Q_NULLPTR)
+ , m_origin_action(Q_NULLPTR)
+ , m_parent(Q_NULLPTR)
+ { }
+
+ ~QMenuSloppyState() { reset(); }
+
+ void initialize(QMenu *menu)
+ {
+ m_menu = menu;
+ m_uni_directional = menu->style()->styleHint(QStyle::SH_Menu_SubMenuUniDirection, 0, menu);
+ m_uni_dir_fail_at_count = menu->style()->styleHint(QStyle::SH_Menu_SubMenuUniDirectionFailCount, 0, menu);
+ m_select_other_actions = menu->style()->styleHint(QStyle::SH_Menu_SubMenuSloppySelectOtherActions, 0 , menu);
+ m_timeout = menu->style()->styleHint(QStyle::SH_Menu_SubMenuSloppyCloseTimeout);
+ m_discard_state_when_entering_parent = menu->style()->styleHint(QStyle::SH_Menu_SubMenuResetWhenReenteringParent);
+ m_dont_start_time_on_leave = menu->style()->styleHint(QStyle::SH_Menu_SubMenuDontStartSloppyOnLeave);
+ reset();
+ }
+
+ void reset();
+ bool enabled() const { return m_enabled; }
+
+ void setResetAction(QAction *action) { m_reset_action = action; }
+
+ enum MouseEventResult {
+ EventIsProcessed,
+ EventShouldBePropogated,
+ EventDiscardsSloppyState
+ };
+
+ void startTimer()
+ {
+ if (m_enabled)
+ m_time.start(m_timeout, m_menu);
+ }
+
+ void startTimerIfNotRunning()
+ {
+ if (!m_time.isActive())
+ startTimer();
+ }
+
+ void stopTimer()
+ {
+ m_time.stop();
+ }
+
+ void enter();
+
+ void childEnter()
+ {
+ stopTimer();
+ if (m_parent)
+ m_parent->childEnter();
+ }
+
+ void leave()
+ {
+ if (m_dont_start_time_on_leave)
+ return;
+ if (m_parent)
+ m_parent->childLeave();
+ startTimer();
+ }
+ void childLeave();
+
+ static float slope(const QPointF &p1, const QPointF &p2)
+ {
+ const QPointF slope = p2 - p1;
+ if (slope.x()== 0)
+ return 9999;
+ return slope.y()/slope.x();
+ }
+
+ bool checkSlope(qreal oldS, qreal newS, bool wantSteeper)
+ {
+ if (wantSteeper)
+ return oldS <= newS;
+ return newS <= oldS;
+ }
+
+ MouseEventResult processMouseEvent(const QPointF &mousePos, QAction *resetAction, QAction *currentAction)
+ {
+ if (m_parent)
+ m_parent->stopTimer();
+
+ if (!m_enabled)
+ return EventShouldBePropogated;
+
+ if (!m_time.isActive())
+ startTimer();
+
+ if (!m_sub_menu) {
+ reset();
+ return EventShouldBePropogated;
+ }
+
+ QSetValueOnDestroy<bool> setFirstMouse(m_first_mouse, false);
+ QSetValueOnDestroy<QPointF> setPreviousPoint(m_previous_point, mousePos);
+
+ if (resetAction && resetAction->isSeparator())
+ m_reset_action = Q_NULLPTR;
+ else {
+ m_reset_action = resetAction;
+ }
+
+ if (m_action_rect.contains(mousePos)) {
+ startTimer();
+ return currentAction == m_menu->menuAction() ? EventIsProcessed : EventShouldBePropogated;
+ }
+
+ if (m_uni_directional && !m_first_mouse && resetAction != m_origin_action) {
+ bool left_to_right = m_menu->layoutDirection() == Qt::LeftToRight;
+ QRect sub_menu_rect = m_sub_menu->geometry();
+ QPoint sub_menu_top =
+ left_to_right? sub_menu_rect.topLeft() : sub_menu_rect.topRight();
+ QPoint sub_menu_bottom =
+ left_to_right? sub_menu_rect.bottomLeft() : sub_menu_rect.bottomRight();
+ qreal prev_slope_top = slope(m_previous_point, sub_menu_top);
+ qreal prev_slope_bottom = slope(m_previous_point, sub_menu_bottom);
+
+ qreal current_slope_top = slope(mousePos, sub_menu_top);
+ qreal current_slope_bottom = slope(mousePos, sub_menu_bottom);
+
+ bool slopeTop = checkSlope(prev_slope_top, current_slope_top, sub_menu_top.y() < mousePos.y());
+ bool slopeBottom = checkSlope(prev_slope_bottom, current_slope_bottom, sub_menu_bottom.y() > mousePos.y());
+ bool rightDirection = false;
+ int mouseDir = m_previous_point.y() - mousePos.y();
+ if (mouseDir >= 0) {
+ rightDirection = rightDirection || slopeTop;
+ }
+ if (mouseDir <= 0) {
+ rightDirection = rightDirection || slopeBottom;
+ }
+
+ if (m_uni_dir_discarded_count >= m_uni_dir_fail_at_count && !rightDirection) {
+ m_uni_dir_discarded_count = 0;
+ return EventDiscardsSloppyState;
+ }
+
+ if (!rightDirection)
+ m_uni_dir_discarded_count++;
+ else
+ m_uni_dir_discarded_count = 0;
+
+ }
+
+ return m_select_other_actions ? EventShouldBePropogated : EventIsProcessed;
+ }
+
+ void setSubMenuPopup(const QRect &actionRect, QAction *resetAction, QMenu *subMenu);
+ bool hasParentActiveDelayTimer() const;
+ void timeout();
+ int timeForTimeout() const { return m_timeout; }
+
+ bool isTimerId(int timerId) const { return m_time.timerId() == timerId; }
+ QMenu *subMenu() const { return m_sub_menu; }
+
+private:
+ QMenu *m_menu;
+ bool m_enabled;
+ bool m_uni_directional;
+ bool m_select_other_actions;
+ bool m_first_mouse;
+ bool m_init_guard;
+ bool m_discard_state_when_entering_parent;
+ bool m_dont_start_time_on_leave;
+ short m_uni_dir_discarded_count;
+ short m_uni_dir_fail_at_count;
+ short m_timeout;
+ QBasicTimer m_time;
+ QAction *m_reset_action;
+ QAction *m_origin_action;
+ QRectF m_action_rect;
+ QPointF m_previous_point;
+ QPointer<QMenu> m_sub_menu;
+ QMenuSloppyState *m_parent;
+};
+
class QMenuPrivate : public QWidgetPrivate
{
Q_DECLARE_PUBLIC(QMenu)
public:
QMenuPrivate() : itemsDirty(0), maxIconWidth(0), tabWidth(0), ncols(0),
collapsibleSeparators(true), toolTipsVisible(false),
- activationRecursionGuard(false), hasHadMouse(0), aboutToHide(0), motions(0),
+ activationRecursionGuard(false), delayedPopupGuard(false),
+ hasReceievedEnter(false),
+ hasHadMouse(0), aboutToHide(0), motions(0),
currentAction(0),
#ifdef QT_KEYPAD_NAVIGATION
selectAction(0),
cancelAction(0),
#endif
scroll(0), eventLoop(0), tearoff(0), tornoff(0), tearoffHighlighted(0),
- hasCheckableItems(0), sloppyDelayTimer(0), sloppyAction(0), doChildEffects(false), platformMenu(0)
+ hasCheckableItems(0), doChildEffects(false), platformMenu(0)
#if defined(Q_OS_WINCE) && !defined(QT_NO_MENUBAR)
,wce_menu(0)
@@ -127,6 +337,8 @@ public:
int getLastVisibleAction() const;
bool activationRecursionGuard;
+ bool delayedPopupGuard;
+ bool hasReceievedEnter;
//selection
static QMenu *mouseDown;
@@ -134,12 +346,39 @@ public:
uint hasHadMouse : 1;
uint aboutToHide : 1;
int motions;
+ int mousePopupDelay;
QAction *currentAction;
#ifdef QT_KEYPAD_NAVIGATION
QAction *selectAction;
QAction *cancelAction;
#endif
- QBasicTimer menuDelayTimer;
+ struct DelayState {
+ DelayState()
+ : parent(0)
+ , action(0)
+ { }
+ void initialize(QMenu *parent)
+ {
+ this->parent = parent;
+ }
+
+ void start(int timeout, QAction *toStartAction)
+ {
+ if (timer.isActive() && toStartAction == action)
+ return;
+ action = toStartAction;
+ timer.start(timeout,parent);
+ }
+ void stop()
+ {
+ action = 0;
+ timer.stop();
+ }
+
+ QMenu *parent;
+ QBasicTimer timer;
+ QAction *action;
+ } delayState;
enum SelectionReason {
SelectedFromKeyboard,
SelectedFromElsewhere
@@ -198,10 +437,7 @@ public:
mutable bool hasCheckableItems;
- //sloppy selection
- int sloppyDelayTimer;
- mutable QAction *sloppyAction;
- QRegion sloppyRegion;
+ QMenuSloppyState sloppyState;
//default action
QPointer<QAction> defaultAction;
@@ -257,6 +493,7 @@ public:
QAction* wceCommands(uint command);
#endif
QPointer<QWidget> noReplayFor;
+ static QPointer<QMenu> previousMouseMenu;
};
#endif // QT_NO_MENU
diff --git a/src/widgets/widgets/qprogressbar.cpp b/src/widgets/widgets/qprogressbar.cpp
index 5501247973..751fcda871 100644
--- a/src/widgets/widgets/qprogressbar.cpp
+++ b/src/widgets/widgets/qprogressbar.cpp
@@ -132,7 +132,7 @@ void QProgressBar::initStyleOption(QStyleOptionProgressBar *option) const
if (QStyleOptionProgressBarV2 *optionV2
= qstyleoption_cast<QStyleOptionProgressBarV2 *>(option)) {
- optionV2->orientation = d->orientation; // ### Qt 5: use State_Horizontal instead
+ optionV2->orientation = d->orientation; // ### Qt 6: remove this member from QStyleOptionProgressBarV2
optionV2->invertedAppearance = d->invertedAppearance;
optionV2->bottomToTop = (d->textDirection == QProgressBar::BottomToTop);
}