2 * Copyright (C) 2013-2014 Canonical, Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17#include <QtTest/QtTest>
18#include <QtCore/QObject>
19#include <QtQuick/QQuickView>
20#include <QtQml/QQmlEngine>
22#include <private/qquickmousearea_p.h>
25#include <DirectionalDragArea.h>
26#include <TouchRegistry.h>
28#include "GestureTest.h"
30using namespace UbuntuGestures;
33class ComplexFakeTimer : public FakeTimer
37 ComplexFakeTimer(const SharedTimeSource &timeSource, QObject *parent = 0)
39 m_timeSource(timeSource)
42 void start() override {
43 AbstractTimer::start();
44 m_nextTimeoutTime = m_timeSource->msecsSinceReference() + (qint64)interval();
48 m_nextTimeoutTime += interval();
52 qint64 nextTimeoutTime() const { return m_nextTimeoutTime; }
55 SharedTimeSource m_timeSource;
56 qint64 m_nextTimeoutTime;
59class FakeTimeSource : public UbuntuGestures::TimeSource
62 FakeTimeSource() { m_msecsSinceReference = 0; }
63 virtual qint64 msecsSinceReference() {return m_msecsSinceReference;}
64 qint64 m_msecsSinceReference;
68 QQuickMouseArea::canceled() signal is not registered in the meta object system.
69 So using a QSignalSpy to track it won't work. Thus the only way to connect to it
70 is using its method address directly.
72class MouseAreaSpy : public QObject
76 MouseAreaSpy(QQuickMouseArea *mouseArea)
79 connect(mouseArea, &QQuickMouseArea::canceled,
80 this, &MouseAreaSpy::onMouseAreaCanceled);
86 void onMouseAreaCanceled() {
91class tst_DirectionalDragArea: public GestureTest
95 tst_DirectionalDragArea();
97 void init(); // called right before each and every test function is executed
98 void cleanup(); // called right after each and every test function is executed
101 void edgeDrag_data();
102 void dragWithShortDirectionChange();
104 void minSpeed_data();
105 void recognitionTimerUsage();
106 void maxSilenceTime();
111 void ignoreOldFinger();
113 void sceneDistance();
114 void sceneDistance_data();
115 void disabledWhileDragging();
116 void oneFingerDownFollowedByLateSecondFingerDown();
117 void givesUpWhenLosesTouch();
118 void threeFingerDrag();
119 void immediateRecognitionWhenConstraintsDisabled();
120 void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition();
121 void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data();
123 void tappedSignal_data();
124 void gettingTouchOwnershipMakesMouseAreaBehindGetCanceled();
127 void passTime(qint64 timeSpanMs);
128 ComplexFakeTimer *fakeTimer;
129 QSharedPointer<FakeTimeSource> fakeTimeSource;
132tst_DirectionalDragArea::tst_DirectionalDragArea()
133 : GestureTest(QStringLiteral("tst_DirectionalDragArea.qml"))
137void tst_DirectionalDragArea::init()
141 // We shouldn't need the three lines below, but a compiz/unity7
142 // regression means we don't pass the test without them because
143 // the window doesn't have the proper size. Can be removed in the
144 // future if the regression is fixed and tests pass again
145 m_view->resize(m_view->rootObject()->width(), m_view->rootObject()->height());
146 QTRY_COMPARE(m_view->width(), (int)m_view->rootObject()->width());
147 QTRY_COMPARE(m_view->height(), (int)m_view->rootObject()->height());
149 fakeTimeSource.reset(new FakeTimeSource);
150 fakeTimer = new ComplexFakeTimer(fakeTimeSource);
153void tst_DirectionalDragArea::cleanup()
158 fakeTimeSource.reset();
160 GestureTest::cleanup();
163void tst_DirectionalDragArea::passTime(qint64 timeSpanMs)
165 qint64 finalTime = fakeTimeSource->m_msecsSinceReference + timeSpanMs;
167 if (fakeTimer->isRunning() && finalTime >= fakeTimer->nextTimeoutTime()) {
168 fakeTimeSource->m_msecsSinceReference = fakeTimer->nextTimeoutTime();
169 fakeTimer->emitTimeout();
171 qint64 timeSpanRemainder = finalTime - fakeTimeSource->m_msecsSinceReference;
172 if (timeSpanRemainder > 0) {
173 passTime(timeSpanRemainder);
176 fakeTimeSource->m_msecsSinceReference = finalTime;
181QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea)
183 QPointF localCenter(edgeDragArea->width() / 2., edgeDragArea->height() / 2.);
184 return edgeDragArea->mapToScene(localCenter);
187QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea,
188 qreal wideningAngleMultiplier)
190 qreal angleRadians = edgeDragArea->wideningAngle() * wideningAngleMultiplier
193 qreal angleCos = qCos(angleRadians);
194 qreal angleSin = qSin(angleRadians);
196 switch (edgeDragArea->direction()) {
197 case Direction::Upwards:
198 return QPointF(angleSin, -angleCos);
199 case Direction::Downwards:
200 return QPointF(angleSin, angleCos);
201 case Direction::Leftwards:
202 return QPointF(-angleCos, angleSin);
203 default: // Direction::Rightwards:
204 return QPointF(angleCos, angleSin);
208QPointF createTouchDeviation(DirectionalDragArea *edgeDragArea)
210 qreal deviation = edgeDragArea->maxDeviation() * 0.8;
212 if (Direction::isHorizontal(edgeDragArea->direction())) {
213 return QPointF(0, deviation);
215 return QPointF(deviation, 0);
220void tst_DirectionalDragArea::edgeDrag()
222 QFETCH(QString, dragAreaObjectName);
223 QFETCH(qreal, wideningAngleMultiplier);
224 QFETCH(qreal, dragDistanceFactor);
225 QFETCH(bool, expectGestureRecognition);
227 DirectionalDragArea *edgeDragArea =
228 m_view->rootObject()->findChild<DirectionalDragArea*>(dragAreaObjectName);
229 QVERIFY(edgeDragArea != 0);
230 edgeDragArea->setRecognitionTimer(fakeTimer);
231 edgeDragArea->setTimeSource(fakeTimeSource);
233 QSignalSpy draggingSpy(edgeDragArea, SIGNAL(draggingChanged(bool)));
235 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
236 QPointF touchPoint = initialTouchPos;
238 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*dragDistanceFactor;
239 QPointF dragDirectionVector = calculateDirectionVector(edgeDragArea,
240 wideningAngleMultiplier);
241 qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
242 QPointF touchMovement = dragDirectionVector * movementStepDistance;
243 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
244 int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
246 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
248 QCOMPARE(draggingSpy.count(), 1);
249 QCOMPARE(edgeDragArea->dragging(), true);
251 if (wideningAngleMultiplier > 0) {
252 // go close to the border of the valid area for this touch point
253 // in order to make it easier to leave it by dragging at an angle
254 // slightly bigger than the widening angle
255 touchPoint += createTouchDeviation(edgeDragArea);
256 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
259 for (int i = 0; i < totalMovementSteps; ++i) {
260 touchPoint += touchMovement;
261 passTime(movementTimeStepMs);
262 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
265 if (expectGestureRecognition)
266 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
268 if (edgeDragArea->status() == DirectionalDragArea::WaitingForTouch) {
269 QCOMPARE(edgeDragArea->dragging(), false);
270 QCOMPARE(draggingSpy.count(), 2);
273 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
275 QCOMPARE(draggingSpy.count(), 2);
276 QCOMPARE(edgeDragArea->dragging(), false);
279void tst_DirectionalDragArea::edgeDrag_data()
281 QTest::addColumn<QString>("dragAreaObjectName");
282 QTest::addColumn<qreal>("wideningAngleMultiplier");
283 QTest::addColumn<qreal>("dragDistanceFactor");
284 QTest::addColumn<bool>("expectGestureRecognition");
286 QTest::newRow("rightwards, tiny drag")
287 << "hpDragArea" << 0.0 << 0.2 << false;
289 QTest::newRow("rightwards, straight drag")
290 << "hpDragArea" << 0.0 << 3.0 << true;
292 QTest::newRow("rightwards, diagonal drag")
293 << "hpDragArea" << 0.9 << 3.0 << true;
295 QTest::newRow("rightwards, overly diagonal drag")
296 << "hpDragArea" << 2.0 << 3.0 << false;
298 QTest::newRow("leftwards, tiny drag")
299 << "hnDragArea" << 0.0 << 0.2 << false;
301 QTest::newRow("leftwards, straight drag")
302 << "hnDragArea" << 0.0 << 3.0 << true;
304 QTest::newRow("leftwards, diagonal drag")
305 << "hnDragArea" << 0.9 << 3.0 << true;
307 QTest::newRow("downwards, tiny drag")
308 << "vpDragArea" << 0.0 << 0.2 << false;
310 QTest::newRow("downwards, straight drag")
311 << "vpDragArea" << 0.0 << 3.0 << true;
313 QTest::newRow("downwards, diagonal drag")
314 << "vpDragArea" << 0.9 << 3.0 << true;
316 QTest::newRow("upwards, tiny drag")
317 << "vnDragArea" << 0.0 << 0.2 << false;
319 QTest::newRow("upwards, straight drag")
320 << "vnDragArea" << 0.0 << 3.0 << true;
322 QTest::newRow("upwards, diagonal drag")
323 << "vnDragArea" << 0.9 << 3.0 << true;
325 QTest::newRow("upwards, overly diagonal drag")
326 << "vnDragArea" << 2.0 << 3.0 << false;
330 A directional drag should still be recognized if there is a momentaneous, small,
331 change in the direction of a drag. That should be accounted as input noise and
334void tst_DirectionalDragArea::dragWithShortDirectionChange()
336 DirectionalDragArea *edgeDragArea =
337 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
338 QVERIFY(edgeDragArea != 0);
339 edgeDragArea->setRecognitionTimer(fakeTimer);
340 edgeDragArea->setTimeSource(fakeTimeSource);
342 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
343 QPointF touchPoint = initialTouchPos;
345 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0;
346 QPointF dragDirectionVector(1.0, 0.0);
347 qreal touchStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
348 // make sure we are above minimum speed
349 int touchStepTimeMs = (touchStepDistance / (edgeDragArea->minSpeed() * 5.0f)) * 1000.0f;
350 QPointF touchMovement = dragDirectionVector * touchStepDistance;
352 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
354 // Move a bit in the proper direction
355 for (int i=0; i < 3; ++i) {
356 touchPoint += touchMovement;
357 passTime(touchStepTimeMs);
358 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
361 // Then a sudden and small movement to the opposite direction
362 touchPoint -= touchMovement*0.2;
363 passTime(touchStepTimeMs*0.2);
364 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
366 // And then resume movment in the correct direction until it crosses the distance and time
369 touchPoint += touchMovement;
370 passTime(touchStepTimeMs);
371 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
372 } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance
373 || fakeTimeSource->m_msecsSinceReference < (edgeDragArea->compositionTime() * 1.5f));
375 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
377 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
381 Checks that a gesture will be rejected if it's slower than minSpeed while
384void tst_DirectionalDragArea::minSpeed()
386 QFETCH(qreal, minSpeed);
387 QFETCH(qreal, speed);
388 QFETCH(int, expectedStatusAfterSpeedCheck);
390 DirectionalDragArea *edgeDragArea =
391 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
392 QVERIFY(edgeDragArea != 0);
393 edgeDragArea->setRecognitionTimer(fakeTimer);
394 edgeDragArea->setTimeSource(fakeTimeSource);
396 // A really long, unattainable, number. We don't want it getting recognized before
397 // the speed checks we want have been performed
398 edgeDragArea->setDistanceThreshold(500000);
400 edgeDragArea->setMinSpeed(minSpeed);
402 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
403 QPointF touchPoint = initialTouchPos;
405 QPointF dragDirectionVector(1.0, 0.0);
406 qint64 timeStepMsecs = 10;
407 qreal distanceStep = (speed / 1000.0f) * timeStepMsecs;
408 QPointF touchMovement = dragDirectionVector * distanceStep;
410 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
412 // Move for a while to ensure our speed check is performed a couple of times
413 for (int i=0; i < 20; ++i) {
414 touchPoint += touchMovement;
415 passTime(timeStepMsecs);
416 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
419 QCOMPARE((int)edgeDragArea->status(), expectedStatusAfterSpeedCheck);
422void tst_DirectionalDragArea::minSpeed_data()
424 QTest::addColumn<qreal>("minSpeed");
425 QTest::addColumn<qreal>("speed");
426 QTest::addColumn<int>("expectedStatusAfterSpeedCheck");
428 QTest::newRow("slower than minSpeed") << 100.0 << 50.0 << (int)DirectionalDragArea::WaitingForTouch;
429 QTest::newRow("faster than minSpeed") << 100.0 << 150.0 << (int)DirectionalDragArea::Undecided;
433 Checks that the recognition timer is started and stopped appropriately.
434 I.e., check that it's running only while gesture recognition is taking place
435 (status == Undecided)
437void tst_DirectionalDragArea::recognitionTimerUsage()
439 DirectionalDragArea *edgeDragArea =
440 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
441 QVERIFY(edgeDragArea != 0);
442 edgeDragArea->setRecognitionTimer(fakeTimer);
443 edgeDragArea->setTimeSource(fakeTimeSource);
445 // don't let it interfere with our test
446 edgeDragArea->setMinSpeed(0.0);
448 int timeStepMs = 5; // some arbitrary small value.
450 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
451 QPointF touchPoint = initialTouchPos;
453 QPointF dragDirectionVector(1.0, 0.0);
454 QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.2f);
456 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
457 QVERIFY(!fakeTimer->isRunning());
459 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
461 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
462 QVERIFY(fakeTimer->isRunning());
464 // Move beyond distance threshold and composition time to ensure recognition
465 while (fakeTimeSource->m_msecsSinceReference <= edgeDragArea->compositionTime() ||
466 (touchPoint - initialTouchPos).manhattanLength() <= edgeDragArea->distanceThreshold()) {
468 QCOMPARE(edgeDragArea->status() == DirectionalDragArea::Undecided, fakeTimer->isRunning());
470 touchPoint += touchMovement;
471 passTime(timeStepMs);
472 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
475 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
476 QVERIFY(!fakeTimer->isRunning());
480 A gesture should be rejected if too much time has passed without any new input
483void tst_DirectionalDragArea::maxSilenceTime()
485 DirectionalDragArea *edgeDragArea =
486 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
487 QVERIFY(edgeDragArea != 0);
488 edgeDragArea->setRecognitionTimer(fakeTimer);
489 edgeDragArea->setTimeSource(fakeTimeSource);
491 // Make sure this property is not disabled
492 edgeDragArea->setMaxSilenceTime(100);
494 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
495 QPointF touchPoint = initialTouchPos;
497 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
499 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
500 QVERIFY(fakeTimer->isRunning());
502 // Force timer to timeout until after maxSilenceTime has been reached
503 while (fakeTimeSource->m_msecsSinceReference < edgeDragArea->maxSilenceTime()) {
504 passTime(fakeTimer->interval());
507 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
511 Checks that it informs the X coordinate of the touch point in local and scene coordinates
514void tst_DirectionalDragArea::sceneXAndX()
516 DirectionalDragArea *edgeDragArea =
517 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
518 QVERIFY(edgeDragArea != 0);
519 edgeDragArea->setRecognitionTimer(fakeTimer);
520 edgeDragArea->setTimeSource(fakeTimeSource);
522 QPointF touchScenePos(m_view->width() - (edgeDragArea->width()/2.0f), m_view->height()/2.0f);
524 QTest::touchEvent(m_view, m_device).press(0, touchScenePos.toPoint());
526 QSignalSpy touchXSpy(edgeDragArea, SIGNAL(touchXChanged(qreal)));
527 QSignalSpy touchSceneXSpy(edgeDragArea, SIGNAL(touchSceneXChanged(qreal)));
529 touchScenePos.rx() = m_view->width() / 2;
530 QTest::touchEvent(m_view, m_device).move(0, touchScenePos.toPoint());
532 QCOMPARE(touchXSpy.count(), 1);
533 QCOMPARE(touchSceneXSpy.count(), 1);
534 QCOMPARE(edgeDragArea->touchX(), touchScenePos.x() - edgeDragArea->x());
535 QCOMPARE(edgeDragArea->touchSceneX(), touchScenePos.x());
539 Checks that it informs the Y coordinate of the touch point in local and scene coordinates
542void tst_DirectionalDragArea::sceneYAndY()
544 DirectionalDragArea *edgeDragArea =
545 m_view->rootObject()->findChild<DirectionalDragArea*>("vnDragArea");
546 QVERIFY(edgeDragArea != 0);
547 edgeDragArea->setRecognitionTimer(fakeTimer);
548 edgeDragArea->setTimeSource(fakeTimeSource);
550 QPointF touchScenePos(m_view->width()/2.0f, m_view->height() - (edgeDragArea->height()/2.0f));
552 QTest::touchEvent(m_view, m_device).press(0, touchScenePos.toPoint());
554 QSignalSpy touchYSpy(edgeDragArea, SIGNAL(touchYChanged(qreal)));
555 QSignalSpy touchSceneYSpy(edgeDragArea, SIGNAL(touchSceneYChanged(qreal)));
557 touchScenePos.ry() = m_view->height() / 2;
558 QTest::touchEvent(m_view, m_device).move(0, touchScenePos.toPoint());
560 QCOMPARE(touchYSpy.count(), 1);
561 QCOMPARE(touchSceneYSpy.count(), 1);
562 QCOMPARE(edgeDragArea->touchY(), touchScenePos.y() - edgeDragArea->y());
563 QCOMPARE(edgeDragArea->touchSceneY(), touchScenePos.y());
567 Regression test for https://bugs.launchpad.net/bugs/1228336
569 Perform a quick two-finger double-tap and check that DirectionalDragArea properly
570 rejects those touch points. In the bug above it got confused and crashed.
572void tst_DirectionalDragArea::twoFingerTap()
574 DirectionalDragArea *edgeDragArea =
575 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
576 QVERIFY(edgeDragArea != 0);
577 edgeDragArea->setRecognitionTimer(fakeTimer);
578 edgeDragArea->setTimeSource(fakeTimeSource);
580 // Make touches evenly spaced along the edgeDragArea
581 QPoint touchAPos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
582 QPoint touchBPos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
584 qint64 timeStepMsecs = 5; // some arbitrary, small value
586 // Perform the first two-finger tap
587 // NB: using move() instead of stationary() becasue in the latter you cannot provide
588 // the touch position and therefore it's left with some garbage numbers.
589 QTest::touchEvent(m_view, m_device)
590 .press(0, touchAPos);
592 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
594 passTime(timeStepMsecs);
595 QTest::touchEvent(m_view, m_device)
597 .press(1, touchBPos);
599 // A second touch point appeared during recognition, reject immediately as this
600 // can't be a single-touch gesture anymore.
601 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
603 passTime(timeStepMsecs);
604 QTest::touchEvent(m_view, m_device)
605 .release(0, touchAPos)
608 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
610 passTime(timeStepMsecs);
611 QTest::touchEvent(m_view, m_device)
612 .release(1, touchBPos);
614 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
616 // Perform the second two-finger tap
618 passTime(timeStepMsecs);
619 QTest::touchEvent(m_view, m_device)
620 .press(0, touchAPos);
622 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
624 passTime(timeStepMsecs);
625 QTest::touchEvent(m_view, m_device)
627 .press(1, touchBPos);
629 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
631 passTime(timeStepMsecs);
632 QTest::touchEvent(m_view, m_device)
633 .release(0, touchAPos)
636 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
638 passTime(timeStepMsecs);
639 QTest::touchEvent(m_view, m_device)
640 .release(1, touchBPos);
642 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
646 Tests that gesture recognition works normally even if the DirectionalDragArea moves
648 This effectively means that we have to do gesture recognition with scene coordinates
649 instead of local item coordinates.
651void tst_DirectionalDragArea::movingDDA()
653 QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
654 Q_ASSERT(rightwardsLauncher != 0);
656 DirectionalDragArea *edgeDragArea =
657 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
658 Q_ASSERT(edgeDragArea != 0);
659 edgeDragArea->setRecognitionTimer(fakeTimer);
660 edgeDragArea->setTimeSource(fakeTimeSource);
662 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
663 QPointF touchPoint = initialTouchPos;
665 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
666 QPointF dragDirectionVector(1.0f, 0.0f);
668 qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
669 QPointF touchMovement = dragDirectionVector * movementStepDistance;
670 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
671 int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
673 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
675 // Move it far ahead along the direction of the gesture
676 // rightwardsLauncher is a parent of our DirectionalDragArea. So moving it will move our DDA
677 rightwardsLauncher->setX(rightwardsLauncher->x() + edgeDragArea->distanceThreshold() * 5.0f);
679 for (int i = 0; i < totalMovementSteps; ++i) {
680 touchPoint += touchMovement;
681 passTime(movementTimeStepMs);
682 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
685 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
687 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
691 The presence of and old, rejected, touch point lying on the DirectionalDragArea
692 shouldn't impede the recognition of a gesture from a new touch point.
694void tst_DirectionalDragArea::ignoreOldFinger()
696 DirectionalDragArea *edgeDragArea =
697 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
698 Q_ASSERT(edgeDragArea != 0);
699 edgeDragArea->setRecognitionTimer(fakeTimer);
700 edgeDragArea->setTimeSource(fakeTimeSource);
702 // Make touches evenly spaced along the edgeDragArea
703 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
704 QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
706 QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
708 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
710 // leave it lying around for some time
711 passTime(qMax(edgeDragArea->maxSilenceTime(), edgeDragArea->compositionTime()) * 10);
713 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
715 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
716 QPointF dragDirectionVector(1.0f, 0.0f);
718 qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
719 QPointF touchMovement = dragDirectionVector * movementStepDistance;
720 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
721 int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
723 QTest::touchEvent(m_view, m_device)
725 .press(1, touch1Pos);
727 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
729 for (int i = 0; i < totalMovementSteps; ++i) {
730 touch1Pos += touchMovement.toPoint();
731 passTime(movementTimeStepMs);
732 QTest::touchEvent(m_view, m_device)
737 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
739 QTest::touchEvent(m_view, m_device)
741 .release(1, touch1Pos);
743 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
747 A Rightwards DDA that is rotated 90 degrees clockwise should recognize gestures
748 that are done downwards in scene coordinates. I.e. the gesture recognition direction
749 should be in local coordinates, not scene coordinates.
751void tst_DirectionalDragArea::rotated()
753 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
754 baseItem->setRotation(90.);
756 QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
757 Q_ASSERT(rightwardsLauncher != 0);
759 DirectionalDragArea *edgeDragArea =
760 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
761 Q_ASSERT(edgeDragArea != 0);
762 edgeDragArea->setRecognitionTimer(fakeTimer);
763 edgeDragArea->setTimeSource(fakeTimeSource);
765 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
766 QPointF touchPoint = initialTouchPos;
768 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
769 QPointF dragDirectionVector(0.0f, 1.0f);
771 qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
772 QPointF touchMovement = dragDirectionVector * movementStepDistance;
773 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
774 int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
776 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
778 for (int i = 0; i < totalMovementSteps; ++i) {
779 touchPoint += touchMovement;
780 passTime(movementTimeStepMs);
781 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
784 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
786 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
789void tst_DirectionalDragArea::sceneDistance()
791 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
792 QFETCH(qreal, rotation);
793 QFETCH(QPointF, dragDirectionVector);
794 baseItem->setRotation(rotation);
796 QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
797 Q_ASSERT(rightwardsLauncher != 0);
799 DirectionalDragArea *edgeDragArea =
800 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
801 Q_ASSERT(edgeDragArea != 0);
802 edgeDragArea->setRecognitionTimer(fakeTimer);
803 edgeDragArea->setTimeSource(fakeTimeSource);
805 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
806 QPointF touchPoint = initialTouchPos;
808 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
810 qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
811 QPointF touchMovement = dragDirectionVector * movementStepDistance;
812 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
813 int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
815 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
817 for (int i = 0; i < totalMovementSteps; ++i) {
818 touchPoint += touchMovement;
819 passTime(movementTimeStepMs);
820 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
823 qreal actualDragDistance = ((qreal)totalMovementSteps) * movementStepDistance;
825 // DirectionalDragArea::sceneDistance() must match the actual drag distance as the
826 // drag was aligned with the gesture direction
827 // NB: qFuzzyCompare(), used internally by QCOMPARE(), is broken.
828 QVERIFY(qAbs(edgeDragArea->sceneDistance() - actualDragDistance) < 0.001);
830 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
833void tst_DirectionalDragArea::sceneDistance_data()
835 QTest::addColumn<qreal>("rotation");
836 QTest::addColumn<QPointF>("dragDirectionVector");
838 QTest::newRow("not rotated") << 0. << QPointF(1., 0.);
839 QTest::newRow("rotated by 90 degrees") << 90. << QPointF(0., 1.);
843 Regression test for https://bugs.launchpad.net/unity8/+bug/1276122
846 If setting "enabled: false" while the DirectionalDragArea's (DDA) dragging
847 property is true, the DDA stays in that state and doesn't recover any more.
849void tst_DirectionalDragArea::disabledWhileDragging()
851 DirectionalDragArea *edgeDragArea =
852 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
853 Q_ASSERT(edgeDragArea != 0);
854 edgeDragArea->setRecognitionTimer(fakeTimer);
855 edgeDragArea->setTimeSource(fakeTimeSource);
857 QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
859 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
860 QPointF dragDirectionVector(1., 0.); // horizontal positive
862 qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
863 QPointF touchMovement = dragDirectionVector * movementStepDistance;
864 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
865 int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
867 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
869 for (int i = 0; i < totalMovementSteps; ++i) {
870 touchPoint += touchMovement;
871 passTime(movementTimeStepMs);
872 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
875 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
876 QCOMPARE(edgeDragArea->dragging(), true);
878 // disable the dragArea while it's being dragged.
879 edgeDragArea->setEnabled(false);
881 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
882 QCOMPARE(edgeDragArea->dragging(), false);
884 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
887void tst_DirectionalDragArea::oneFingerDownFollowedByLateSecondFingerDown()
889 DirectionalDragArea *edgeDragArea =
890 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
891 Q_ASSERT(edgeDragArea != 0);
892 edgeDragArea->setRecognitionTimer(fakeTimer);
893 edgeDragArea->setTimeSource(fakeTimeSource);
895 // Disable some constraints we're not interested in
896 edgeDragArea->setMaxSilenceTime(60 * 1000);
897 edgeDragArea->setMinSpeed(0);
899 // And ensure others have the values we want
900 edgeDragArea->setCompositionTime(60);
902 // Put an item right behind edgeDragArea to receive the touches ignored by it
903 DummyItem *dummyItem = new DummyItem;
904 dummyItem->setParentItem(edgeDragArea->parentItem());
905 dummyItem->setX(edgeDragArea->x());
906 dummyItem->setY(edgeDragArea->y());
907 dummyItem->setZ(edgeDragArea->z() - 1.0);
908 dummyItem->setWidth(edgeDragArea->width());
909 dummyItem->setHeight(edgeDragArea->height());
911 // Make touches evenly spaced along the edgeDragArea
912 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
913 QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
915 QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
917 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
919 // We are now going to be way beyond compositionTime
920 passTime(edgeDragArea->compositionTime()*3);
922 QTest::touchEvent(m_view, m_device)
924 .press(1, touch1Pos);
926 // A new touch has come, but as it can't be composed with touch 0, it should be
927 // ignored/rejected by the DirectionalDragArea
928 // Therefore the last event received by dummyItem must have both touch points (0 and 1)
930 TouchMemento &touchMemento = dummyItem->touchEvents.last();
931 QCOMPARE(touchMemento.touchPoints.count(), 2);
932 QVERIFY(touchMemento.containsTouchWithId(0));
933 QVERIFY(touchMemento.containsTouchWithId(1));
938 QTest::touchEvent(m_view, m_device)
942 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
946 QTest::touchEvent(m_view, m_device)
947 .release(0, touch0Pos)
950 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
954 QTest::touchEvent(m_view, m_device)
955 .release(1, touch1Pos);
957 // Shouldn't be keepping info about touches that no longer exist or interest us
958 QVERIFY(edgeDragArea->m_activeTouches.isEmpty());
963void tst_DirectionalDragArea::givesUpWhenLosesTouch()
965 DirectionalDragArea *edgeDragArea =
966 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
967 Q_ASSERT(edgeDragArea != 0);
968 edgeDragArea->setRecognitionTimer(fakeTimer);
969 edgeDragArea->setTimeSource(fakeTimeSource);
971 // Disable some constraints we're not interested in
972 edgeDragArea->setMaxSilenceTime(60 * 1000);
973 edgeDragArea->setMinSpeed(0);
975 // Put an item right in front of edgeDragArea
976 DummyItem *dummyItem = new DummyItem(edgeDragArea->parentItem());
977 dummyItem->setX(edgeDragArea->x());
978 dummyItem->setY(edgeDragArea->y());
979 dummyItem->setZ(edgeDragArea->z() + 1.0);
980 dummyItem->setWidth(edgeDragArea->width());
981 dummyItem->setHeight(edgeDragArea->height());
983 QPoint touchPos(edgeDragArea->width()/2.0f, m_view->height()/2.0f);
985 dummyItem->touchEventHandler = [&](QTouchEvent *event) {
986 m_touchRegistry->addCandidateOwnerForTouch(0, dummyItem);
990 QTest::touchEvent(m_view, m_device).press(0, touchPos);
992 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
994 m_touchRegistry->requestTouchOwnership(0, dummyItem);
996 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
998 dummyItem->grabTouchPoints({0});
999 dummyItem->touchEventHandler = [&](QTouchEvent *event) { event->accept(); };
1002 QTest::touchEvent(m_view, m_device).release(0, touchPos);
1004 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
1006 QVERIFY(edgeDragArea->m_activeTouches.isEmpty());
1009void tst_DirectionalDragArea::threeFingerDrag()
1011 DirectionalDragArea *edgeDragArea =
1012 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1013 Q_ASSERT(edgeDragArea != 0);
1014 edgeDragArea->setRecognitionTimer(fakeTimer);
1015 edgeDragArea->setTimeSource(fakeTimeSource);
1017 // Disable some constraints we're not interested in
1018 edgeDragArea->setMaxSilenceTime(60 * 1000);
1019 edgeDragArea->setMinSpeed(0);
1021 // And ensure others have the values we want
1022 edgeDragArea->setCompositionTime(60);
1024 // Make touches evenly spaced along the edgeDragArea
1025 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.25f);
1026 QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.50f);
1027 QPoint touch2Pos(edgeDragArea->width()/2.0f, m_view->height()*0.75f);
1029 QTest::touchEvent(m_view, m_device)
1030 .press(0, touch0Pos);
1032 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
1035 QTest::touchEvent(m_view, m_device)
1037 .press(1, touch1Pos);
1039 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
1042 QTest::touchEvent(m_view, m_device)
1045 .press(2, touch2Pos);
1047 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
1050 QTest::touchEvent(m_view, m_device)
1053 .move(2, touch2Pos);
1056 QTest::touchEvent(m_view, m_device)
1058 .release(1, touch1Pos)
1059 .move(2, touch2Pos);
1062 QTest::touchEvent(m_view, m_device)
1064 .release(2, touch2Pos);
1067 QTest::touchEvent(m_view, m_device)
1068 .release(0, touch0Pos);
1070 // Shouldn't be keepping info about touches that no longer exist or interest us
1071 QVERIFY(edgeDragArea->m_activeTouches.isEmpty());
1075 If all the relevant gesture recognition constraints/parameters have been disabled,
1076 it means that the gesture recognition itself has been disabled and DirectionalDragArea
1077 will therefore work like a simple touch area, merely reporting touch movement.
1079void tst_DirectionalDragArea::immediateRecognitionWhenConstraintsDisabled()
1081 DirectionalDragArea *edgeDragArea =
1082 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1083 Q_ASSERT(edgeDragArea != 0);
1084 edgeDragArea->setRecognitionTimer(fakeTimer);
1085 edgeDragArea->setTimeSource(fakeTimeSource);
1087 // Disable the minimum amount of constraints to ensure immediate recognition
1088 edgeDragArea->setDistanceThreshold(0);
1089 edgeDragArea->setCompositionTime(0);
1091 // Put an item right behind edgeDragArea to receive the touches ignored by it
1092 DummyItem *dummyItem = new DummyItem;
1093 dummyItem->setParentItem(edgeDragArea->parentItem());
1094 dummyItem->setX(edgeDragArea->x());
1095 dummyItem->setY(edgeDragArea->y());
1096 dummyItem->setZ(edgeDragArea->z() - 1.0);
1097 dummyItem->setWidth(edgeDragArea->width());
1098 dummyItem->setHeight(edgeDragArea->height());
1100 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()/2.0f);
1102 QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
1104 // check for immediate recognition
1105 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
1107 // and therefore it should have immediately grabbed the touch point,
1108 // not letting it leak to items behind him.
1109 QCOMPARE(dummyItem->touchEvents.count(), 0);
1112void tst_DirectionalDragArea::withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition()
1114 DirectionalDragArea *edgeDragArea =
1115 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1116 Q_ASSERT(edgeDragArea != 0);
1117 edgeDragArea->setRecognitionTimer(fakeTimer);
1118 edgeDragArea->setTimeSource(fakeTimeSource);
1120 QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
1122 // Move less than the minimum needed for the drag gesture recognition
1123 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*0.5f;
1124 QPointF dragDirectionVector(1., 0.); // horizontal positive
1126 qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
1127 QPointF touchMovement = dragDirectionVector * movementStepDistance;
1128 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
1129 int movementTimeStepMs = (edgeDragArea->compositionTime() * 0.8f) / totalMovementSteps;
1131 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
1133 for (int i = 0; i < totalMovementSteps; ++i) {
1134 touchPoint += touchMovement;
1135 passTime(movementTimeStepMs);
1136 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
1139 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
1141 // edgeDragArea should be an undecided candidate
1143 auto touchInfo = m_touchRegistry->findTouchInfo(0);
1144 QCOMPARE(touchInfo->candidates.size(), 1);
1145 QCOMPARE(touchInfo->candidates.at(0).item.data(), edgeDragArea);
1146 QCOMPARE(touchInfo->candidates.at(0).undecided, true);
1149 // disable the dragArea while it's still recognizing a possible drag gesture.
1150 QFETCH(bool, disable);
1152 edgeDragArea->setEnabled(false);
1154 edgeDragArea->setVisible(false);
1157 // edgeDragArea should no longer be a candidate
1159 auto touchInfo = m_touchRegistry->findTouchInfo(0);
1160 QCOMPARE(touchInfo->candidates.size(), 0);
1163 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
1165 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
1168void tst_DirectionalDragArea::withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data()
1170 QTest::addColumn<bool>("disable");
1172 QTest::newRow("disabled") << true;
1173 QTest::newRow("invisible") << false;
1176void tst_DirectionalDragArea::tappedSignal()
1178 DirectionalDragArea *edgeDragArea =
1179 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1180 QVERIFY(edgeDragArea != 0);
1181 edgeDragArea->setRecognitionTimer(fakeTimer);
1182 edgeDragArea->setTimeSource(fakeTimeSource);
1184 QFETCH(bool, immediateGestureRecognition);
1185 if (immediateGestureRecognition) {
1186 // Disable the minimum amount of constraints to ensure immediate recognition
1187 edgeDragArea->setDistanceThreshold(0);
1188 edgeDragArea->setCompositionTime(0);
1191 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()/2.0f);
1193 QSignalSpy tappedSpy(edgeDragArea, SIGNAL(tapped()));
1195 QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
1196 passTime(edgeDragArea->maxTapDuration() / 2);
1197 QTest::touchEvent(m_view, m_device).release(0, touch0Pos);
1199 QCOMPARE(tappedSpy.count(), 1);
1202void tst_DirectionalDragArea::tappedSignal_data()
1204 QTest::addColumn<bool>("immediateGestureRecognition");
1206 QTest::newRow("immediate gesture recognition") << true;
1207 QTest::newRow("default gesture recognition") << false;
1210void tst_DirectionalDragArea::gettingTouchOwnershipMakesMouseAreaBehindGetCanceled()
1212 DirectionalDragArea *edgeDragArea =
1213 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1214 QVERIFY(edgeDragArea != nullptr);
1215 edgeDragArea->setRecognitionTimer(fakeTimer);
1216 edgeDragArea->setTimeSource(fakeTimeSource);
1218 QQuickMouseArea *mouseArea =
1219 m_view->rootObject()->findChild<QQuickMouseArea*>("mouseArea");
1220 QVERIFY(mouseArea != nullptr);
1222 MouseAreaSpy mouseAreaSpy(mouseArea);
1224 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
1225 QPointF touchPoint = initialTouchPos;
1227 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2;
1228 QPointF dragDirectionVector(1.0f, 0.0f); // rightwards
1229 qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
1230 QPointF touchMovement = dragDirectionVector * movementStepDistance;
1231 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
1232 int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
1234 QCOMPARE(mouseArea->pressed(), false);
1236 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
1238 // The TouchBegin passes through the DirectionalDragArea and reaches the MouseArea behind it,
1239 // where it's converted to a MouseEvent by QQuickWindow and sent to the MouseArea which then
1240 // accepts it. Making it get pressed.
1241 QCOMPARE(mouseArea->pressed(), true);
1242 QCOMPARE(mouseAreaSpy.canceledCount, 0);
1244 for (int i = 0; i < totalMovementSteps; ++i) {
1245 touchPoint += touchMovement;
1246 passTime(movementTimeStepMs);
1247 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
1250 // As the DirectionalDragArea recognizes the gesture, it grabs the touch from the MouseArea,
1251 // which should make the MouseArea get a cancelation event, which will then cause it to
1252 // reset its state (going back to "unpressed"/"released").
1253 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
1254 QCOMPARE(mouseArea->pressed(), false);
1255 QCOMPARE(mouseAreaSpy.canceledCount, 1);
1257 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
1260QTEST_MAIN(tst_DirectionalDragArea)
1262#include "tst_DirectionalDragArea.moc"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list