2 * Copyright (C) 2013 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 <qpa/qwindowsysteminterface.h>
20#include <QtQuick/QQuickView>
21#include <QtQml/QQmlEngine>
23#include <DirectionalDragArea.h>
25class tst_DirectionalDragArea: public QObject
29 tst_DirectionalDragArea() : device(0) { }
31 void initTestCase(); // will be called before the first test function is executed
32 void cleanupTestCase(); // will be called after the last test function was executed.
36 void dragWithShortDirectionChange();
39 QQuickView *createView();
43void tst_DirectionalDragArea::initTestCase()
46 device = new QTouchDevice;
47 device->setType(QTouchDevice::TouchScreen);
48 QWindowSystemInterface::registerTouchDevice(device);
52void tst_DirectionalDragArea::cleanupTestCase()
56QQuickView *tst_DirectionalDragArea::createView()
58 QQuickView *window = new QQuickView(0);
59 window->setResizeMode(QQuickView::SizeRootObjectToView);
60 window->resize(600, 600);
61 window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
67QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea, QQuickView *view)
69 switch (edgeDragArea->direction()) {
70 case DirectionalDragArea::Upwards:
71 return QPointF(view->width()/2.0f, view->height() - (edgeDragArea->height()/2.0f));
72 case DirectionalDragArea::Downwards:
73 return QPointF(view->width()/2.0f, edgeDragArea->height()/2.0f);
74 case DirectionalDragArea::Leftwards:
75 return QPointF(view->width() - (edgeDragArea->width()/2.0f), view->height()/2.0f);
76 default: // DirectionalDragArea::Rightwards:
77 return QPointF(edgeDragArea->width()/2.0f, view->height()/2.0f);
81QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea,
82 qreal wideningAngleMultiplier)
84 qreal angleRadians = edgeDragArea->wideningAngle() * wideningAngleMultiplier
87 qreal angleCos = qCos(angleRadians);
88 qreal angleSin = qSin(angleRadians);
90 switch (edgeDragArea->direction()) {
91 case DirectionalDragArea::Upwards:
92 return QPointF(angleSin, -angleCos);
93 case DirectionalDragArea::Downwards:
94 return QPointF(angleSin, angleCos);
95 case DirectionalDragArea::Leftwards:
96 return QPointF(-angleCos, angleSin);
97 default: // DirectionalDragArea::Rightwards:
98 return QPointF(angleCos, angleSin);
102QPointF createTouchDeviation(DirectionalDragArea *edgeDragArea)
104 qreal deviation = edgeDragArea->maxDeviation() * 0.8;
106 if (edgeDragArea->direction() == DirectionalDragArea::Leftwards
107 || edgeDragArea->direction() == DirectionalDragArea::Rightwards) {
108 return QPointF(0, deviation);
110 return QPointF(deviation, 0);
115void tst_DirectionalDragArea::edgeDrag()
117 QFETCH(QString, dragAreaObjectName);
118 QFETCH(qreal, wideningAngleMultiplier);
119 QFETCH(qreal, dragDistanceFactor);
120 QFETCH(int, expectedGestureRecognition);
122 QQuickView *view = createView();
123 QScopedPointer<QQuickView> scope(view);
124 view->setSource(QUrl::fromLocalFile("edgeDragExample.qml"));
126 QVERIFY(QTest::qWaitForWindowExposed(view));
127 QVERIFY(view->rootObject() != 0);
128 qApp->processEvents();
130 DirectionalDragArea *edgeDragArea =
131 view->rootObject()->findChild<DirectionalDragArea*>(dragAreaObjectName);
132 QVERIFY(edgeDragArea != 0);
134 QSignalSpy draggingSpy(edgeDragArea, SIGNAL(draggingChanged(bool)));
136 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
137 QPointF touchPoint = initialTouchPos;
139 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*dragDistanceFactor;
140 QPointF dragDirectionVector = calculateDirectionVector(edgeDragArea,
141 wideningAngleMultiplier);
142 QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.1f);
144 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
146 QCOMPARE(draggingSpy.count(), 1);
147 QCOMPARE(edgeDragArea->dragging(), true);
149 if (wideningAngleMultiplier > 0) {
150 // go close to the border of the valid area for this touch point
151 // in order to make it easier to leave it by dragging at an angle
152 // slightly bigger than the widening angle
153 touchPoint += createTouchDeviation(edgeDragArea);
154 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
158 touchPoint += touchMovement;
159 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
160 } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance);
162 if (expectedGestureRecognition)
163 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
165 if (edgeDragArea->status() == DirectionalDragArea::Rejected) {
166 QCOMPARE(edgeDragArea->dragging(), false);
167 QCOMPARE(draggingSpy.count(), 2);
170 QTest::touchEvent(view, device).release(0, touchPoint.toPoint());
172 QCOMPARE(draggingSpy.count(), 2);
173 QCOMPARE(edgeDragArea->dragging(), false);
176void tst_DirectionalDragArea::edgeDrag_data()
178 QTest::addColumn<QString>("dragAreaObjectName");
179 QTest::addColumn<qreal>("wideningAngleMultiplier");
180 QTest::addColumn<qreal>("dragDistanceFactor");
181 QTest::addColumn<int>("expectedGestureRecognition");
183 QTest::newRow("rightwards, tiny drag")
184 << "hpDragArea" << 0.0 << 0.2 << 0;
186 QTest::newRow("rightwards, straight drag")
187 << "hpDragArea" << 0.0 << 3.0 << 1;
189 QTest::newRow("rightwards, diagonal drag")
190 << "hpDragArea" << 0.9 << 3.0 << 1;
192 QTest::newRow("rightwards, overly diagonal drag")
193 << "hpDragArea" << 2.0 << 3.0 << 0;
195 QTest::newRow("leftwards, tiny drag")
196 << "hnDragArea" << 0.0 << 0.2 << 0;
198 QTest::newRow("leftwards, straight drag")
199 << "hnDragArea" << 0.0 << 3.0 << 1;
201 QTest::newRow("leftwards, diagonal drag")
202 << "hnDragArea" << 0.9 << 3.0 << 1;
204 QTest::newRow("downwards, tiny drag")
205 << "vpDragArea" << 0.0 << 0.2 << 0;
207 QTest::newRow("downwards, straight drag")
208 << "vpDragArea" << 0.0 << 3.0 << 1;
210 QTest::newRow("downwards, diagonal drag")
211 << "vpDragArea" << 0.9 << 3.0 << 1;
213 QTest::newRow("upwards, tiny drag")
214 << "vnDragArea" << 0.0 << 0.2 << 0;
216 QTest::newRow("upwards, straight drag")
217 << "vnDragArea" << 0.0 << 3.0 << 1;
219 QTest::newRow("upwards, diagonal drag")
220 << "vnDragArea" << 0.9 << 3.0 << 1;
222 QTest::newRow("upwards, overly diagonal drag")
223 << "vnDragArea" << 2.0 << 3.0 << 0;
227 A directional drag should still be recognized if there is a momentaneous, small,
228 change in the direction of a drag. That should be accounted as input noise and
231void tst_DirectionalDragArea::dragWithShortDirectionChange()
233 QQuickView *view = createView();
234 QScopedPointer<QQuickView> scope(view);
235 view->setSource(QUrl::fromLocalFile("edgeDragExample.qml"));
237 QVERIFY(QTest::qWaitForWindowExposed(view));
238 QVERIFY(view->rootObject() != 0);
239 qApp->processEvents();
241 DirectionalDragArea *edgeDragArea =
242 view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
243 QVERIFY(edgeDragArea != 0);
245 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
246 QPointF touchPoint = initialTouchPos;
248 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0;
249 QPointF dragDirectionVector(1.0, 0.0);
250 QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.1f);
252 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
254 // Move a bit in the proper direction
255 for (int i=0; i < 3; ++i) {
256 touchPoint += touchMovement;
257 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
260 // Then a sudden and small movement to the opposite direction
261 touchPoint -= dragDirectionVector * (edgeDragArea->maxDeviation() * 0.7);
262 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
264 // And then resume movment in the correct direction until it crosses the distance threshold.
266 touchPoint += touchMovement;
267 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
268 } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance);
270 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
272 QTest::touchEvent(view, device).release(0, touchPoint.toPoint());
275QTEST_MAIN(tst_DirectionalDragArea)
277#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