diff options
author | Jan Arve Sæther <jan-arve.saether@qt.io> | 2017-10-19 14:34:47 +0200 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2017-10-27 14:43:23 +0000 |
commit | 5cb76fb3704947cfc4d575695b137460ecc8bbd9 (patch) | |
tree | ec83080ea86fd407855b459a4b8269ecf22f2e9a /tests | |
parent | ec596406c03714dbd6865c18c83bf61d615e5791 (diff) |
Fix a bug with TapHandler+DragHandler on top of Flickable
If an item that had a TapHandler and a DragHandler was placed inside a
Flickable it would call sendFilteredPointerEvent() for each of the
handlers, even if they were siblings.
This is not ideal, and because of a mechanism in flickable it even caused
the DragHandler to not drag the item as expected.
This is because of a mechanism in Flickable where the value returned is
actually derived from the previous call to filterMouseEvent() (stored in
member variable stealGrab).
Below are the relevant steps it went through when the mouse drag exceeded
the drag threshold (mouse pointer started on the item):
Precondition: QQuickFlickablePrivate::stealMouse == false
1. Mouse Drag (which exceeded drag threshold)
2. sendFilteredPointerEvent(tapHandler->parentItem()) returns false.
(but since it moved beyond threshold, it would set stealGrab-> true).
3. tapHandler->handlePointerEvent() declined and ungrabbed (due to
DragThreshold gesture policy).
4. sendFilteredPointerEvent(dragHandler->parentItem()) returns true
(because the previous call to sendFilteredPointerEvent() set stealGrab
to true).
As a consequence of (4), dragHandler->handlePointerEvent() was not called,
and the flickable would start to flick instead of the item starting to drag.
Change-Id: Ia99eae91cad0903ebbaedaaafcdf92a25705a922
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml | 78 | ||||
-rw-r--r-- | tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp | 77 |
2 files changed, 154 insertions, 1 deletions
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml index 833fef0a81..651f290570 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml @@ -43,7 +43,7 @@ import Qt.labs.handlers 1.0 Rectangle { id: root - width: 400 + width: 500 height: 480 objectName: "root" color: "#222222" @@ -81,6 +81,82 @@ Rectangle { gesturePolicy: TapHandler.ReleaseWithinBounds // the default } } + Column { + spacing: 6 + Rectangle { + width: 50 + height: 50 + color: "aqua" + border.color: drag1.active ? "darkgreen" : "transparent" + border.width: 3 + objectName: "drag" + DragHandler { + id: drag1 + } + Text { + anchors.centerIn: parent + enabled: false + text: "drag" + } + } + Rectangle { + width: 50 + height: 50 + color: "aqua" + objectName: "tap" + border.color: tap1.isPressed ? "red" : "transparent" + border.width: 3 + TapHandler { + id: tap1 + gesturePolicy: TapHandler.DragThreshold + } + Text { + anchors.centerIn: parent + enabled: false + text: "tap" + } + } + Rectangle { + width: 50 + height: 50 + color: "aqua" + border.color: tap2.isPressed ? "red" : drag2.active ? "darkgreen" : "transparent" + border.width: 3 + objectName: "dragAndTap" + DragHandler { + id: drag2 + } + TapHandler { + id: tap2 + gesturePolicy: TapHandler.DragThreshold + } + Text { + anchors.centerIn: parent + enabled: false + text: "drag\nand\ntap" + } + } + Rectangle { + width: 50 + height: 50 + color: "aqua" + border.color: tap3.isPressed ? "red" : drag3.active ? "darkgreen" : "transparent" + border.width: 3 + objectName: "tapAndDrag" + TapHandler { + id: tap3 + gesturePolicy: TapHandler.DragThreshold + } + DragHandler { + id: drag3 + } + Text { + anchors.centerIn: parent + enabled: false + text: "tap\nand\ndrag" + } + } + } } } } diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp index c8fe6052fb..7862d72db8 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp +++ b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp @@ -71,6 +71,10 @@ private slots: void touchDragFlickableBehindSlider(); void mouseDragSlider(); void mouseDragFlickableBehindSlider(); + void touchDragFlickableBehindItemWithHandlers_data(); + void touchDragFlickableBehindItemWithHandlers(); + void mouseDragFlickableBehindItemWithHandlers_data(); + void mouseDragFlickableBehindItemWithHandlers(); private: void createView(QScopedPointer<QQuickView> &window, const char *fileName); @@ -469,6 +473,79 @@ void tst_FlickableInterop::mouseDragFlickableBehindSlider() QCOMPARE(translationChangedSpy.count(), 0); } +void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers_data() +{ + QTest::addColumn<QByteArray>("nameOfRectangleToDrag"); + QTest::addColumn<bool>("expectedFlickableMoving"); + QTest::newRow("drag") << QByteArray("drag") << false; + QTest::newRow("tap") << QByteArray("tap") << true; + QTest::newRow("dragAndTap") << QByteArray("dragAndTap") << false; + QTest::newRow("tapAndDrag") << QByteArray("tapAndDrag") << false; +} + +void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers() +{ + QFETCH(bool, expectedFlickableMoving); + QFETCH(QByteArray, nameOfRectangleToDrag); + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>(nameOfRectangleToDrag); + QVERIFY(rect); + QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + QPoint p1 = rect->mapToScene(rect->clipRect().center()).toPoint(); + QPoint originP1 = p1; + + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + for (int i = 0; i < dragThreshold * 3; ++i) { + p1 = originP1; + p1.rx() += i; + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + } + QCOMPARE(flickable->isMoving(), expectedFlickableMoving); + if (!expectedFlickableMoving) { + QVERIFY(rect->mapToScene(rect->clipRect().center()).toPoint().x() > originP1.x()); + } + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); +} + +void tst_FlickableInterop::mouseDragFlickableBehindItemWithHandlers_data() +{ + touchDragFlickableBehindItemWithHandlers_data(); +} + +void tst_FlickableInterop::mouseDragFlickableBehindItemWithHandlers() +{ + QFETCH(bool, expectedFlickableMoving); + QFETCH(QByteArray, nameOfRectangleToDrag); + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>(nameOfRectangleToDrag); + QVERIFY(rect); + QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + QPoint p1 = rect->mapToScene(rect->clipRect().center()).toPoint(); + QPoint originP1 = p1; + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + for (int i = 0; i < 3; ++i) { + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QQuickTouchUtils::flush(window); + } + QCOMPARE(flickable->isMoving(), expectedFlickableMoving); + if (!expectedFlickableMoving) { + QCOMPARE(originP1 + QPoint(3*dragThreshold, 0), p1); + } + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); +} + QTEST_MAIN(tst_FlickableInterop) #include "tst_flickableinterop.moc" |