Nested Flickables with pressDelay flick incorrect Flickable
authorMartin Jones <martin.jones@jollamobile.com>
Sun, 25 Nov 2012 23:33:20 +0000 (09:33 +1000)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Mon, 26 Nov 2012 01:00:02 +0000 (02:00 +0100)
If the gesture is triggered within the pressDelay the outer Flickable
will always handle the gesture.  When the drag distance is exceeded
replay the press event to allow all Flickables an opportunity to
process the gesture normally.

Task-number: QTBUG-28189
Change-Id: I36912cc19a48c90ae7a9a430580a8f40071bd5fd
Reviewed-by: Andrew den Exter <andrew.den.exter@qinetic.com.au>
src/quick/items/qquickflickable.cpp
tests/auto/quick/qquickflickable/data/nestedPressDelay.qml
tests/auto/quick/qquickflickable/tst_qquickflickable.cpp

index a0bd1fa..105989c 100644 (file)
@@ -2007,6 +2007,22 @@ bool QQuickFlickable::sendMouseEvent(QMouseEvent *event)
 
         switch (mouseEvent->type()) {
         case QEvent::MouseMove:
+            if (d->delayedPressEvent) {
+                // A move beyond the threshold replays the press to give nested Flickables
+                // the opportunity to grab the gesture.
+                QPointF delta = event->localPos() - d->delayedPressEvent->localPos();
+                if (QQuickWindowPrivate::dragOverThreshold(qAbs(delta.x()), Qt::XAxis, event)
+                    || QQuickWindowPrivate::dragOverThreshold(qAbs(delta.y()), Qt::YAxis, event)) {
+                    // We replay the mouse press but the grabber we had might not be interested in the event (e.g. overlay)
+                    // so we reset the grabber
+                    if (c->mouseGrabberItem() == d->delayedPressTarget)
+                        d->delayedPressTarget->ungrabMouse();
+                    // Use the event handler that will take care of finding the proper item to propagate the event
+                    QQuickWindowPrivate::get(window())->deliverMouseEvent(d->delayedPressEvent);
+                    d->clearDelayedPress();
+                    // continue on to handle mouse move event
+                }
+            }
             d->handleMouseMoveEvent(mouseEvent.data());
             break;
         case QEvent::MouseButtonPress:
index 60dadcc..557b7c4 100644 (file)
@@ -8,24 +8,30 @@ Flickable {
     contentHeight: 320
     flickableDirection: Flickable.HorizontalFlick
     pressDelay: 50
-    Flickable {
-        objectName: "innerFlickable"
-        flickableDirection: Flickable.VerticalFlick
-        width: 480
-        height: 320
-        contentWidth: 480
-        contentHeight: 400
-        pressDelay: 10000
-        Rectangle {
-            y: 100
-            anchors.horizontalCenter: parent.horizontalCenter
-            width: 240
-            height: 100
-            color: ma.pressed ? 'blue' : 'green'
-            MouseArea {
-                id: ma
-                objectName: "mouseArea"
-                anchors.fill: parent
+    Rectangle {
+        x: 20
+        y: 20
+        width: 400
+        height: 300
+        color: "yellow"
+        Flickable {
+            objectName: "innerFlickable"
+            anchors.fill: parent
+            flickableDirection: Flickable.HorizontalFlick
+            contentWidth: 1480
+            contentHeight: 400
+            pressDelay: 10000
+            Rectangle {
+                y: 100
+                x: 80
+                width: 240
+                height: 100
+                color: ma.pressed ? 'blue' : 'green'
+                MouseArea {
+                    id: ma
+                    objectName: "mouseArea"
+                    anchors.fill: parent
+                }
             }
         }
     }
index 703e291..ceed276 100644 (file)
@@ -388,6 +388,35 @@ void tst_qquickflickable::nestedPressDelay()
 
     QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(150, 150));
 
+    // Dragging inner Flickable should work
+    QTest::mousePress(window, Qt::LeftButton, 0, QPoint(80, 150));
+    // the MouseArea is not pressed immediately
+    QVERIFY(outer->property("pressed").toBool() == false);
+
+    QTest::mouseMove(window, QPoint(60, 150));
+    QTest::mouseMove(window, QPoint(40, 150));
+    QTest::mouseMove(window, QPoint(20, 150));
+
+    QVERIFY(outer->property("moving").toBool() == false);
+    QVERIFY(inner->property("moving").toBool() == true);
+
+    QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(20, 150));
+
+    // Dragging the MouseArea in the inner Flickable should move the inner Flickable
+    QTest::mousePress(window, Qt::LeftButton, 0, QPoint(150, 150));
+    // the MouseArea is not pressed immediately
+    QVERIFY(outer->property("pressed").toBool() == false);
+
+    QTest::mouseMove(window, QPoint(130, 150));
+    QTest::mouseMove(window, QPoint(110, 150));
+    QTest::mouseMove(window, QPoint(90, 150));
+
+
+    QVERIFY(outer->property("moving").toBool() == false);
+    QVERIFY(inner->property("moving").toBool() == true);
+
+    QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(90, 150));
+
     delete window;
 }