aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/auto/quick/pointerhandlers/pointerhandlers.pro1
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml69
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml59
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml53
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/qquickpinchhandler.pro16
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp692
-rw-r--r--tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp2
7 files changed, 891 insertions, 1 deletions
diff --git a/tests/auto/quick/pointerhandlers/pointerhandlers.pro b/tests/auto/quick/pointerhandlers/pointerhandlers.pro
index dc14bc1c27..df9869315f 100644
--- a/tests/auto/quick/pointerhandlers/pointerhandlers.pro
+++ b/tests/auto/quick/pointerhandlers/pointerhandlers.pro
@@ -7,6 +7,7 @@ qtConfig(private_tests) {
qquickpointerhandler \
qquickpointhandler \
qquickdraghandler \
+ qquickpinchhandler \
qquicktaphandler \
}
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml
new file mode 100644
index 0000000000..15775df1e7
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+
+Rectangle {
+ id: whiteRect
+ property real scale: -1.0
+ property int activeCount : 0
+ property int deactiveCount : 0
+ width: 240; height: 320
+ color: "white"
+ Rectangle {
+ id: blackRect
+ objectName: "blackrect"
+ color: "black"
+ y: 50
+ x: 50
+ width: 100
+ height: 100
+ opacity: (whiteRect.width-blackRect.x+whiteRect.height-blackRect.y-199)/200
+ Text { color: "white"; text: "opacity: " + blackRect.opacity + "\nscale: " + blackRect.scale}
+ PinchHandler {
+ id: pincharea
+ objectName: "pinchHandler"
+ minimumScale: 1.0
+ maximumScale: 4.0
+ minimumRotation: 0.0
+ maximumRotation: 90.0
+ xAxis.maximum: 140
+ yAxis.maximum: 170
+ onActiveChanged: {
+ whiteRect.scale = pincharea.scale
+ if (active) ++activeCount
+ else ++deactiveCount;
+ }
+
+ onUpdated: {
+ whiteRect.scale = pincharea.scale
+ //whiteRect.pointCount = pincharea.pointCount
+ }
+ }
+ }
+ }
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml
new file mode 100644
index 0000000000..4d1a520c01
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+
+Rectangle {
+ id: root
+ property variant centroid : pinchHandler.centroid
+ property real scale: pinchHandler.scale
+ property int pointCount: 0
+ property bool pinchActive: pinchHandler.active
+ width: 240; height: 320
+
+ Rectangle {
+ id: blackRect
+ objectName: "blackrect"
+ color: "black"
+ y: 50
+ x: 50
+ width: 200
+ height: 200
+
+ PinchHandler {
+ id: pinchHandler
+ objectName: "pinchHandler"
+ minimumScale: 0.5
+ maximumScale: 2.0
+ minimumRotation: 0.0
+ maximumRotation: 0.0
+ minimumPointCount: 3
+ maximumPointCount: 3
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml
new file mode 100644
index 0000000000..46e9ccca87
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+
+Rectangle {
+ width: 400
+ height: 400
+
+ Rectangle {
+ x: 100
+ y: 100
+ width: 200
+ height: 200
+ rotation: 45
+
+ Rectangle {
+ id: rect
+ scale: 0.5
+ color: "black"
+ anchors.fill: parent
+
+ PinchHandler {
+ objectName: "pinchHandler"
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/qquickpinchhandler.pro b/tests/auto/quick/pointerhandlers/qquickpinchhandler/qquickpinchhandler.pro
new file mode 100644
index 0000000000..7e177d9786
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/qquickpinchhandler.pro
@@ -0,0 +1,16 @@
+CONFIG += testcase
+TARGET = tst_qquickpinchhandler
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qquickpinchhandler.cpp
+OTHER_FILES = \
+ data/pinchproperties.qml \
+ data/threeFingers.qml \
+ data/transformedPinchArea.qml
+
+include (../../../shared/util.pri)
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
+QT += core-private gui-private qml-private quick-private testlib
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp
new file mode 100644
index 0000000000..818863bf86
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp
@@ -0,0 +1,692 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtTest/QSignalSpy>
+#include <QtGui/QStyleHints>
+#include <qpa/qwindowsysteminterface.h>
+#include <private/qquickpinchhandler_p.h>
+#include <QtQuick/private/qquickrectangle_p.h>
+#include <QtQuick/qquickview.h>
+#include <QtQml/qqmlcontext.h>
+#include "../../../shared/util.h"
+#include "../../shared/viewtestutil.h"
+
+class tst_QQuickPinchHandler: public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_QQuickPinchHandler() : device(0) { }
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void pinchProperties();
+ void scale();
+ void scaleThreeFingers();
+ void pan();
+ void retouch();
+ void cancel();
+ void transformedpinchHandler_data();
+ void transformedpinchHandler();
+
+private:
+ QQuickView *createView();
+ QTouchDevice *device;
+};
+void tst_QQuickPinchHandler::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ if (!device) {
+ device = new QTouchDevice;
+ device->setType(QTouchDevice::TouchScreen);
+ QWindowSystemInterface::registerTouchDevice(device);
+ }
+}
+
+void tst_QQuickPinchHandler::cleanupTestCase()
+{
+
+}
+
+static bool withinBounds(qreal lower, qreal num, qreal upper)
+{
+ return num >= lower && num <= upper;
+}
+
+void tst_QQuickPinchHandler::pinchProperties()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("pinchproperties.qml"));
+ window->show();
+ QVERIFY(window->rootObject() != nullptr);
+
+ QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler");
+ QVERIFY(pinchHandler != nullptr);
+
+ // target
+ QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect");
+ QVERIFY(blackRect != nullptr);
+ QCOMPARE(blackRect, pinchHandler->target());
+ QQuickItem *rootItem = qobject_cast<QQuickItem*>(window->rootObject());
+ QVERIFY(rootItem != nullptr);
+ QSignalSpy targetSpy(pinchHandler, SIGNAL(targetChanged()));
+ pinchHandler->setTarget(rootItem);
+ QCOMPARE(targetSpy.count(),1);
+ pinchHandler->setTarget(rootItem);
+ QCOMPARE(targetSpy.count(),1);
+
+ // axis
+ /*
+ QCOMPARE(pinchHandler->axis(), QQuickPinch::XAndYAxis);
+ QSignalSpy axisSpy(pinchHandler, SIGNAL(dragAxisChanged()));
+ pinchHandler->setAxis(QQuickPinch::XAxis);
+ QCOMPARE(pinchHandler->axis(), QQuickPinch::XAxis);
+ QCOMPARE(axisSpy.count(),1);
+ pinchHandler->setAxis(QQuickPinch::XAxis);
+ QCOMPARE(axisSpy.count(),1);
+
+ // minimum and maximum drag properties
+ QSignalSpy xminSpy(pinchHandler, SIGNAL(minimumXChanged()));
+ QSignalSpy xmaxSpy(pinchHandler, SIGNAL(maximumXChanged()));
+ QSignalSpy yminSpy(pinchHandler, SIGNAL(minimumYChanged()));
+ QSignalSpy ymaxSpy(pinchHandler, SIGNAL(maximumYChanged()));
+
+ QCOMPARE(pinchHandler->xmin(), 0.0);
+ QCOMPARE(pinchHandler->xmax(), rootItem->width()-blackRect->width());
+ QCOMPARE(pinchHandler->ymin(), 0.0);
+ QCOMPARE(pinchHandler->ymax(), rootItem->height()-blackRect->height());
+
+ pinchHandler->setXmin(10);
+ pinchHandler->setXmax(10);
+ pinchHandler->setYmin(10);
+ pinchHandler->setYmax(10);
+
+ QCOMPARE(pinchHandler->xmin(), 10.0);
+ QCOMPARE(pinchHandler->xmax(), 10.0);
+ QCOMPARE(pinchHandler->ymin(), 10.0);
+ QCOMPARE(pinchHandler->ymax(), 10.0);
+
+ QCOMPARE(xminSpy.count(),1);
+ QCOMPARE(xmaxSpy.count(),1);
+ QCOMPARE(yminSpy.count(),1);
+ QCOMPARE(ymaxSpy.count(),1);
+
+ pinchHandler->setXmin(10);
+ pinchHandler->setXmax(10);
+ pinchHandler->setYmin(10);
+ pinchHandler->setYmax(10);
+
+ QCOMPARE(xminSpy.count(),1);
+ QCOMPARE(xmaxSpy.count(),1);
+ QCOMPARE(yminSpy.count(),1);
+ QCOMPARE(ymaxSpy.count(),1);
+ */
+
+ // minimum and maximum scale properties
+ QSignalSpy scaleMinSpy(pinchHandler, SIGNAL(minimumScaleChanged()));
+ QSignalSpy scaleMaxSpy(pinchHandler, SIGNAL(maximumScaleChanged()));
+
+ QCOMPARE(pinchHandler->minimumScale(), 1.0);
+ QCOMPARE(pinchHandler->maximumScale(), 4.0);
+
+ pinchHandler->setMinimumScale(0.5);
+ pinchHandler->setMaximumScale(1.5);
+
+ QCOMPARE(pinchHandler->minimumScale(), 0.5);
+ QCOMPARE(pinchHandler->maximumScale(), 1.5);
+
+ QCOMPARE(scaleMinSpy.count(),1);
+ QCOMPARE(scaleMaxSpy.count(),1);
+
+ pinchHandler->setMinimumScale(0.5);
+ pinchHandler->setMaximumScale(1.5);
+
+ QCOMPARE(scaleMinSpy.count(),1);
+ QCOMPARE(scaleMaxSpy.count(),1);
+
+ // minimum and maximum rotation properties
+ QSignalSpy rotMinSpy(pinchHandler, SIGNAL(minimumRotationChanged()));
+ QSignalSpy rotMaxSpy(pinchHandler, SIGNAL(maximumRotationChanged()));
+
+ QCOMPARE(pinchHandler->minimumRotation(), 0.0);
+ QCOMPARE(pinchHandler->maximumRotation(), 90.0);
+
+ pinchHandler->setMinimumRotation(-90.0);
+ pinchHandler->setMaximumRotation(45.0);
+
+ QCOMPARE(pinchHandler->minimumRotation(), -90.0);
+ QCOMPARE(pinchHandler->maximumRotation(), 45.0);
+
+ QCOMPARE(rotMinSpy.count(),1);
+ QCOMPARE(rotMaxSpy.count(),1);
+
+ pinchHandler->setMinimumRotation(-90.0);
+ pinchHandler->setMaximumRotation(45.0);
+
+ QCOMPARE(rotMinSpy.count(),1);
+ QCOMPARE(rotMaxSpy.count(),1);
+}
+
+QTouchEvent::TouchPoint makeTouchPoint(int id, QPoint p, QQuickView *v, QQuickItem *i)
+{
+ QTouchEvent::TouchPoint touchPoint(id);
+ touchPoint.setPos(i->mapFromScene(p));
+ touchPoint.setScreenPos(v->mapToGlobal(p));
+ touchPoint.setScenePos(p);
+ return touchPoint;
+}
+
+void tst_QQuickPinchHandler::scale()
+{
+ QQuickView *window = createView();
+ QScopedPointer<QQuickView> scope(window);
+ window->setSource(testFileUrl("pinchproperties.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ QVERIFY(window->rootObject() != nullptr);
+ qApp->processEvents();
+
+ QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler");
+ QVERIFY(pinchHandler != nullptr);
+
+ QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
+ QVERIFY(root != nullptr);
+
+ // target
+ QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect");
+ QVERIFY(blackRect != nullptr);
+
+ QPoint p0(80, 80);
+ QPoint p1(100, 100);
+ {
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
+ pinchSequence.press(0, p0, window).commit();
+ QQuickTouchUtils::flush(window);
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object. Otherwise if we let it
+ // be destroyed and then start a new sequence, point 0 will default to being
+ // stationary at 0, 0, and pinchHandler will filter out that touchpoint because
+ // it is outside its bounds.
+ pinchSequence.stationary(0).press(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+
+ QPoint pd(10, 10);
+ // move one point until PinchHandler activates
+ for (int pi = 0; pi < 10 && !pinchHandler->active(); ++pi) {
+ p1 += pd;
+ pinchSequence.stationary(0).move(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ }
+ QCOMPARE(pinchHandler->active(), true);
+ QLineF line(p0, p1);
+ const qreal startLength = line.length();
+
+ p1+=pd;
+ pinchSequence.stationary(0).move(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ line.setP2(p1);
+ qreal scale = line.length() / startLength;
+ QVERIFY(qFloatDistance(root->property("scale").toReal(), scale) < 10);
+ QVERIFY(qFloatDistance(blackRect->scale(), scale) < 10);
+
+ p1+=pd;
+ pinchSequence.stationary(0).move(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ line.setP2(p1);
+ scale = line.length() / startLength;
+
+ QVERIFY(qFloatDistance(root->property("scale").toReal(), scale) < 10);
+ QVERIFY(qFloatDistance(blackRect->scale(), scale) < 10);
+
+ QPointF expectedCentroid = p0 + (p1 - p0)/2;
+ QCOMPARE(pinchHandler->centroid().scenePosition(), expectedCentroid);
+ }
+
+ // scale beyond bound
+ p1 += QPoint(20, 20);
+ {
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
+ pinchSequence.stationary(0).move(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ QCOMPARE(blackRect->scale(), qreal(4)); // qquickpinchhandler does not manipulate scale property
+ pinchSequence.release(0, p0, window).release(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ }
+ QCOMPARE(pinchHandler->active(), false);
+}
+
+void tst_QQuickPinchHandler::scaleThreeFingers()
+{
+ QQuickView *window = createView();
+ QScopedPointer<QQuickView> scope(window);
+ window->setSource(testFileUrl("threeFingers.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ QVERIFY(window->rootObject() != nullptr);
+ qApp->processEvents();
+
+ QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler");
+ QVERIFY(pinchHandler != nullptr);
+
+ QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
+ QVERIFY(root != nullptr);
+
+ // target
+ QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect");
+ QVERIFY(blackRect != nullptr);
+
+ // center of blackrect is at 150,150
+ QPoint p0(80, 80);
+ QPoint p1(220, 80);
+ QPoint p2(150, 220);
+ {
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
+ pinchSequence.press(0, p0, window).commit();
+ QQuickTouchUtils::flush(window);
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object. Otherwise if we let it
+ // be destroyed and then start a new sequence, point 0 will default to being
+ // stationary at 0, 0, and pinchHandler will filter out that touchpoint because
+ // it is outside its bounds.
+ pinchSequence.stationary(0).press(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ pinchSequence.stationary(0).stationary(1).press(2, p2, window).commit();
+ QQuickTouchUtils::flush(window);
+ for (int i = 0; i < 5;++i) {
+ p0 += QPoint(-4, -4);
+ p1 += QPoint(+4, -4);
+ p2 += QPoint( 0, +6);
+ pinchSequence.move(0, p0,window).move(1, p1,window).move(2, p2,window).commit();
+ QQuickTouchUtils::flush(window);
+ }
+
+ QCOMPARE(pinchHandler->active(), true);
+ // scale we got was 1.1729088738267854364, but keep some slack
+ QVERIFY(withinBounds(1.163, root->property("scale").toReal(), 1.183));
+ // should not rotate
+ QCOMPARE(root->property("rotation").toReal(), 0.);
+
+ for (int i = 0; i < 5;++i) {
+ p0 += QPoint(-4, -4);
+ p1 += QPoint(+4, -4);
+ p2 += QPoint( 0, +6);
+ pinchSequence.move(0, p0,window).move(1, p1,window).move(2, p2,window).commit();
+ QQuickTouchUtils::flush(window);
+ }
+ // scale we got was 1.4613, but keep some slack
+ QVERIFY(withinBounds(1.361, root->property("scale").toReal(), 1.561));
+
+ // since points were moved symetrically around the y axis, centroid should remain at x:150
+ QCOMPARE(root->property("centroid").value<QQuickHandlerPoint>().scenePosition().x(), 150); // blackrect is at 50,50
+
+ // scale beyond bound, we should reach the maximumScale
+ p0 += QPoint(-40, -40);
+ p1 += QPoint(+40, -40);
+ p2 += QPoint( 0, +60);
+ pinchSequence.move(0, p0,window).move(1, p1,window).move(2, p2,window).commit();
+ QQuickTouchUtils::flush(window);
+
+ QCOMPARE(root->property("scale").toReal(), 2.);
+ pinchSequence.release(0, p0, window).release(1, p1, window).release(2, p2, window).commit();
+ QQuickTouchUtils::flush(window);
+ }
+ QCOMPARE(pinchHandler->active(), false);
+}
+
+void tst_QQuickPinchHandler::pan()
+{
+ QQuickView *window = createView();
+ QScopedPointer<QQuickView> scope(window);
+ window->setSource(testFileUrl("pinchproperties.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ QVERIFY(window->rootObject() != nullptr);
+ qApp->processEvents();
+
+ QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler");
+ QVERIFY(pinchHandler != nullptr);
+
+ QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
+ QVERIFY(root != nullptr);
+
+ // target
+ QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect");
+ QVERIFY(blackRect != nullptr);
+
+ QPoint p0(80, 80);
+ QPoint p1(100, 100);
+ {
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
+ pinchSequence.press(0, p0, window).commit();
+ QQuickTouchUtils::flush(window);
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object.
+ pinchSequence.stationary(0).press(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ QVERIFY(!root->property("pinchActive").toBool());
+ QCOMPARE(root->property("scale").toReal(), -1.0);
+
+ p0 += QPoint(dragThreshold, 0);
+ p1 += QPoint(dragThreshold, 0);
+ pinchSequence.move(0, p0, window).move(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ // movement < dragThreshold: pinchHandler not yet active
+ QVERIFY(!root->property("pinchActive").toBool());
+ QCOMPARE(root->property("scale").toReal(), -1.0);
+
+ // just above the dragThreshold: pinchHandler starts
+ p0 += QPoint(1, 0);
+ p1 += QPoint(1, 0);
+ pinchSequence.move(0, p0, window).move(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ QCOMPARE(pinchHandler->active(), true);
+ QCOMPARE(root->property("scale").toReal(), 1.0);
+
+ // Calculation of the center point is tricky at first:
+ // center point of the two touch points in item coordinates:
+ // scene coordinates: (80, 80) + (dragThreshold, 0), (100, 100) + (dragThreshold, 0)
+ // = ((180+dT)/2, 180/2) = (90+dT, 90)
+ // item coordinates: (scene) - (50, 50) = (40+dT, 40)
+ QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 1, 90));
+ // pan started, but no actual movement registered yet:
+ // blackrect starts at 50,50
+ QCOMPARE(blackRect->x(), 50.0);
+ QCOMPARE(blackRect->y(), 50.0);
+
+ p0 += QPoint(10, 0);
+ p1 += QPoint(10, 0);
+ pinchSequence.move(0, p0, window).move(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 11, 90));
+ QCOMPARE(blackRect->x(), 60.0);
+ QCOMPARE(blackRect->y(), 50.0);
+
+ p0 += QPoint(0, 10);
+ p1 += QPoint(0, 10);
+ pinchSequence.move(0, p0, window).move(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 11, 90 + 10));
+ QCOMPARE(blackRect->x(), 60.0);
+ QCOMPARE(blackRect->y(), 60.0);
+
+ p0 += QPoint(10, 10);
+ p1 += QPoint(10, 10);
+ pinchSequence.move(0, p0, window).move(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ // now the item moved again, thus the center point of the touch is moved in total by (10, 10)
+ QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 21, 90 + 20));
+ QCOMPARE(blackRect->x(), 70.0);
+ QCOMPARE(blackRect->y(), 70.0);
+ }
+
+ // pan x beyond bound
+ p0 += QPoint(100,100);
+ p1 += QPoint(100,100);
+ QTest::touchEvent(window, device).move(0, p0, window).move(1, p1, window);
+ QQuickTouchUtils::flush(window);
+
+ QCOMPARE(blackRect->x(), 140.0);
+ QCOMPARE(blackRect->y(), 170.0);
+
+ QTest::touchEvent(window, device).release(0, p0, window).release(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ QVERIFY(!root->property("pinchActive").toBool());
+}
+
+// test pinchHandler, release one point, touch again to continue pinchHandler
+void tst_QQuickPinchHandler::retouch()
+{
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QQuickView *window = createView();
+ QScopedPointer<QQuickView> scope(window);
+ window->setSource(testFileUrl("pinchproperties.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ QVERIFY(window->rootObject() != nullptr);
+ qApp->processEvents();
+
+ QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler");
+ QVERIFY(pinchHandler != nullptr);
+
+ QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
+ QVERIFY(root != nullptr);
+
+ // target
+ QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect");
+ QVERIFY(blackRect != nullptr);
+
+ QPoint p0(80, 80);
+ QPoint p1(100, 100);
+ {
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
+ pinchSequence.press(0, p0, window).commit();
+ QQuickTouchUtils::flush(window);
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object.
+ pinchSequence.stationary(0).press(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ const QPoint delta(dragThreshold + 1, dragThreshold + 1);
+ p0 -= delta;
+ p1 += delta;
+ pinchSequence.move(0, p0,window).move(1, p1,window).commit();
+ QQuickTouchUtils::flush(window);
+
+ QCOMPARE(root->property("scale").toReal(), 1.0);
+ QCOMPARE(pinchHandler->active(), true);
+
+ p0 -= delta;
+ p1 += delta;
+ pinchSequence.move(0, p0,window).move(1, p1,window).commit();
+ QQuickTouchUtils::flush(window);
+
+ QCOMPARE(pinchHandler->active(), true);
+
+ // accept some slack
+ QVERIFY(withinBounds(1.4, root->property("scale").toReal(), 1.6));
+ QCOMPARE(pinchHandler->centroid().position(), QPointF(40, 40)); // blackrect is at 50,50
+ QVERIFY(withinBounds(1.4, blackRect->scale(), 1.6));
+
+ QCOMPARE(root->property("activeCount").toInt(), 1);
+ QCOMPARE(root->property("deactiveCount").toInt(), 0);
+
+ // Hold down the first finger but release the second one
+ pinchSequence.stationary(0).release(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+
+ QCOMPARE(root->property("activeCount").toInt(), 1);
+ QCOMPARE(root->property("deactiveCount").toInt(), 1);
+
+ // Keep holding down the first finger and re-touch the second one, then move them both
+ pinchSequence.stationary(0).press(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ p0 -= QPoint(10,10);
+ p1 += QPoint(10,10);
+ pinchSequence.move(0, p0, window).move(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+
+ // Lifting and retouching results in onPinchStarted being called again
+ QCOMPARE(root->property("activeCount").toInt(), 2);
+ QCOMPARE(root->property("deactiveCount").toInt(), 1);
+
+ pinchSequence.release(0, p0, window).release(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+
+ QCOMPARE(pinchHandler->active(), false);
+ QCOMPARE(root->property("activeCount").toInt(), 2);
+ QCOMPARE(root->property("deactiveCount").toInt(), 2);
+ }
+}
+
+void tst_QQuickPinchHandler::cancel()
+{
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QQuickView *window = createView();
+ QScopedPointer<QQuickView> scope(window);
+ window->setSource(testFileUrl("pinchproperties.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ QVERIFY(window->rootObject() != nullptr);
+ qApp->processEvents();
+
+ QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler");
+ QVERIFY(pinchHandler != nullptr);
+
+ QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
+ QVERIFY(root != nullptr);
+
+ // target
+ QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect");
+ QVERIFY(blackRect != nullptr);
+
+ QPoint p0(80, 80);
+ QPoint p1(100, 100);
+ {
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
+ pinchSequence.press(0, p0, window).commit();
+ QQuickTouchUtils::flush(window);
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object. Otherwise if we let it
+ // be destroyed and then start a new sequence, point 0 will default to being
+ // stationary at 0, 0, and pinchHandler will filter out that touchpoint because
+ // it is outside its bounds.
+ pinchSequence.stationary(0).press(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ const QPoint delta(dragThreshold + 1, dragThreshold + 1);
+ p0 -= delta;
+ p1 += delta;
+ pinchSequence.move(0, p0,window).move(1, p1,window).commit();
+ QQuickTouchUtils::flush(window);
+
+ QCOMPARE(root->property("scale").toReal(), 1.0);
+ QCOMPARE(pinchHandler->active(), true);
+
+ p0 -= delta;
+ p1 += delta;
+ pinchSequence.move(0, p0,window).move(1, p1,window).commit();
+ QQuickTouchUtils::flush(window);
+
+ QVERIFY(withinBounds(1.4, root->property("scale").toReal(), 1.6));
+ QCOMPARE(pinchHandler->centroid().position(), QPointF(40, 40)); // blackrect is at 50,50
+ QVERIFY(withinBounds(1.4, blackRect->scale(), 1.6));
+
+ QSKIP("cancel is not supported atm");
+
+ QTouchEvent cancelEvent(QEvent::TouchCancel);
+ cancelEvent.setDevice(device);
+ QCoreApplication::sendEvent(window, &cancelEvent);
+ QQuickTouchUtils::flush(window);
+
+ QCOMPARE(root->property("scale").toReal(), 1.0);
+ QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50
+ QCOMPARE(blackRect->scale(), 1.0);
+ QVERIFY(!root->property("pinchActive").toBool());
+ }
+}
+
+void tst_QQuickPinchHandler::transformedpinchHandler_data()
+{
+ QTest::addColumn<QPoint>("p0");
+ QTest::addColumn<QPoint>("p1");
+ QTest::addColumn<bool>("shouldPinch");
+
+ QTest::newRow("checking inner pinchHandler 1")
+ << QPoint(200, 140) << QPoint(200, 260) << true;
+
+ QTest::newRow("checking inner pinchHandler 2")
+ << QPoint(140, 200) << QPoint(200, 140) << true;
+
+ QTest::newRow("checking inner pinchHandler 3")
+ << QPoint(140, 200) << QPoint(260, 200) << true;
+
+ QTest::newRow("checking outer pinchHandler 1")
+ << QPoint(140, 140) << QPoint(260, 260) << false;
+
+ QTest::newRow("checking outer pinchHandler 2")
+ << QPoint(140, 140) << QPoint(200, 200) << false;
+
+ QTest::newRow("checking outer pinchHandler 3")
+ << QPoint(140, 260) << QPoint(260, 260) << false;
+}
+
+void tst_QQuickPinchHandler::transformedpinchHandler()
+{
+ QFETCH(QPoint, p0);
+ QFETCH(QPoint, p1);
+ QFETCH(bool, shouldPinch);
+
+ QQuickView *view = createView();
+ QScopedPointer<QQuickView> scope(view);
+ view->setSource(testFileUrl("transformedPinchHandler.qml"));
+ view->show();
+ QVERIFY(QTest::qWaitForWindowExposed(view));
+ QVERIFY(view->rootObject() != nullptr);
+ qApp->processEvents();
+
+ QQuickPinchHandler *pinchHandler = view->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler");
+ QVERIFY(pinchHandler != nullptr);
+
+ const int threshold = qApp->styleHints()->startDragDistance();
+
+ {
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(view, device);
+ // start pinchHandler
+ pinchSequence.press(0, p0, view).commit();
+ QQuickTouchUtils::flush(view);
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object.
+ pinchSequence.stationary(0).press(1, p1, view).commit();
+ QQuickTouchUtils::flush(view);
+
+ // we move along the line that the two points form.
+ // The distance we move should be above the threshold (threshold * 2 to be safe)
+ QVector2D delta(p1 - p0);
+ delta.normalize();
+ QVector2D movement = delta * (threshold * 2);
+ pinchSequence.stationary(0).move(1, p1 + movement.toPoint(), view).commit();
+ QQuickTouchUtils::flush(view);
+ QCOMPARE(pinchHandler->active(), shouldPinch);
+
+ // release pinchHandler
+ pinchSequence.release(0, p0, view).release(1, p1, view).commit();
+ QQuickTouchUtils::flush(view);
+ QCOMPARE(pinchHandler->active(), false);
+ }
+}
+
+QQuickView *tst_QQuickPinchHandler::createView()
+{
+ QQuickView *window = new QQuickView(0);
+ window->setGeometry(0,0,240,320);
+
+ return window;
+}
+
+QTEST_MAIN(tst_QQuickPinchHandler)
+
+#include "tst_qquickpinchhandler.moc"
diff --git a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
index 2571e4f288..5b7108d96b 100644
--- a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
+++ b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.