aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2021-05-03 11:15:49 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2021-05-27 14:26:35 +0200
commit42ae5a32eb384cb7042eeace193aa42637970387 (patch)
treec4ce2e9bcfd0e8703828406a7d53069df328c828
parent1b56c6ebb3fa66ebf0f7366bd9ba5a50089f4d95 (diff)
Keep DragHandler active while dragging even if other event happens
QQuickPointerHandler::handlePointerEvent() calls setActive(false) when wantsPointerEvent() returns false (except for a NativeGesture event), for the sake of deactivating reliably when it receives an event which it does not handle. Now we need one more exception, because it's not what we want in DragHandler while dragging: If we get a wheel event, that should not interrupt the current drag operation. Thus, we change the logic in wantsPointerEvent to consider even events we wouldn't normally handle while the DragHandler is active. In handlePointerEventImpl, we then simply ignore them. Fixes: QTBUG-91549 Change-Id: I24e8bd890a21b244c9964f4df76986688085fa87 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> (cherry picked from commit 40bbf1e8fddebb0974426a03b0f48dfc08f942de)
-rw-r--r--src/quick/handlers/qquickdraghandler.cpp11
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragAndWheel.qml32
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp73
3 files changed, 115 insertions, 1 deletions
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp
index 980481303f..9471ef7660 100644
--- a/src/quick/handlers/qquickdraghandler.cpp
+++ b/src/quick/handlers/qquickdraghandler.cpp
@@ -182,7 +182,13 @@ void QQuickDragHandler::onActiveChanged()
bool QQuickDragHandler::wantsPointerEvent(QPointerEvent *event)
{
if (!QQuickMultiPointHandler::wantsPointerEvent(event))
- return false;
+ /* Do handle other events than we would normally care about
+ while we are still doing a drag; otherwise we would suddenly
+ become inactive when a wheel event arrives during dragging.
+ This extra condition needs to be kept in sync with
+ handlePointerEventImpl */
+ if (!active())
+ return false;
#if QT_CONFIG(gestures)
if (event->type() == QEvent::NativeGesture)
@@ -194,6 +200,9 @@ bool QQuickDragHandler::wantsPointerEvent(QPointerEvent *event)
void QQuickDragHandler::handlePointerEventImpl(QPointerEvent *event)
{
+ if (active() && !QQuickMultiPointHandler::wantsPointerEvent(event))
+ return; // see QQuickDragHandler::wantsPointerEvent; we don't want to handle those events
+
QQuickMultiPointHandler::handlePointerEventImpl(event);
event->setAccepted(true);
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragAndWheel.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragAndWheel.qml
new file mode 100644
index 0000000000..811326aaba
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragAndWheel.qml
@@ -0,0 +1,32 @@
+import QtQuick 2.15
+
+Item {
+ id: root
+
+ property bool gotWheel: false
+ property int changeCount: 0
+ property alias wheelHandlerEnabled: wheelHandler.enabled
+
+ width: 640
+ height: 480
+
+ Rectangle {
+ color: "blue"
+ width: 200
+ height: 200
+
+ DragHandler {
+ id: dragHandler
+ }
+
+ WheelHandler {
+ id: wheelHandler
+
+ enabled: !dragHandler.active
+ onEnabledChanged: root.changeCount++
+ onWheel: root.gotWheel = true
+ }
+
+ }
+
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
index 9c9ca2fe00..4c9f015679 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
@@ -69,8 +69,10 @@ private slots:
void touchPassiveGrabbers_data();
void touchPassiveGrabbers();
void touchPinchAndMouseMove();
+ void unsuitableEventDuringDrag();
private:
+ void sendWheelEvent(QQuickView &window, QPoint pos, QPoint angleDelta, QPoint pixelDelta, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase, bool inverted);
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
QSet<QQuickPointerHandler *> passiveGrabbers(QQuickWindow *window, int pointId = 0);
QPointingDevice *touchDevice;
@@ -821,6 +823,77 @@ void tst_DragHandler::touchPinchAndMouseMove()
}
}
+void tst_DragHandler::unsuitableEventDuringDrag()
+{
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "dragAndWheel.qml");
+ QQuickView *window = windowPtr.data();
+ auto root = window->rootObject();
+ QQmlProperty changeCount(root, "changeCount");
+ QQmlProperty wheelHandlerEnabled(root, "wheelHandlerEnabled");
+ bool ok = false;
+ QCOMPARE(changeCount.read().toInt(&ok), 0);
+ QVERIFY(ok);
+ QCOMPARE(wheelHandlerEnabled.read().toBool(), true);
+
+ QPoint p1(100, 100);
+ QPoint p2(150, 150);
+
+ QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice);
+ // When we start dragging...
+ touch.press(3,p1).commit();
+ touch.move(3, p2).commit();
+ QQuickTouchUtils::flush(window);
+ // the DragHandler becomes active
+ ok = false;
+ QCOMPARE(changeCount.read().toInt(&ok), 1);
+ QVERIFY(ok);
+ QCOMPARE(wheelHandlerEnabled.read().toBool(), false);
+
+ // When a scroll event arrives while we are dragging
+ sendWheelEvent(*window, p2, QPoint(160, 120), QPoint(-360, 120), Qt::NoModifier, Qt::ScrollBegin, false);
+ // nothing changes because the DragHandler is still active, and the wheel handler stays disabled
+ ok = false;
+ QCOMPARE(changeCount.read().toInt(&ok), 1);
+ QVERIFY(ok);
+ QCOMPARE(wheelHandlerEnabled.read().toBool(), false);
+
+ // When we stop dragging...
+ touch.release(3, p2).commit();
+ QQuickTouchUtils::flush(window);
+
+ // the wheel handler becomes active again
+ ok = false;
+ QCOMPARE(changeCount.read().toInt(&ok), 2);
+ QVERIFY(ok);
+ QCOMPARE(wheelHandlerEnabled.read().toBool(), true);
+
+ // During the whole sequence the wheel handler never got a wheel event
+ // as it was disabled:
+ QQmlProperty gotWheel(root, "gotWheel");
+ QVERIFY(!gotWheel.read().toBool());
+
+ // If the WheelHandler is unconditionally enabled...
+ wheelHandlerEnabled.write(true);
+ // it receives scroll events during drags.
+ touch.press(4,p2).commit();
+ touch.move(4, p1).commit();
+ QQuickTouchUtils::flush(window);
+ sendWheelEvent(*window, p2, QPoint(160, 120), QPoint(-360, 120), Qt::NoModifier, Qt::ScrollBegin, false);
+ touch.release(4, p2).commit();
+ QQuickTouchUtils::flush(window);
+ QVERIFY(gotWheel.read().toBool());
+}
+
+void tst_DragHandler::sendWheelEvent(QQuickView &window, QPoint pos, QPoint angleDelta, QPoint pixelDelta, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase, bool inverted)
+{
+ QWheelEvent wheelEvent(pos, window.mapToGlobal(pos), pixelDelta, angleDelta,
+ Qt::NoButton, modifiers, phase, inverted);
+ QGuiApplication::sendEvent(&window, &wheelEvent);
+ qApp->processEvents();
+ QQuickTouchUtils::flush(&window);
+}
+
QTEST_MAIN(tst_DragHandler)
#include "tst_qquickdraghandler.moc"