summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2018-09-26 17:36:04 +0200
committerUlf Hermann <ulf.hermann@qt.io>2018-10-04 07:00:21 +0000
commit21355b3630882932be940a48a88d8c40cf7ebf63 (patch)
tree7228a7b44299f02a500f7502db509e84d262e290
parentd37d8e962a1b9e83800d17207c78bc87f7d64c31 (diff)
QGraphicsScene: Make focusing on touchBegin optional
Usually we focus in when we receive a click or equivalent. QGraphicsScene by default also transfers the focus when you start a touch on a trackpad or similar. Most of the time this also generates a synthetic mouse click, so people don't necessary notice. However, at least on macOS you can configure this behavior. With focusOnTouch switched off, QGraphicsScene behaves as one would expect on macOS. Fixes: QTBUG-59442 Change-Id: Ib87112640eef6b77892ad2490d80eedd055e6dce Reviewed-by: Paul Wicking <paul.wicking@qt.io> Reviewed-by: Venugopal Shivashankar <Venugopal.Shivashankar@qt.io> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
-rw-r--r--src/widgets/graphicsview/qgraphicsscene.cpp91
-rw-r--r--src/widgets/graphicsview/qgraphicsscene.h4
-rw-r--r--src/widgets/graphicsview/qgraphicsscene_p.h3
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp36
4 files changed, 107 insertions, 27 deletions
diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp
index 37af4ecda0..bba992144d 100644
--- a/src/widgets/graphicsview/qgraphicsscene.cpp
+++ b/src/widgets/graphicsview/qgraphicsscene.cpp
@@ -297,6 +297,7 @@ QGraphicsScenePrivate::QGraphicsScenePrivate()
painterStateProtection(true),
sortCacheEnabled(false),
allItemsIgnoreTouchEvents(true),
+ focusOnTouch(true),
minimumRenderSize(0.0),
selectionChanging(0),
rectAdjust(2),
@@ -2393,6 +2394,7 @@ void QGraphicsScene::clear()
d->allItemsIgnoreHoverEvents = true;
d->allItemsUseDefaultCursor = true;
d->allItemsIgnoreTouchEvents = true;
+ d->focusOnTouch = true;
}
/*!
@@ -5854,6 +5856,41 @@ void QGraphicsScene::setMinimumRenderSize(qreal minSize)
update();
}
+/*!
+ \property QGraphicsScene::focusOnTouch
+ \since 5.12
+ \brief whether items gain focus when receiving a \e {touch begin} event.
+
+ The usual behavior is to transfer focus only when an item is clicked. Often
+ a tap on a touchpad is interpreted as equivalent to a mouse click by the
+ operating system, generating a synthesized click event in response. However,
+ at least on macOS you can configure this behavior.
+
+ By default, QGraphicsScene also transfers focus when you touch on a trackpad
+ or similar. If the operating system is configured to not generate a
+ synthetic mouse click on tapping the trackpad, this is surprising. If the
+ operating system does generate synthetic mouse clicks on tapping the
+ trackpad, the focus transfer on starting a touch gesture is unnecessary.
+
+ With focusOnTouch switched off, QGraphicsScene behaves as one would expect
+ on macOS.
+
+ The default value is \c true, ensuring that the default behavior is just as
+ in Qt versions prior to 5.12. Set to \c false to prevent touch events from
+ triggering focus changes.
+*/
+bool QGraphicsScene::focusOnTouch() const
+{
+ Q_D(const QGraphicsScene);
+ return d->focusOnTouch;
+}
+
+void QGraphicsScene::setFocusOnTouch(bool enabled)
+{
+ Q_D(QGraphicsScene);
+ d->focusOnTouch = enabled;
+}
+
void QGraphicsScenePrivate::addView(QGraphicsView *view)
{
views << view;
@@ -6033,39 +6070,41 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve
{
Q_Q(QGraphicsScene);
- if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.constFirst() != origin) {
- const QTouchEvent::TouchPoint &firstTouchPoint = touchEvent->touchPoints().first();
- cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint.screenPos().toPoint(),
- firstTouchPoint.scenePos(),
- static_cast<QWidget *>(touchEvent->target()));
- }
+ if (focusOnTouch) {
+ if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.constFirst() != origin) {
+ const QTouchEvent::TouchPoint &firstTouchPoint = touchEvent->touchPoints().first();
+ cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint.screenPos().toPoint(),
+ firstTouchPoint.scenePos(),
+ static_cast<QWidget *>(touchEvent->target()));
+ }
- // Set focus on the topmost enabled item that can take focus.
- bool setFocus = false;
+ // Set focus on the topmost enabled item that can take focus.
+ bool setFocus = false;
- foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
- if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
- if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
+ foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
+ if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
+ if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
+ setFocus = true;
+ if (item != q->focusItem())
+ q->setFocusItem(item, Qt::MouseFocusReason);
+ break;
+ }
+ }
+ if (item->isPanel())
+ break;
+ if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
+ break;
+ if (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling) {
+ // Make sure we don't clear focus.
setFocus = true;
- if (item != q->focusItem())
- q->setFocusItem(item, Qt::MouseFocusReason);
break;
}
}
- if (item->isPanel())
- break;
- if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
- break;
- if (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling) {
- // Make sure we don't clear focus.
- setFocus = true;
- break;
- }
- }
- // If nobody could take focus, clear it.
- if (!stickyFocus && !setFocus)
- q->setFocusItem(0, Qt::MouseFocusReason);
+ // If nobody could take focus, clear it.
+ if (!stickyFocus && !setFocus)
+ q->setFocusItem(0, Qt::MouseFocusReason);
+ }
bool res = false;
bool eventAccepted = touchEvent->isAccepted();
diff --git a/src/widgets/graphicsview/qgraphicsscene.h b/src/widgets/graphicsview/qgraphicsscene.h
index 8efbcd273e..287e551db7 100644
--- a/src/widgets/graphicsview/qgraphicsscene.h
+++ b/src/widgets/graphicsview/qgraphicsscene.h
@@ -106,6 +106,7 @@ class Q_WIDGETS_EXPORT QGraphicsScene : public QObject
Q_PROPERTY(bool sortCacheEnabled READ isSortCacheEnabled WRITE setSortCacheEnabled)
Q_PROPERTY(bool stickyFocus READ stickyFocus WRITE setStickyFocus)
Q_PROPERTY(qreal minimumRenderSize READ minimumRenderSize WRITE setMinimumRenderSize)
+ Q_PROPERTY(bool focusOnTouch READ focusOnTouch WRITE setFocusOnTouch)
public:
enum ItemIndexMethod {
@@ -253,6 +254,9 @@ public:
qreal minimumRenderSize() const;
void setMinimumRenderSize(qreal minSize);
+ bool focusOnTouch() const;
+ void setFocusOnTouch(bool enabled);
+
public Q_SLOTS:
void update(const QRectF &rect = QRectF());
void invalidate(const QRectF &rect = QRectF(), SceneLayers layers = AllLayers);
diff --git a/src/widgets/graphicsview/qgraphicsscene_p.h b/src/widgets/graphicsview/qgraphicsscene_p.h
index 2f5d7c54bb..a2d13436fc 100644
--- a/src/widgets/graphicsview/qgraphicsscene_p.h
+++ b/src/widgets/graphicsview/qgraphicsscene_p.h
@@ -114,7 +114,8 @@ public:
quint32 painterStateProtection : 1;
quint32 sortCacheEnabled : 1; // for compatibility
quint32 allItemsIgnoreTouchEvents : 1;
- quint32 padding : 15;
+ quint32 focusOnTouch : 1;
+ quint32 padding : 14;
qreal minimumRenderSize;
diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
index c8ee2d65a3..838b1f4be6 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
@@ -254,6 +254,7 @@ private slots:
void zeroScale();
void focusItemChangedSignal();
void minimumRenderSize();
+ void focusOnTouch();
// task specific tests below me
void task139710_bspTreeCrash();
@@ -4758,6 +4759,41 @@ void tst_QGraphicsScene::minimumRenderSize()
QVERIFY(smallChild->repaints > smallerGrandChild->repaints);
}
+void tst_QGraphicsScene::focusOnTouch()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ scene.setSceneRect(0, 0, 100, 100);
+ QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100);
+ rect->setFlag(QGraphicsItem::ItemIsFocusable, true);
+
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QVERIFY(!rect->hasFocus());
+
+ scene.setFocusOnTouch(false);
+
+ QTouchDevice device;
+ device.setType(QTouchDevice::TouchPad);
+ QList<QTouchEvent::TouchPoint> touchPoints;
+ QTouchEvent::TouchPoint point;
+ point.setScenePos(QPointF(10, 10));
+ point.setState(Qt::TouchPointPressed);
+ touchPoints.append(point);
+ QTouchEvent event(QEvent::TouchBegin, &device, Qt::NoModifier, Qt::TouchPointStates(),
+ touchPoints);
+
+ QApplication::sendEvent(&scene, &event);
+
+ QVERIFY(!rect->hasFocus());
+ scene.setFocusOnTouch(true);
+
+ QApplication::sendEvent(&scene, &event);
+ QVERIFY(rect->hasFocus());
+}
+
void tst_QGraphicsScene::taskQTBUG_15977_renderWithDeviceCoordinateCache()
{
QGraphicsScene scene;