| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 | #include <QtTest/QtTest> | 
| 30 | #include <QtTest/QSignalSpy> | 
| 31 | #include <QtGui/QStyleHints> | 
| 32 | #include <qpa/qwindowsysteminterface.h> | 
| 33 | #include <private/qquickpinchhandler_p.h> | 
| 34 | #include <QtQuick/private/qquickrectangle_p.h> | 
| 35 | #include <QtQuick/qquickview.h> | 
| 36 | #include <QtQml/qqmlcontext.h> | 
| 37 | #include "../../../shared/util.h" | 
| 38 | #include "../../shared/viewtestutil.h" | 
| 39 |  | 
| 40 | Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests" ) | 
| 41 |  | 
| 42 | class tst_QQuickPinchHandler: public QQmlDataTest | 
| 43 | { | 
| 44 |     Q_OBJECT | 
| 45 | public: | 
| 46 |     tst_QQuickPinchHandler() : device(0) { } | 
| 47 | private slots: | 
| 48 |     void initTestCase(); | 
| 49 |     void cleanupTestCase(); | 
| 50 |     void pinchProperties(); | 
| 51 |     void scale(); | 
| 52 |     void scaleThreeFingers(); | 
| 53 |     void pan(); | 
| 54 |     void dragAxesEnabled_data(); | 
| 55 |     void dragAxesEnabled(); | 
| 56 |     void retouch(); | 
| 57 |     void cancel(); | 
| 58 |     void transformedpinchHandler_data(); | 
| 59 |     void transformedpinchHandler(); | 
| 60 |  | 
| 61 | private: | 
| 62 |     QQuickView *createView(); | 
| 63 |     QTouchDevice *device; | 
| 64 | }; | 
| 65 | void tst_QQuickPinchHandler::initTestCase() | 
| 66 | { | 
| 67 |     QQmlDataTest::initTestCase(); | 
| 68 |     if (!device) { | 
| 69 |         device = new QTouchDevice; | 
| 70 |         device->setType(QTouchDevice::TouchScreen); | 
| 71 |         QWindowSystemInterface::registerTouchDevice(device); | 
| 72 |     } | 
| 73 | } | 
| 74 |  | 
| 75 | void tst_QQuickPinchHandler::cleanupTestCase() | 
| 76 | { | 
| 77 |  | 
| 78 | } | 
| 79 |  | 
| 80 | static bool withinBounds(qreal lower, qreal num, qreal upper) | 
| 81 | { | 
| 82 |     return num >= lower && num <= upper; | 
| 83 | } | 
| 84 |  | 
| 85 | void tst_QQuickPinchHandler::pinchProperties() | 
| 86 | { | 
| 87 |     QScopedPointer<QQuickView> window(createView()); | 
| 88 |     window->setSource(testFileUrl(fileName: "pinchproperties.qml" )); | 
| 89 |     window->show(); | 
| 90 |     QVERIFY(window->rootObject() != nullptr); | 
| 91 |  | 
| 92 |     QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>(aName: "pinchHandler" ); | 
| 93 |     QVERIFY(pinchHandler != nullptr); | 
| 94 |  | 
| 95 |     // target | 
| 96 |     QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>(aName: "blackrect" ); | 
| 97 |     QVERIFY(blackRect != nullptr); | 
| 98 |     QCOMPARE(blackRect, pinchHandler->target()); | 
| 99 |     QQuickItem *rootItem = qobject_cast<QQuickItem*>(object: window->rootObject()); | 
| 100 |     QVERIFY(rootItem != nullptr); | 
| 101 |     QSignalSpy targetSpy(pinchHandler, SIGNAL(targetChanged())); | 
| 102 |     pinchHandler->setTarget(rootItem); | 
| 103 |     QCOMPARE(targetSpy.count(),1); | 
| 104 |     pinchHandler->setTarget(rootItem); | 
| 105 |     QCOMPARE(targetSpy.count(),1); | 
| 106 |  | 
| 107 |     // axis | 
| 108 |     /* | 
| 109 |     QCOMPARE(pinchHandler->axis(), QQuickPinch::XAndYAxis); | 
| 110 |     QSignalSpy axisSpy(pinchHandler, SIGNAL(dragAxisChanged())); | 
| 111 |     pinchHandler->setAxis(QQuickPinch::XAxis); | 
| 112 |     QCOMPARE(pinchHandler->axis(), QQuickPinch::XAxis); | 
| 113 |     QCOMPARE(axisSpy.count(),1); | 
| 114 |     pinchHandler->setAxis(QQuickPinch::XAxis); | 
| 115 |     QCOMPARE(axisSpy.count(),1); | 
| 116 |  | 
| 117 |     // minimum and maximum drag properties | 
| 118 |     QSignalSpy xminSpy(pinchHandler, SIGNAL(minimumXChanged())); | 
| 119 |     QSignalSpy xmaxSpy(pinchHandler, SIGNAL(maximumXChanged())); | 
| 120 |     QSignalSpy yminSpy(pinchHandler, SIGNAL(minimumYChanged())); | 
| 121 |     QSignalSpy ymaxSpy(pinchHandler, SIGNAL(maximumYChanged())); | 
| 122 |  | 
| 123 |     QCOMPARE(pinchHandler->xmin(), 0.0); | 
| 124 |     QCOMPARE(pinchHandler->xmax(), rootItem->width()-blackRect->width()); | 
| 125 |     QCOMPARE(pinchHandler->ymin(), 0.0); | 
| 126 |     QCOMPARE(pinchHandler->ymax(), rootItem->height()-blackRect->height()); | 
| 127 |  | 
| 128 |     pinchHandler->setXmin(10); | 
| 129 |     pinchHandler->setXmax(10); | 
| 130 |     pinchHandler->setYmin(10); | 
| 131 |     pinchHandler->setYmax(10); | 
| 132 |  | 
| 133 |     QCOMPARE(pinchHandler->xmin(), 10.0); | 
| 134 |     QCOMPARE(pinchHandler->xmax(), 10.0); | 
| 135 |     QCOMPARE(pinchHandler->ymin(), 10.0); | 
| 136 |     QCOMPARE(pinchHandler->ymax(), 10.0); | 
| 137 |  | 
| 138 |     QCOMPARE(xminSpy.count(),1); | 
| 139 |     QCOMPARE(xmaxSpy.count(),1); | 
| 140 |     QCOMPARE(yminSpy.count(),1); | 
| 141 |     QCOMPARE(ymaxSpy.count(),1); | 
| 142 |  | 
| 143 |     pinchHandler->setXmin(10); | 
| 144 |     pinchHandler->setXmax(10); | 
| 145 |     pinchHandler->setYmin(10); | 
| 146 |     pinchHandler->setYmax(10); | 
| 147 |  | 
| 148 |     QCOMPARE(xminSpy.count(),1); | 
| 149 |     QCOMPARE(xmaxSpy.count(),1); | 
| 150 |     QCOMPARE(yminSpy.count(),1); | 
| 151 |     QCOMPARE(ymaxSpy.count(),1); | 
| 152 |     */ | 
| 153 |  | 
| 154 |     // minimum and maximum scale properties | 
| 155 |     QSignalSpy scaleMinSpy(pinchHandler, SIGNAL(minimumScaleChanged())); | 
| 156 |     QSignalSpy scaleMaxSpy(pinchHandler, SIGNAL(maximumScaleChanged())); | 
| 157 |  | 
| 158 |     QCOMPARE(pinchHandler->minimumScale(), 1.0); | 
| 159 |     QCOMPARE(pinchHandler->maximumScale(), 4.0); | 
| 160 |  | 
| 161 |     pinchHandler->setMinimumScale(0.5); | 
| 162 |     pinchHandler->setMaximumScale(1.5); | 
| 163 |  | 
| 164 |     QCOMPARE(pinchHandler->minimumScale(), 0.5); | 
| 165 |     QCOMPARE(pinchHandler->maximumScale(), 1.5); | 
| 166 |  | 
| 167 |     QCOMPARE(scaleMinSpy.count(),1); | 
| 168 |     QCOMPARE(scaleMaxSpy.count(),1); | 
| 169 |  | 
| 170 |     pinchHandler->setMinimumScale(0.5); | 
| 171 |     pinchHandler->setMaximumScale(1.5); | 
| 172 |  | 
| 173 |     QCOMPARE(scaleMinSpy.count(),1); | 
| 174 |     QCOMPARE(scaleMaxSpy.count(),1); | 
| 175 |  | 
| 176 |     // minimum and maximum rotation properties | 
| 177 |     QSignalSpy rotMinSpy(pinchHandler, SIGNAL(minimumRotationChanged())); | 
| 178 |     QSignalSpy rotMaxSpy(pinchHandler, SIGNAL(maximumRotationChanged())); | 
| 179 |  | 
| 180 |     QCOMPARE(pinchHandler->minimumRotation(), 0.0); | 
| 181 |     QCOMPARE(pinchHandler->maximumRotation(), 90.0); | 
| 182 |  | 
| 183 |     pinchHandler->setMinimumRotation(-90.0); | 
| 184 |     pinchHandler->setMaximumRotation(45.0); | 
| 185 |  | 
| 186 |     QCOMPARE(pinchHandler->minimumRotation(), -90.0); | 
| 187 |     QCOMPARE(pinchHandler->maximumRotation(), 45.0); | 
| 188 |  | 
| 189 |     QCOMPARE(rotMinSpy.count(),1); | 
| 190 |     QCOMPARE(rotMaxSpy.count(),1); | 
| 191 |  | 
| 192 |     pinchHandler->setMinimumRotation(-90.0); | 
| 193 |     pinchHandler->setMaximumRotation(45.0); | 
| 194 |  | 
| 195 |     QCOMPARE(rotMinSpy.count(),1); | 
| 196 |     QCOMPARE(rotMaxSpy.count(),1); | 
| 197 | } | 
| 198 |  | 
| 199 | QTouchEvent::TouchPoint makeTouchPoint(int id, QPoint p, QQuickView *v, QQuickItem *i) | 
| 200 | { | 
| 201 |     QTouchEvent::TouchPoint touchPoint(id); | 
| 202 |     touchPoint.setPos(i->mapFromScene(point: p)); | 
| 203 |     touchPoint.setScreenPos(v->mapToGlobal(pos: p)); | 
| 204 |     touchPoint.setScenePos(p); | 
| 205 |     return touchPoint; | 
| 206 | } | 
| 207 |  | 
| 208 | void tst_QQuickPinchHandler::scale() | 
| 209 | { | 
| 210 |     QQuickView *window = createView(); | 
| 211 |     QScopedPointer<QQuickView> scope(window); | 
| 212 |     window->setSource(testFileUrl(fileName: "pinchproperties.qml" )); | 
| 213 |     window->show(); | 
| 214 |     QVERIFY(QTest::qWaitForWindowExposed(window)); | 
| 215 |     QVERIFY(window->rootObject() != nullptr); | 
| 216 |     qApp->processEvents(); | 
| 217 |  | 
| 218 |     QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>(aName: "pinchHandler" ); | 
| 219 |     QVERIFY(pinchHandler != nullptr); | 
| 220 |     QSignalSpy grabChangedSpy(pinchHandler, SIGNAL(grabChanged(QQuickEventPoint::GrabTransition, QQuickEventPoint*))); | 
| 221 |  | 
| 222 |     QQuickItem *root = qobject_cast<QQuickItem*>(object: window->rootObject()); | 
| 223 |     QVERIFY(root != nullptr); | 
| 224 |  | 
| 225 |     // target | 
| 226 |     QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>(aName: "blackrect" ); | 
| 227 |     QVERIFY(blackRect != nullptr); | 
| 228 |  | 
| 229 |     QPoint p0(80, 80); | 
| 230 |     QPoint p1(100, 100); | 
| 231 |     { | 
| 232 |         QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); | 
| 233 |         pinchSequence.press(touchId: 0, pt: p0, window).commit(); | 
| 234 |         QQuickTouchUtils::flush(window); | 
| 235 |         // In order for the stationary point to remember its previous position, | 
| 236 |         // we have to reuse the same pinchSequence object.  Otherwise if we let it | 
| 237 |         // be destroyed and then start a new sequence, point 0 will default to being | 
| 238 |         // stationary at 0, 0, and pinchHandler will filter out that touchpoint because | 
| 239 |         // it is outside its bounds. | 
| 240 |         pinchSequence.stationary(touchId: 0).press(touchId: 1, pt: p1, window).commit(); | 
| 241 |         QQuickTouchUtils::flush(window); | 
| 242 |         QTRY_COMPARE(grabChangedSpy.count(), 1); // passive grab | 
| 243 |  | 
| 244 |         QPoint pd(10, 10); | 
| 245 |         // move one point until PinchHandler activates | 
| 246 |         for (int pi = 0; pi < 10 && !pinchHandler->active(); ++pi) { | 
| 247 |             p1 += pd; | 
| 248 |             pinchSequence.stationary(touchId: 0).move(touchId: 1, pt: p1, window).commit(); | 
| 249 |             QQuickTouchUtils::flush(window); | 
| 250 |         } | 
| 251 |         QCOMPARE(pinchHandler->active(), true); | 
| 252 |         // first point got a passive grab; both points got exclusive grabs | 
| 253 |         QCOMPARE(grabChangedSpy.count(), 3); | 
| 254 |         QLineF line(p0, p1); | 
| 255 |         const qreal startLength = line.length(); | 
| 256 |  | 
| 257 |         p1+=pd; | 
| 258 |         pinchSequence.stationary(touchId: 0).move(touchId: 1, pt: p1, window).commit(); | 
| 259 |         QQuickTouchUtils::flush(window); | 
| 260 |         line.setP2(p1); | 
| 261 |         qreal scale = line.length() / startLength; | 
| 262 |         QVERIFY(qFloatDistance(root->property("scale" ).toReal(), scale) < 10); | 
| 263 |         QVERIFY(qFloatDistance(blackRect->scale(), scale) < 10); | 
| 264 |  | 
| 265 |         p1+=pd; | 
| 266 |         pinchSequence.stationary(touchId: 0).move(touchId: 1, pt: p1, window).commit(); | 
| 267 |         QQuickTouchUtils::flush(window); | 
| 268 |         line.setP2(p1); | 
| 269 |         scale = line.length() / startLength; | 
| 270 |  | 
| 271 |         QVERIFY(qFloatDistance(root->property("scale" ).toReal(), scale) < 10); | 
| 272 |         QVERIFY(qFloatDistance(blackRect->scale(), scale) < 10); | 
| 273 |  | 
| 274 |         QPointF expectedCentroid = p0 + (p1 - p0)/2; | 
| 275 |         QCOMPARE(pinchHandler->centroid().scenePosition(), expectedCentroid); | 
| 276 |     } | 
| 277 |  | 
| 278 |     // scale beyond bound | 
| 279 |     p1 += QPoint(20, 20); | 
| 280 |     { | 
| 281 |         QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); | 
| 282 |         pinchSequence.stationary(touchId: 0).move(touchId: 1, pt: p1, window).commit(); | 
| 283 |         QQuickTouchUtils::flush(window); | 
| 284 |         QCOMPARE(blackRect->scale(), qreal(4));    // qquickpinchhandler does not manipulate scale property | 
| 285 |         pinchSequence.release(touchId: 0, pt: p0, window).release(touchId: 1, pt: p1, window).commit(); | 
| 286 |         QQuickTouchUtils::flush(window); | 
| 287 |     } | 
| 288 |     QCOMPARE(pinchHandler->active(), false); | 
| 289 | } | 
| 290 |  | 
| 291 | void tst_QQuickPinchHandler::scaleThreeFingers() | 
| 292 | { | 
| 293 |     QQuickView *window = createView(); | 
| 294 |     QScopedPointer<QQuickView> scope(window); | 
| 295 |     window->setSource(testFileUrl(fileName: "threeFingers.qml" )); | 
| 296 |     window->show(); | 
| 297 |     QVERIFY(QTest::qWaitForWindowExposed(window)); | 
| 298 |     QVERIFY(window->rootObject() != nullptr); | 
| 299 |     qApp->processEvents(); | 
| 300 |  | 
| 301 |     QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>(aName: "pinchHandler" ); | 
| 302 |     QVERIFY(pinchHandler != nullptr); | 
| 303 |  | 
| 304 |     QQuickItem *root = qobject_cast<QQuickItem*>(object: window->rootObject()); | 
| 305 |     QVERIFY(root != nullptr); | 
| 306 |  | 
| 307 |     // target | 
| 308 |     QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>(aName: "blackrect" ); | 
| 309 |     QVERIFY(blackRect != nullptr); | 
| 310 |  | 
| 311 |     // center of blackrect is at 150,150 | 
| 312 |     QPoint p0(80, 80); | 
| 313 |     QPoint p1(220, 80); | 
| 314 |     QPoint p2(150, 220); | 
| 315 |     { | 
| 316 |         QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); | 
| 317 |         pinchSequence.press(touchId: 0, pt: p0, window).commit(); | 
| 318 |         QQuickTouchUtils::flush(window); | 
| 319 |         // In order for the stationary point to remember its previous position, | 
| 320 |         // we have to reuse the same pinchSequence object.  Otherwise if we let it | 
| 321 |         // be destroyed and then start a new sequence, point 0 will default to being | 
| 322 |         // stationary at 0, 0, and pinchHandler will filter out that touchpoint because | 
| 323 |         // it is outside its bounds. | 
| 324 |         pinchSequence.stationary(touchId: 0).press(touchId: 1, pt: p1, window).commit(); | 
| 325 |         QQuickTouchUtils::flush(window); | 
| 326 |         pinchSequence.stationary(touchId: 0).stationary(touchId: 1).press(touchId: 2, pt: p2, window).commit(); | 
| 327 |         QQuickTouchUtils::flush(window); | 
| 328 |         for (int i = 0; i < 5;++i) { | 
| 329 |             p0 += QPoint(-4, -4); | 
| 330 |             p1 += QPoint(+4, -4); | 
| 331 |             p2 += QPoint( 0, +6); | 
| 332 |             pinchSequence.move(touchId: 0, pt: p0,window).move(touchId: 1, pt: p1,window).move(touchId: 2, pt: p2,window).commit(); | 
| 333 |             QQuickTouchUtils::flush(window); | 
| 334 |         } | 
| 335 |  | 
| 336 |         QCOMPARE(pinchHandler->active(), true); | 
| 337 |         // scale we got was 1.1729088738267854364, but keep some slack | 
| 338 |         QVERIFY(withinBounds(1.163, root->property("scale" ).toReal(), 1.183)); | 
| 339 |         // should not rotate | 
| 340 |         QCOMPARE(root->property("rotation" ).toReal(), 0.); | 
| 341 |  | 
| 342 |         for (int i = 0; i < 5;++i) { | 
| 343 |             p0 += QPoint(-4, -4); | 
| 344 |             p1 += QPoint(+4, -4); | 
| 345 |             p2 += QPoint( 0, +6); | 
| 346 |             pinchSequence.move(touchId: 0, pt: p0,window).move(touchId: 1, pt: p1,window).move(touchId: 2, pt: p2,window).commit(); | 
| 347 |             QQuickTouchUtils::flush(window); | 
| 348 |         } | 
| 349 |         // scale we got was 1.4613, but keep some slack | 
| 350 |         QVERIFY(withinBounds(1.361, root->property("scale" ).toReal(), 1.561)); | 
| 351 |  | 
| 352 |         // since points were moved symetrically around the y axis, centroid should remain at x:150 | 
| 353 |         QCOMPARE(root->property("centroid" ).value<QQuickHandlerPoint>().scenePosition().x(), 150); // blackrect is at 50,50 | 
| 354 |  | 
| 355 |         // scale beyond bound, we should reach the maximumScale | 
| 356 |         p0 += QPoint(-40, -40); | 
| 357 |         p1 += QPoint(+40, -40); | 
| 358 |         p2 += QPoint(  0, +60); | 
| 359 |         pinchSequence.move(touchId: 0, pt: p0,window).move(touchId: 1, pt: p1,window).move(touchId: 2, pt: p2,window).commit(); | 
| 360 |         QQuickTouchUtils::flush(window); | 
| 361 |  | 
| 362 |         QCOMPARE(root->property("scale" ).toReal(), 2.); | 
| 363 |         pinchSequence.release(touchId: 0, pt: p0, window).release(touchId: 1, pt: p1, window).release(touchId: 2, pt: p2, window).commit(); | 
| 364 |         QQuickTouchUtils::flush(window); | 
| 365 |     } | 
| 366 |     QCOMPARE(pinchHandler->active(), false); | 
| 367 | } | 
| 368 |  | 
| 369 | void tst_QQuickPinchHandler::pan() | 
| 370 | { | 
| 371 |     QQuickView *window = createView(); | 
| 372 |     QScopedPointer<QQuickView> scope(window); | 
| 373 |     window->setSource(testFileUrl(fileName: "pinchproperties.qml" )); | 
| 374 |     window->show(); | 
| 375 |     QVERIFY(QTest::qWaitForWindowExposed(window)); | 
| 376 |     QVERIFY(window->rootObject() != nullptr); | 
| 377 |     qApp->processEvents(); | 
| 378 |  | 
| 379 |     QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>(aName: "pinchHandler" ); | 
| 380 |     QVERIFY(pinchHandler != nullptr); | 
| 381 |  | 
| 382 |     QQuickItem *root = qobject_cast<QQuickItem*>(object: window->rootObject()); | 
| 383 |     QVERIFY(root != nullptr); | 
| 384 |  | 
| 385 |     // target | 
| 386 |     QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>(aName: "blackrect" ); | 
| 387 |     QVERIFY(blackRect != nullptr); | 
| 388 |  | 
| 389 |     QPoint p0(80, 80); | 
| 390 |     QPoint p1(100, 100); | 
| 391 |     { | 
| 392 |         const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); | 
| 393 |         QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); | 
| 394 |         pinchSequence.press(touchId: 0, pt: p0, window).commit(); | 
| 395 |         QQuickTouchUtils::flush(window); | 
| 396 |         // In order for the stationary point to remember its previous position, | 
| 397 |         // we have to reuse the same pinchSequence object. | 
| 398 |         pinchSequence.stationary(touchId: 0).press(touchId: 1, pt: p1, window).commit(); | 
| 399 |         QQuickTouchUtils::flush(window); | 
| 400 |         QVERIFY(!root->property("pinchActive" ).toBool()); | 
| 401 |         QCOMPARE(root->property("scale" ).toReal(), -1.0); | 
| 402 |  | 
| 403 |         p0 += QPoint(dragThreshold, 0); | 
| 404 |         p1 += QPoint(dragThreshold, 0); | 
| 405 |         pinchSequence.move(touchId: 0, pt: p0, window).move(touchId: 1, pt: p1, window).commit(); | 
| 406 |         QQuickTouchUtils::flush(window); | 
| 407 |         // movement < dragThreshold: pinchHandler not yet active | 
| 408 |         QVERIFY(!root->property("pinchActive" ).toBool()); | 
| 409 |         QCOMPARE(root->property("scale" ).toReal(), -1.0); | 
| 410 |  | 
| 411 |         // just above the dragThreshold: pinchHandler starts | 
| 412 |         p0 += QPoint(1, 0); | 
| 413 |         p1 += QPoint(1, 0); | 
| 414 |         pinchSequence.move(touchId: 0, pt: p0, window).move(touchId: 1, pt: p1, window).commit(); | 
| 415 |         QQuickTouchUtils::flush(window); | 
| 416 |         QCOMPARE(pinchHandler->active(), true); | 
| 417 |         QCOMPARE(root->property("scale" ).toReal(), 1.0); | 
| 418 |  | 
| 419 |         // Calculation of the center point is tricky at first: | 
| 420 |         // center point of the two touch points in item coordinates: | 
| 421 |         // scene coordinates: (80, 80) + (dragThreshold, 0), (100, 100) + (dragThreshold, 0) | 
| 422 |         //                    = ((180+dT)/2, 180/2) = (90+dT, 90) | 
| 423 |         // item  coordinates: (scene) - (50, 50) = (40+dT, 40) | 
| 424 |         QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 1, 90)); | 
| 425 |         // pan started, but no actual movement registered yet: | 
| 426 |         // blackrect starts at 50,50 | 
| 427 |         QCOMPARE(blackRect->x(), 50.0); | 
| 428 |         QCOMPARE(blackRect->y(), 50.0); | 
| 429 |  | 
| 430 |         p0 += QPoint(10, 0); | 
| 431 |         p1 += QPoint(10, 0); | 
| 432 |         pinchSequence.move(touchId: 0, pt: p0, window).move(touchId: 1, pt: p1, window).commit(); | 
| 433 |         QQuickTouchUtils::flush(window); | 
| 434 |         QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 11, 90)); | 
| 435 |         QCOMPARE(blackRect->x(), 60.0); | 
| 436 |         QCOMPARE(blackRect->y(), 50.0); | 
| 437 |  | 
| 438 |         p0 += QPoint(0, 10); | 
| 439 |         p1 += QPoint(0, 10); | 
| 440 |         pinchSequence.move(touchId: 0, pt: p0, window).move(touchId: 1, pt: p1, window).commit(); | 
| 441 |         QQuickTouchUtils::flush(window); | 
| 442 |         QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 11, 90 + 10)); | 
| 443 |         QCOMPARE(blackRect->x(), 60.0); | 
| 444 |         QCOMPARE(blackRect->y(), 60.0); | 
| 445 |  | 
| 446 |         p0 += QPoint(10, 10); | 
| 447 |         p1 += QPoint(10, 10); | 
| 448 |         pinchSequence.move(touchId: 0, pt: p0, window).move(touchId: 1, pt: p1, window).commit(); | 
| 449 |         QQuickTouchUtils::flush(window); | 
| 450 |         // now the item moved again, thus the center point of the touch is moved in total by (10, 10) | 
| 451 |         QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 21, 90 + 20)); | 
| 452 |         QCOMPARE(blackRect->x(), 70.0); | 
| 453 |         QCOMPARE(blackRect->y(), 70.0); | 
| 454 |     } | 
| 455 |  | 
| 456 |     // pan x beyond bound | 
| 457 |     p0 += QPoint(100,100); | 
| 458 |     p1 += QPoint(100,100); | 
| 459 |     QTest::touchEvent(window, device).move(touchId: 0, pt: p0, window).move(touchId: 1, pt: p1, window); | 
| 460 |     QQuickTouchUtils::flush(window); | 
| 461 |  | 
| 462 |     QCOMPARE(blackRect->x(), 140.0); | 
| 463 |     QCOMPARE(blackRect->y(), 170.0); | 
| 464 |  | 
| 465 |     QTest::touchEvent(window, device).release(touchId: 0, pt: p0, window).release(touchId: 1, pt: p1, window); | 
| 466 |     QQuickTouchUtils::flush(window); | 
| 467 |     QVERIFY(!root->property("pinchActive" ).toBool()); | 
| 468 | } | 
| 469 |  | 
| 470 | void tst_QQuickPinchHandler::dragAxesEnabled_data() | 
| 471 | { | 
| 472 |     QTest::addColumn<bool>(name: "xEnabled" ); | 
| 473 |     QTest::addColumn<bool>(name: "yEnabled" ); | 
| 474 |  | 
| 475 |     QTest::newRow(dataTag: "both enabled" ) << true << true; | 
| 476 |     QTest::newRow(dataTag: "x enabled" ) << true << false; | 
| 477 |     QTest::newRow(dataTag: "y enabled" ) << false << true; | 
| 478 |     QTest::newRow(dataTag: "both disabled" ) << false << false; | 
| 479 | } | 
| 480 |  | 
| 481 | void tst_QQuickPinchHandler::dragAxesEnabled() | 
| 482 | { | 
| 483 |     QQuickView *window = createView(); | 
| 484 |     QScopedPointer<QQuickView> scope(window); | 
| 485 |     window->setSource(testFileUrl(fileName: "pinchproperties.qml" )); | 
| 486 |     window->show(); | 
| 487 |     QVERIFY(QTest::qWaitForWindowExposed(window)); | 
| 488 |     QVERIFY(window->rootObject() != nullptr); | 
| 489 |     QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>(aName: "blackrect" ); | 
| 490 |     QVERIFY(blackRect != nullptr); | 
| 491 |     QQuickPinchHandler *pinchHandler = blackRect->findChild<QQuickPinchHandler*>(); | 
| 492 |     QVERIFY(pinchHandler != nullptr); | 
| 493 |  | 
| 494 |     QFETCH(bool, xEnabled); | 
| 495 |     QFETCH(bool, yEnabled); | 
| 496 |     const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); | 
| 497 |     pinchHandler->xAxis()->setEnabled(xEnabled); | 
| 498 |     pinchHandler->yAxis()->setEnabled(yEnabled); | 
| 499 |     QPoint c = blackRect->mapToScene(point: blackRect->clipRect().center()).toPoint(); | 
| 500 |     QPoint p0 = c - QPoint(0, dragThreshold); | 
| 501 |     QPoint p1 = c + QPoint(0, dragThreshold); | 
| 502 |     QPoint blackRectPos = blackRect->position().toPoint(); | 
| 503 |  | 
| 504 |     // press two points, one above the rectangle's center and one below | 
| 505 |     QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); | 
| 506 |     pinchSequence.press(touchId: 0, pt: p0, window).press(touchId: 1, pt: p1, window).commit(); | 
| 507 |     QQuickTouchUtils::flush(window); | 
| 508 |  | 
| 509 |     // expand the pinch vertically | 
| 510 |     p0 -= QPoint(0, dragThreshold); | 
| 511 |     p1 += QPoint(0, dragThreshold); | 
| 512 |     pinchSequence.move(touchId: 0, pt: p0, window).move(touchId: 1, pt: p1, window).commit(); | 
| 513 |     for (int pi = 0; pi < 4; ++pi) { | 
| 514 |         p0 -= QPoint(0, dragThreshold); | 
| 515 |         p1 += QPoint(0, dragThreshold); | 
| 516 |         pinchSequence.move(touchId: 0, pt: p0, window).move(touchId: 1, pt: p1, window).commit(); | 
| 517 |         QQuickTouchUtils::flush(window); | 
| 518 |         qCDebug(lcPointerTests) << pi << "active"  << pinchHandler->active() << "pts"  << p0 << p1 | 
| 519 |                                 << "centroid"  << pinchHandler->centroid().scenePosition() | 
| 520 |                                 << "rect pos"  << blackRect->position() << "scale"  << blackRect->scale(); | 
| 521 |     } | 
| 522 |     QCOMPARE(pinchHandler->active(), true); | 
| 523 |     QVERIFY(blackRect->scale() >= 2.0); | 
| 524 |     // drag started, but we only did scaling without any translation | 
| 525 |     QCOMPARE(pinchHandler->centroid().scenePosition().toPoint(), c); | 
| 526 |     QCOMPARE(blackRect->position().toPoint().x(), blackRectPos.x()); | 
| 527 |     QCOMPARE(blackRect->position().toPoint().y(), blackRectPos.y()); | 
| 528 |  | 
| 529 |     // drag diagonally | 
| 530 |     p0 += QPoint(150, 150); | 
| 531 |     p1 += QPoint(150, 150); | 
| 532 |     pinchSequence.move(touchId: 0, pt: p0, window).move(touchId: 1, pt: p1, window).commit(); | 
| 533 |     QQuickTouchUtils::flush(window); | 
| 534 |     // the target should move if the xAxis is enabled, or stay in place if not | 
| 535 |     qCDebug(lcPointerTests) << "after diagonal drag: pts"  << p0 << p1 | 
| 536 |                             << "centroid"  << pinchHandler->centroid().scenePosition() | 
| 537 |                             << "rect pos"  << blackRect->position() << "scale"  << blackRect->scale(); | 
| 538 |     QCOMPARE(pinchHandler->centroid().scenePosition().toPoint(), QPoint(250, 250)); | 
| 539 |     QCOMPARE(blackRect->position().toPoint().x(), xEnabled ? 140 : blackRectPos.x()); // because of xAxis.maximum | 
| 540 |     QCOMPARE(blackRect->position().toPoint().y(), yEnabled ? 170 : blackRectPos.y()); // because of yAxis.maximum | 
| 541 |  | 
| 542 |     QTest::touchEvent(window, device).release(touchId: 0, pt: p0, window).release(touchId: 1, pt: p1, window); | 
| 543 |     QQuickTouchUtils::flush(window); | 
| 544 | } | 
| 545 |  | 
| 546 | // test pinchHandler, release one point, touch again to continue pinchHandler | 
| 547 | void tst_QQuickPinchHandler::retouch() | 
| 548 | { | 
| 549 |     const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); | 
| 550 |     QQuickView *window = createView(); | 
| 551 |     QScopedPointer<QQuickView> scope(window); | 
| 552 |     window->setSource(testFileUrl(fileName: "pinchproperties.qml" )); | 
| 553 |     window->show(); | 
| 554 |     QVERIFY(QTest::qWaitForWindowExposed(window)); | 
| 555 |     QVERIFY(window->rootObject() != nullptr); | 
| 556 |     qApp->processEvents(); | 
| 557 |  | 
| 558 |     QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>(aName: "pinchHandler" ); | 
| 559 |     QVERIFY(pinchHandler != nullptr); | 
| 560 |  | 
| 561 |     QQuickItem *root = qobject_cast<QQuickItem*>(object: window->rootObject()); | 
| 562 |     QVERIFY(root != nullptr); | 
| 563 |  | 
| 564 |     // target | 
| 565 |     QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>(aName: "blackrect" ); | 
| 566 |     QVERIFY(blackRect != nullptr); | 
| 567 |  | 
| 568 |     QPoint p0(80, 80); | 
| 569 |     QPoint p1(100, 100); | 
| 570 |     { | 
| 571 |         QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); | 
| 572 |         pinchSequence.press(touchId: 0, pt: p0, window).commit(); | 
| 573 |         QQuickTouchUtils::flush(window); | 
| 574 |         // In order for the stationary point to remember its previous position, | 
| 575 |         // we have to reuse the same pinchSequence object. | 
| 576 |         pinchSequence.stationary(touchId: 0).press(touchId: 1, pt: p1, window).commit(); | 
| 577 |         QQuickTouchUtils::flush(window); | 
| 578 |         const QPoint delta(dragThreshold + 1, dragThreshold + 1); | 
| 579 |         p0 -= delta; | 
| 580 |         p1 += delta; | 
| 581 |         pinchSequence.move(touchId: 0, pt: p0,window).move(touchId: 1, pt: p1,window).commit(); | 
| 582 |         QQuickTouchUtils::flush(window); | 
| 583 |  | 
| 584 |         QCOMPARE(root->property("scale" ).toReal(), 1.0); | 
| 585 |         QCOMPARE(pinchHandler->active(), true); | 
| 586 |  | 
| 587 |         p0 -= delta; | 
| 588 |         p1 += delta; | 
| 589 |         pinchSequence.move(touchId: 0, pt: p0,window).move(touchId: 1, pt: p1,window).commit(); | 
| 590 |         QQuickTouchUtils::flush(window); | 
| 591 |  | 
| 592 |         QCOMPARE(pinchHandler->active(), true); | 
| 593 |  | 
| 594 |         // accept some slack | 
| 595 |         QVERIFY(withinBounds(1.4, root->property("scale" ).toReal(), 1.6)); | 
| 596 |         QCOMPARE(pinchHandler->centroid().position(), QPointF(40, 40)); // blackrect is at 50,50 | 
| 597 |         QVERIFY(withinBounds(1.4, blackRect->scale(), 1.6)); | 
| 598 |  | 
| 599 |         QCOMPARE(root->property("activeCount" ).toInt(), 1); | 
| 600 |         QCOMPARE(root->property("deactiveCount" ).toInt(), 0); | 
| 601 |  | 
| 602 |         // Hold down the first finger but release the second one | 
| 603 |         pinchSequence.stationary(touchId: 0).release(touchId: 1, pt: p1, window).commit(); | 
| 604 |         QQuickTouchUtils::flush(window); | 
| 605 |  | 
| 606 |         QCOMPARE(root->property("activeCount" ).toInt(), 1); | 
| 607 |         QCOMPARE(root->property("deactiveCount" ).toInt(), 1); | 
| 608 |  | 
| 609 |         // Keep holding down the first finger and re-touch the second one, then move them both | 
| 610 |         pinchSequence.stationary(touchId: 0).press(touchId: 1, pt: p1, window).commit(); | 
| 611 |         QQuickTouchUtils::flush(window); | 
| 612 |         p0 -= QPoint(10,10); | 
| 613 |         p1 += QPoint(10,10); | 
| 614 |         pinchSequence.move(touchId: 0, pt: p0, window).move(touchId: 1, pt: p1, window).commit(); | 
| 615 |         QQuickTouchUtils::flush(window); | 
| 616 |  | 
| 617 |         // Lifting and retouching results in onPinchStarted being called again | 
| 618 |         QCOMPARE(root->property("activeCount" ).toInt(), 2); | 
| 619 |         QCOMPARE(root->property("deactiveCount" ).toInt(), 1); | 
| 620 |  | 
| 621 |         pinchSequence.release(touchId: 0, pt: p0, window).release(touchId: 1, pt: p1, window).commit(); | 
| 622 |         QQuickTouchUtils::flush(window); | 
| 623 |  | 
| 624 |         QCOMPARE(pinchHandler->active(), false); | 
| 625 |         QCOMPARE(root->property("activeCount" ).toInt(), 2); | 
| 626 |         QCOMPARE(root->property("deactiveCount" ).toInt(), 2); | 
| 627 |     } | 
| 628 | } | 
| 629 |  | 
| 630 | void tst_QQuickPinchHandler::cancel() | 
| 631 | { | 
| 632 |     const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); | 
| 633 |     QQuickView *window = createView(); | 
| 634 |     QScopedPointer<QQuickView> scope(window); | 
| 635 |     window->setSource(testFileUrl(fileName: "pinchproperties.qml" )); | 
| 636 |     window->show(); | 
| 637 |     QVERIFY(QTest::qWaitForWindowExposed(window)); | 
| 638 |     QVERIFY(window->rootObject() != nullptr); | 
| 639 |     qApp->processEvents(); | 
| 640 |  | 
| 641 |     QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>(aName: "pinchHandler" ); | 
| 642 |     QVERIFY(pinchHandler != nullptr); | 
| 643 |  | 
| 644 |     QQuickItem *root = qobject_cast<QQuickItem*>(object: window->rootObject()); | 
| 645 |     QVERIFY(root != nullptr); | 
| 646 |  | 
| 647 |     // target | 
| 648 |     QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>(aName: "blackrect" ); | 
| 649 |     QVERIFY(blackRect != nullptr); | 
| 650 |  | 
| 651 |     QPoint p0(80, 80); | 
| 652 |     QPoint p1(100, 100); | 
| 653 |     { | 
| 654 |         QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); | 
| 655 |         pinchSequence.press(touchId: 0, pt: p0, window).commit(); | 
| 656 |         QQuickTouchUtils::flush(window); | 
| 657 |         // In order for the stationary point to remember its previous position, | 
| 658 |         // we have to reuse the same pinchSequence object.  Otherwise if we let it | 
| 659 |         // be destroyed and then start a new sequence, point 0 will default to being | 
| 660 |         // stationary at 0, 0, and pinchHandler will filter out that touchpoint because | 
| 661 |         // it is outside its bounds. | 
| 662 |         pinchSequence.stationary(touchId: 0).press(touchId: 1, pt: p1, window).commit(); | 
| 663 |         QQuickTouchUtils::flush(window); | 
| 664 |         const QPoint delta(dragThreshold + 1, dragThreshold + 1); | 
| 665 |         p0 -= delta; | 
| 666 |         p1 += delta; | 
| 667 |         pinchSequence.move(touchId: 0, pt: p0,window).move(touchId: 1, pt: p1,window).commit(); | 
| 668 |         QQuickTouchUtils::flush(window); | 
| 669 |  | 
| 670 |         QCOMPARE(root->property("scale" ).toReal(), 1.0); | 
| 671 |         QCOMPARE(pinchHandler->active(), true); | 
| 672 |  | 
| 673 |         p0 -= delta; | 
| 674 |         p1 += delta; | 
| 675 |         pinchSequence.move(touchId: 0, pt: p0,window).move(touchId: 1, pt: p1,window).commit(); | 
| 676 |         QQuickTouchUtils::flush(window); | 
| 677 |  | 
| 678 |         QVERIFY(withinBounds(1.4, root->property("scale" ).toReal(), 1.6)); | 
| 679 |         QCOMPARE(pinchHandler->centroid().position(), QPointF(40, 40)); // blackrect is at 50,50 | 
| 680 |         QVERIFY(withinBounds(1.4, blackRect->scale(), 1.6)); | 
| 681 |  | 
| 682 |         QSKIP("cancel is not supported atm" ); | 
| 683 |  | 
| 684 |         QTouchEvent cancelEvent(QEvent::TouchCancel); | 
| 685 |         cancelEvent.setDevice(device); | 
| 686 |         QCoreApplication::sendEvent(receiver: window, event: &cancelEvent); | 
| 687 |         QQuickTouchUtils::flush(window); | 
| 688 |  | 
| 689 |         QCOMPARE(root->property("scale" ).toReal(), 1.0); | 
| 690 |         QCOMPARE(root->property("center" ).toPointF(), QPointF(40, 40)); // blackrect is at 50,50 | 
| 691 |         QCOMPARE(blackRect->scale(), 1.0); | 
| 692 |         QVERIFY(!root->property("pinchActive" ).toBool()); | 
| 693 |     } | 
| 694 | } | 
| 695 |  | 
| 696 | void tst_QQuickPinchHandler::transformedpinchHandler_data() | 
| 697 | { | 
| 698 |     QTest::addColumn<QPoint>(name: "p0" ); | 
| 699 |     QTest::addColumn<QPoint>(name: "p1" ); | 
| 700 |     QTest::addColumn<bool>(name: "shouldPinch" ); | 
| 701 |  | 
| 702 |     QTest::newRow(dataTag: "checking inner pinchHandler 1" ) | 
| 703 |         << QPoint(200, 140) << QPoint(200, 260) << true; | 
| 704 |  | 
| 705 |     QTest::newRow(dataTag: "checking inner pinchHandler 2" ) | 
| 706 |         << QPoint(140, 200) << QPoint(200, 140) << true; | 
| 707 |  | 
| 708 |     QTest::newRow(dataTag: "checking inner pinchHandler 3" ) | 
| 709 |         << QPoint(140, 200) << QPoint(260, 200) << true; | 
| 710 |  | 
| 711 |     QTest::newRow(dataTag: "checking outer pinchHandler 1" ) | 
| 712 |         << QPoint(140, 140) << QPoint(260, 260) << false; | 
| 713 |  | 
| 714 |     QTest::newRow(dataTag: "checking outer pinchHandler 2" ) | 
| 715 |         << QPoint(140, 140) << QPoint(200, 200) << false; | 
| 716 |  | 
| 717 |     QTest::newRow(dataTag: "checking outer pinchHandler 3" ) | 
| 718 |         << QPoint(140, 260) << QPoint(260, 260) << false; | 
| 719 | } | 
| 720 |  | 
| 721 | void tst_QQuickPinchHandler::transformedpinchHandler() | 
| 722 | { | 
| 723 |     QFETCH(QPoint, p0); | 
| 724 |     QFETCH(QPoint, p1); | 
| 725 |     QFETCH(bool, shouldPinch); | 
| 726 |  | 
| 727 |     QQuickView *view = createView(); | 
| 728 |     QScopedPointer<QQuickView> scope(view); | 
| 729 |     view->setSource(testFileUrl(fileName: "transformedPinchHandler.qml" )); | 
| 730 |     view->show(); | 
| 731 |     QVERIFY(QTest::qWaitForWindowExposed(view)); | 
| 732 |     QVERIFY(view->rootObject() != nullptr); | 
| 733 |     qApp->processEvents(); | 
| 734 |  | 
| 735 |     QQuickPinchHandler *pinchHandler = view->rootObject()->findChild<QQuickPinchHandler*>(aName: "pinchHandler" ); | 
| 736 |     QVERIFY(pinchHandler != nullptr); | 
| 737 |  | 
| 738 |     const int threshold = qApp->styleHints()->startDragDistance(); | 
| 739 |  | 
| 740 |     { | 
| 741 |         QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window: view, device); | 
| 742 |         // start pinchHandler | 
| 743 |         pinchSequence.press(touchId: 0, pt: p0, window: view).commit(); | 
| 744 |         QQuickTouchUtils::flush(window: view); | 
| 745 |         // In order for the stationary point to remember its previous position, | 
| 746 |         // we have to reuse the same pinchSequence object. | 
| 747 |         pinchSequence.stationary(touchId: 0).press(touchId: 1, pt: p1, window: view).commit(); | 
| 748 |         QQuickTouchUtils::flush(window: view); | 
| 749 |  | 
| 750 |         // we move along the line that the two points form. | 
| 751 |         // The distance we move should be above the threshold (threshold * 2 to be safe) | 
| 752 |         QVector2D delta(p1 - p0); | 
| 753 |         delta.normalize(); | 
| 754 |         QVector2D movement = delta * (threshold * 2); | 
| 755 |         pinchSequence.stationary(touchId: 0).move(touchId: 1, pt: p1 + movement.toPoint(), window: view).commit(); | 
| 756 |         QQuickTouchUtils::flush(window: view); | 
| 757 |         QCOMPARE(pinchHandler->active(), shouldPinch); | 
| 758 |  | 
| 759 |         // release pinchHandler | 
| 760 |         pinchSequence.release(touchId: 0, pt: p0, window: view).release(touchId: 1, pt: p1, window: view).commit(); | 
| 761 |         QQuickTouchUtils::flush(window: view); | 
| 762 |         QCOMPARE(pinchHandler->active(), false); | 
| 763 |     } | 
| 764 | } | 
| 765 |  | 
| 766 | QQuickView *tst_QQuickPinchHandler::createView() | 
| 767 | { | 
| 768 |     QQuickView *window = new QQuickView(0); | 
| 769 |     window->setGeometry(posx: 0,posy: 0,w: 240,h: 320); | 
| 770 |  | 
| 771 |     return window; | 
| 772 | } | 
| 773 |  | 
| 774 | QTEST_MAIN(tst_QQuickPinchHandler) | 
| 775 |  | 
| 776 | #include "tst_qquickpinchhandler.moc" | 
| 777 |  |