Handle pinch correctly when one point is released and repressed.
authorMartin Jones <martin.jones@nokia.com>
Mon, 25 Jul 2011 03:21:25 +0000 (13:21 +1000)
committerQt by Nokia <qt-info@nokia.com>
Mon, 25 Jul 2011 04:08:56 +0000 (06:08 +0200)
The pinch is not finished at the time one point is released.  Ensure
that a onPinchStarted is called each time a repress happens, and
that onPinchFinished is called when all points are released.

Fixes: QTBUG-19632

Change-Id: I467dd612383f7dd11d58a9df063dd86860796216
Reviewed-on: http://codereview.qt.nokia.com/2059
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Bea Lam <bea.lam@nokia.com>
src/declarative/items/qsgflickable.cpp
src/declarative/items/qsgpincharea.cpp
src/declarative/items/qsgpincharea_p_p.h
tests/auto/declarative/qsgpincharea/data/pinchproperties.qml
tests/auto/declarative/qsgpincharea/tst_qsgpincharea.cpp

index 29bda22..f562a85 100644 (file)
@@ -1299,10 +1299,9 @@ bool QSGFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
         }
 
         return stealThisEvent || d->delayedPressEvent || disabledItem;
-    } else if (d->lastPosTime.isValid()) {
-        d->lastPosTime.invalidate();
     }
     if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+        d->lastPosTime.invalidate();
         d->clearDelayedPress();
         d->stealMouse = false;
         d->pressed = false;
index 6c22652..a9bf028 100644 (file)
@@ -122,8 +122,6 @@ void QSGPinchArea::updatePinch()
     Q_D(QSGPinchArea);
     if (d->touchPoints.count() == 0) {
         if (d->inPinch) {
-            d->stealMouse = false;
-            setKeepMouseGrab(false);
             d->inPinch = false;
             QPointF pinchCenter = mapFromScene(d->sceneLastCenter);
             QSGPinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, d->pinchRotation);
@@ -141,6 +139,13 @@ void QSGPinchArea::updatePinch()
             if (d->pinch && d->pinch->target())
                 d->pinch->setActive(false);
         }
+        d->initPinch = false;
+        d->pinchRejected = false;
+        d->stealMouse = false;
+        setKeepMouseGrab(false);
+        QSGCanvas *c = canvas();
+        if (c && c->mouseGrabberItem() == this)
+            ungrabMouse();
         return;
     }
     QTouchEvent::TouchPoint touchPoint1 = d->touchPoints.at(0);
@@ -150,10 +155,10 @@ void QSGPinchArea::updatePinch()
         d->id1 = touchPoint1.id();
         d->sceneStartPoint1 = touchPoint1.scenePos();
         d->sceneStartPoint2 = touchPoint2.scenePos();
-        d->inPinch = false;
-        d->pinchRejected = false;
         d->pinchActivated = true;
-    } else if (d->pinchActivated && !d->pinchRejected){
+        d->initPinch = true;
+    }
+    if (d->pinchActivated && !d->pinchRejected){
         const int dragThreshold = QApplication::startDragDistance();
         QPointF p1 = touchPoint1.scenePos();
         QPointF p2 = touchPoint2.scenePos();
@@ -173,12 +178,13 @@ void QSGPinchArea::updatePinch()
         d->id1 = touchPoint1.id();
         if (angle > 180)
             angle -= 360;
-        if (!d->inPinch) {
+        if (!d->inPinch || d->initPinch) {
             if (d->touchPoints.count() >= 2
                     && (qAbs(p1.x()-d->sceneStartPoint1.x()) > dragThreshold
                     || qAbs(p1.y()-d->sceneStartPoint1.y()) > dragThreshold
                     || qAbs(p2.x()-d->sceneStartPoint2.x()) > dragThreshold
                     || qAbs(p2.y()-d->sceneStartPoint2.y()) > dragThreshold)) {
+                d->initPinch = false;
                 d->sceneStartCenter = sceneCenter;
                 d->sceneLastCenter = sceneCenter;
                 d->pinchStartCenter = mapFromScene(sceneCenter);
index 9210bac..9cf928b 100644 (file)
@@ -68,7 +68,7 @@ class QSGPinchAreaPrivate : public QSGItemPrivate
 public:
     QSGPinchAreaPrivate()
       : absorb(true), stealMouse(false), inPinch(false)
-      , pinchRejected(false), pinchActivated(false)
+      , pinchRejected(false), pinchActivated(false), initPinch(false)
       , pinch(0), pinchStartDist(0), pinchStartScale(1.0)
       , pinchLastScale(1.0), pinchStartRotation(0.0), pinchStartAngle(0.0)
       , pinchLastAngle(0.0), pinchRotation(0.0)
@@ -89,6 +89,7 @@ public:
     bool inPinch : 1;
     bool pinchRejected : 1;
     bool pinchActivated : 1;
+    bool initPinch : 1;
     QSGPinch *pinch;
     QPointF sceneStartPoint1;
     QPointF sceneStartPoint2;
index a1cd113..44d1161 100644 (file)
@@ -3,6 +3,7 @@ Rectangle {
     id: whiteRect
     property variant center
     property real scale
+    property int pointCount: 0
     width: 240; height: 320
     color: "white"
     Rectangle {
@@ -32,14 +33,17 @@ Rectangle {
             onPinchStarted: {
                 whiteRect.center = pinch.center
                 whiteRect.scale = pinch.scale
+                whiteRect.pointCount = pinch.pointCount;
             }
             onPinchUpdated: {
                 whiteRect.center = pinch.center
                 whiteRect.scale = pinch.scale
+                whiteRect.pointCount = pinch.pointCount;
             }
             onPinchFinished: {
                 whiteRect.center = pinch.center
                 whiteRect.scale = pinch.scale
+                whiteRect.pointCount = pinch.pointCount;
             }
          }
      }
index abfa85c..2e93f71 100644 (file)
@@ -61,6 +61,7 @@ private slots:
     void pinchProperties();
     void scale();
     void pan();
+    void retouch();
 
 private:
     QSGView *createView();
@@ -310,6 +311,85 @@ void tst_QSGPinchArea::pan()
     delete canvas;
 }
 
+// test pinch, release one point, touch again to continue pinch
+void tst_QSGPinchArea::retouch()
+{
+    QSGView *canvas = createView();
+    canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pinchproperties.qml"));
+    canvas->show();
+    canvas->setFocus();
+    QTest::qWaitForWindowShown(canvas);
+    QVERIFY(canvas->rootObject() != 0);
+    qApp->processEvents();
+
+    QSGPinchArea *pinchArea = canvas->rootObject()->findChild<QSGPinchArea*>("pincharea");
+    QSGPinch *pinch = pinchArea->pinch();
+    QVERIFY(pinchArea != 0);
+    QVERIFY(pinch != 0);
+
+    QSGItem *root = qobject_cast<QSGItem*>(canvas->rootObject());
+    QVERIFY(root != 0);
+
+    QSignalSpy startedSpy(pinchArea, SIGNAL(pinchStarted(QSGPinchEvent *)));
+    QSignalSpy finishedSpy(pinchArea, SIGNAL(pinchFinished(QSGPinchEvent *)));
+
+    // target
+    QSGItem *blackRect = canvas->rootObject()->findChild<QSGItem*>("blackrect");
+    QVERIFY(blackRect != 0);
+
+    QPoint p1(80, 80);
+    QPoint p2(100, 100);
+
+    QTest::touchEvent(canvas).press(0, p1);
+    QTest::touchEvent(canvas).stationary(0).press(1, p2);
+    p1 -= QPoint(10,10);
+    p2 += QPoint(10,10);
+    QTest::touchEvent(canvas).move(0, p1).move(1, p2);
+
+    QCOMPARE(root->property("scale").toReal(), 1.0);
+
+    p1 -= QPoint(10,10);
+    p2 += QPoint(10,10);
+    QTest::touchEvent(canvas).move(0, p1).move(1, p2);
+
+    QCOMPARE(startedSpy.count(), 1);
+
+    QCOMPARE(root->property("scale").toReal(), 1.5);
+    QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50
+    QCOMPARE(blackRect->scale(), 1.5);
+
+    QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 2);
+
+    QCOMPARE(startedSpy.count(), 1);
+    QCOMPARE(finishedSpy.count(), 0);
+
+    QTest::touchEvent(canvas).stationary(0).release(1, p2);
+
+    QCOMPARE(startedSpy.count(), 1);
+    QCOMPARE(finishedSpy.count(), 0);
+
+    QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 1);
+
+    QTest::touchEvent(canvas).stationary(0).press(1, p2);
+    p1 -= QPoint(10,10);
+    p2 += QPoint(10,10);
+    QTest::touchEvent(canvas).move(0, p1).move(1, p2);
+
+    // Lifting and retouching results in onPinchStarted being called again
+    QCOMPARE(startedSpy.count(), 2);
+    QCOMPARE(finishedSpy.count(), 0);
+
+    QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 2);
+
+    QTest::touchEvent(canvas).release(0, p1).release(1, p2);
+
+    QCOMPARE(startedSpy.count(), 2);
+    QCOMPARE(finishedSpy.count(), 1);
+
+    delete canvas;
+}
+
+
 QSGView *tst_QSGPinchArea::createView()
 {
     QSGView *canvas = new QSGView(0);