diff options
-rw-r--r-- | src/widgets/graphicsview/qgraphicsscene.cpp | 91 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsscene.h | 4 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsscene_p.h | 3 | ||||
-rw-r--r-- | tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp | 36 |
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; |