summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;