aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
authorJan Arve Sæther <jan-arve.saether@qt.io>2017-10-19 14:34:47 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2017-10-27 14:43:23 +0000
commit5cb76fb3704947cfc4d575695b137460ecc8bbd9 (patch)
treeec83080ea86fd407855b459a4b8269ecf22f2e9a /tests/auto
parentec596406c03714dbd6865c18c83bf61d615e5791 (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/auto')
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml78
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp77
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"