From: Martin Jones Date: Mon, 25 Jul 2011 03:21:25 +0000 (+1000) Subject: Handle pinch correctly when one point is released and repressed. X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=647ea955f3d1c45cce978a9b85b4732baf49a040;p=konrad%2Fqtdeclarative.git Handle pinch correctly when one point is released and repressed. 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 Reviewed-by: Bea Lam --- diff --git a/src/declarative/items/qsgflickable.cpp b/src/declarative/items/qsgflickable.cpp index 29bda22..f562a85 100644 --- a/src/declarative/items/qsgflickable.cpp +++ b/src/declarative/items/qsgflickable.cpp @@ -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; diff --git a/src/declarative/items/qsgpincharea.cpp b/src/declarative/items/qsgpincharea.cpp index 6c22652..a9bf028 100644 --- a/src/declarative/items/qsgpincharea.cpp +++ b/src/declarative/items/qsgpincharea.cpp @@ -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); diff --git a/src/declarative/items/qsgpincharea_p_p.h b/src/declarative/items/qsgpincharea_p_p.h index 9210bac..9cf928b 100644 --- a/src/declarative/items/qsgpincharea_p_p.h +++ b/src/declarative/items/qsgpincharea_p_p.h @@ -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; diff --git a/tests/auto/declarative/qsgpincharea/data/pinchproperties.qml b/tests/auto/declarative/qsgpincharea/data/pinchproperties.qml index a1cd113..44d1161 100644 --- a/tests/auto/declarative/qsgpincharea/data/pinchproperties.qml +++ b/tests/auto/declarative/qsgpincharea/data/pinchproperties.qml @@ -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; } } } diff --git a/tests/auto/declarative/qsgpincharea/tst_qsgpincharea.cpp b/tests/auto/declarative/qsgpincharea/tst_qsgpincharea.cpp index abfa85c..2e93f71 100644 --- a/tests/auto/declarative/qsgpincharea/tst_qsgpincharea.cpp +++ b/tests/auto/declarative/qsgpincharea/tst_qsgpincharea.cpp @@ -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("pincharea"); + QSGPinch *pinch = pinchArea->pinch(); + QVERIFY(pinchArea != 0); + QVERIFY(pinch != 0); + + QSGItem *root = qobject_cast(canvas->rootObject()); + QVERIFY(root != 0); + + QSignalSpy startedSpy(pinchArea, SIGNAL(pinchStarted(QSGPinchEvent *))); + QSignalSpy finishedSpy(pinchArea, SIGNAL(pinchFinished(QSGPinchEvent *))); + + // target + QSGItem *blackRect = canvas->rootObject()->findChild("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);