summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSophie Kums <sophie.kums@web.de>2021-01-06 16:34:06 +0100
committerSophie Kums <sophie.kums@web.de>2021-01-19 19:10:41 +0100
commitaa09bea00ca88c587cfb1f56dc9a85040dd63b22 (patch)
tree9c9ea00f93acedc08ac7df8a4d9c4fc9e97f8970
parent65cc6ec16bd724f96007748823bb8902e3a7881b (diff)
control scrolling of QTabBar using StyleHint
Mouse wheel/touchpad scroll signals sent to the tab bar trigger cycling through the tabs. In applications where the tab bar is close to "mouse click hotspots", the cursor may accidentally be left over the tab bar instead of the main content of the window. When the user wants to scroll up/down the main conten, the scroll signals are thus sent to the tab bar and instead of scrolling, the focus switches to another tab. This is confusing to the user, because not only does the application not carry out the desired action (scrolling through the main content), it jumps to a different tab. Two common examples of applications affected by this nuisance are Konsole and any kind of browser (file browser or web browser), where the address bar is right below the tab bar. Moreover, on macOS, scroll events do not have an effect on the tab bar widget of the native UI. Currently, the code makes use of preprocessor directives to achieve consistent behavior on macOS (`#ifndef Q_OS_MAC`). This patch implements the check of a StyleHint in order to determine if scroll events on the tabbar should have an effect. This approach is more consistent with Qt coding style than OS-dependent preprocessor directives and, in addition, makes the behavior configurable according to the user's preferences. [ChangeLog][QtWidgets][QStyle] Added SH_TabBar_AllowWheelScrolling as a style hint to enable/disable cycling through tabs using the scroll wheel. This defaults to true in all styles except the macOS one so there is no change in existing behavior. Change-Id: I99eeb5a1aab03cbc574fac7187d85a8a2d60cf34 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm3
-rw-r--r--src/widgets/styles/qcommonstyle.cpp3
-rw-r--r--src/widgets/styles/qstyle.cpp5
-rw-r--r--src/widgets/styles/qstyle.h1
-rw-r--r--src/widgets/widgets/qtabbar.cpp16
-rw-r--r--tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp60
6 files changed, 79 insertions, 9 deletions
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index 2be0a490ce..7b3709459d 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -2902,6 +2902,9 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
case SH_Table_GridLineColor:
ret = int(qt_mac_toQColor(NSColor.gridColor).rgba());
break;
+ case SH_TabBar_AllowWheelScrolling:
+ ret = false;
+ break;
default:
ret = QCommonStyle::styleHint(sh, opt, w, hret);
break;
diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp
index 5c5b25cc94..fd618149ac 100644
--- a/src/widgets/styles/qcommonstyle.cpp
+++ b/src/widgets/styles/qcommonstyle.cpp
@@ -5407,6 +5407,9 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget
case SH_SpinBox_StepModifier:
ret = Qt::ControlModifier;
break;
+ case SH_TabBar_AllowWheelScrolling:
+ ret = true;
+ break;
default:
ret = 0;
break;
diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp
index 9f49a55386..c839afd639 100644
--- a/src/widgets/styles/qstyle.cpp
+++ b/src/widgets/styles/qstyle.cpp
@@ -2005,6 +2005,11 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
disables this feature.
This enum value has been introduced in Qt 5.12.
+ \value SH_TabBar_AllowWheelScrolling
+ Determines if the mouse wheel can be used to cycle through the tabs
+ of a QTabBar.
+ This enum value has been introduced in Qt 6.1.
+
\sa styleHint()
*/
diff --git a/src/widgets/styles/qstyle.h b/src/widgets/styles/qstyle.h
index ec13fdb80d..ba64a6b1bf 100644
--- a/src/widgets/styles/qstyle.h
+++ b/src/widgets/styles/qstyle.h
@@ -733,6 +733,7 @@ public:
SH_ComboBox_AllowWheelScrolling,
SH_SpinBox_ButtonsInsideFrame,
SH_SpinBox_StepModifier,
+ SH_TabBar_AllowWheelScrolling,
// Add new style hint values here
SH_CustomBase = 0xf0000000
diff --git a/src/widgets/widgets/qtabbar.cpp b/src/widgets/widgets/qtabbar.cpp
index b21e038843..a390f9ec0d 100644
--- a/src/widgets/widgets/qtabbar.cpp
+++ b/src/widgets/widgets/qtabbar.cpp
@@ -2363,16 +2363,14 @@ void QTabBar::keyPressEvent(QKeyEvent *event)
#if QT_CONFIG(wheelevent)
void QTabBar::wheelEvent(QWheelEvent *event)
{
-#ifndef Q_OS_MAC
Q_D(QTabBar);
- int delta = (qAbs(event->angleDelta().x()) > qAbs(event->angleDelta().y()) ?
- event->angleDelta().x() : event->angleDelta().y());
- int offset = delta > 0 ? -1 : 1;
- d->setCurrentNextEnabledIndex(offset);
- QWidget::wheelEvent(event);
-#else
- Q_UNUSED(event);
-#endif
+ if (style()->styleHint(QStyle::SH_TabBar_AllowWheelScrolling)) {
+ int delta = (qAbs(event->angleDelta().x()) > qAbs(event->angleDelta().y()) ?
+ event->angleDelta().x() : event->angleDelta().y());
+ int offset = delta > 0 ? -1 : 1;
+ d->setCurrentNextEnabledIndex(offset);
+ QWidget::wheelEvent(event);
+ }
}
#endif // QT_CONFIG(wheelevent)
diff --git a/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp b/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp
index 9d6d4b599c..7f713ebe6d 100644
--- a/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp
+++ b/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp
@@ -33,6 +33,7 @@
#include <QPushButton>
#include <QStyle>
#include <QStyleOptionTab>
+#include <QProxyStyle>
#include <QTimer>
class TabBar;
@@ -98,6 +99,8 @@ private slots:
void mouseReleaseOutsideTabBar();
+ void mouseWheel();
+
private:
void checkPositions(const TabBar &tabbar, const QList<int> &positions);
};
@@ -869,5 +872,62 @@ void tst_QTabBar::checkPositions(const TabBar &tabbar, const QList<int> &positio
}
}
+#if QT_CONFIG(wheelevent)
+// defined to be 120 by the wheel mouse vendors according to the docs
+#define WHEEL_DELTA 120
+
+class TabBarScrollingProxyStyle : public QProxyStyle
+{
+public:
+ TabBarScrollingProxyStyle() : QProxyStyle(), scrolling(true)
+ { }
+
+ int styleHint(StyleHint hint, const QStyleOption *option = 0,
+ const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const override
+ {
+ if (hint == QStyle::SH_TabBar_AllowWheelScrolling)
+ return scrolling;
+
+ return QProxyStyle::styleHint(hint, option, widget, returnData);
+ }
+
+ bool scrolling;
+};
+
+void tst_QTabBar::mouseWheel()
+{
+
+ // apply custom style to app, which can toggle tabbar scrolling behavior
+ QCoreApplication *applicationInstance = QApplication::instance();
+ QVERIFY(applicationInstance != 0);
+ auto *proxyStyle = new TabBarScrollingProxyStyle;
+ QApplication::setStyle(proxyStyle);
+
+ // make tabbar with three tabs, select the middle one
+ TabBar tabbar;
+ tabbar.addTab("one");
+ tabbar.addTab("two");
+ tabbar.addTab("three");
+ int startIndex = 1;
+ tabbar.setCurrentIndex(startIndex);
+
+ // define scroll event
+ const QPoint wheelPoint = tabbar.rect().bottomRight();
+ QWheelEvent event(wheelPoint, tabbar.mapToGlobal(wheelPoint), QPoint(), QPoint(0, WHEEL_DELTA),
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
+
+ // disable scrolling, send scroll event, confirm that tab did not change
+ proxyStyle->scrolling = false;
+ QVERIFY(applicationInstance->sendEvent(&tabbar, &event));
+ QVERIFY(tabbar.currentIndex() == startIndex);
+
+ // enable scrolling, send scroll event, confirm that tab changed
+ proxyStyle->scrolling = true;
+ QVERIFY(applicationInstance->sendEvent(&tabbar, &event));
+ QVERIFY(tabbar.currentIndex() != startIndex);
+}
+
+#endif // QT_CONFIG(wheelevent)
+
QTEST_MAIN(tst_QTabBar)
#include "tst_qtabbar.moc"