Merge lp:~dandrader/unity8/rotatedDDA into lp:unity8

Proposed by Daniel d'Andrada
Status: Merged
Approved by: Daniel d'Andrada
Approved revision: 693
Merged at revision: 721
Proposed branch: lp:~dandrader/unity8/rotatedDDA
Merge into: lp:unity8
Diff against target: 941 lines (+410/-183)
12 files modified
plugins/Ubuntu/Gestures/DirectionalDragArea.cpp (+105/-45)
plugins/Ubuntu/Gestures/DirectionalDragArea.h (+11/-1)
qml/Components/DragHandle.qml (+2/-1)
tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml (+8/-1)
tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml (+7/-0)
tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml (+7/-0)
tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml (+7/-0)
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp (+108/-17)
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml (+32/-10)
tests/qmltests/Components/tst_DragHandle.cpp (+45/-5)
tests/qmltests/Components/tst_DragHandle.qml (+78/-62)
tests/qmltests/Components/tst_DragHandle/TestButton.qml (+0/-41)
To merge this branch: bzr merge lp:~dandrader/unity8/rotatedDDA
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Gerry Boland (community) Approve
Michael Zanetti (community) Approve
Review via email: mp+205845@code.launchpad.net

Commit message

Make DirectionalDragArea work when rotated

The drag gesture direction is in local coordinates, not in scene coordinates

Description of the change

run "make tryDirectionalDragArea".
Then press the "rotated: 0" button to change it to "rotated: 90".
Try out dragging from the window edges.

Without this patch DirectionalDragAreas would fail recognizing gestures when rotated.

As for "make tryDragHandle", when rotated, the ubuntu logos would never stay open. Once released, they would always rollback.

This is needed for the "rotated nexus 7" work.
I.e.: having a rotated unity8 shell.

e.g.: a landscape unity8 (tablet mode) on a portrait display.

* Are there any related MPs required for this MP to build/function as expected?
  No
* Did you perform an exploratory manual test run of your code change and any related functionality?
 Yes, with "make tryDirectionalDragArea"
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
  Not applicable
* If you changed the UI, has there been a design review?
  Not applicable

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:688
http://jenkins.qa.ubuntu.com/job/unity8-ci/2295/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/3137
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty-touch/2824
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-trusty/1165
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-amd64-ci/816
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/820
        deb: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/820/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-i386-ci/816
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/2756
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/3139
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/3139/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/2826
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/2826/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-runner-mako/5235
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/3848

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/2295/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?

Yip yip. Doesn't seem to break anything on Nexus 4. Gerry will do the test for the new functionality on the rotated Nexus 7.

 * Did CI run pass? If not, please explain why.

Nope :/ Unrelated test failure. It's fix is waiting to be picked up on the Train station still.

review: Approve
Revision history for this message
Gerry Boland (gerboland) wrote :

Works good on rotated shell. Approving

review: Approve
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

There is still a bit more work to be done. Making use of this MP instead of opening another one as it hasn't been merged yet.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

All fixed now.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:693
http://jenkins.qa.ubuntu.com/job/unity8-ci/2306/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/3182
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty-touch/2863
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-trusty/1176
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-amd64-ci/827
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/831
        deb: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/831/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-i386-ci/827
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/2798
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/3184
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/3184/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/2865
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/2865/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-runner-mako/5273
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/3892

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/2306/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

Approving, as works even better on rotated shell than before

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:693
http://jenkins.qa.ubuntu.com/job/unity8-ci/2332/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/3264
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty-touch/2933/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-trusty/1202
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-amd64-ci/853
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/857
        deb: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/857/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-i386-ci/853
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/2872
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/3266
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/3266/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/2935
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/2935/artifact/work/output/*zip*/output.zip
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-runner-mako/5339/console
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/4003

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/2332/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

• Did you perform an exploratory manual test run of the code change and any related functionality?
Yes
• Did CI run pass? If not, please explain why.
It did

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea.cpp'
2--- plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2013-10-23 13:09:39 +0000
3+++ plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2014-02-12 22:13:40 +0000
4@@ -114,6 +114,7 @@
5 , m_wideningAngle(0)
6 , m_wideningFactor(0)
7 , m_distanceThreshold(0)
8+ , m_distanceThresholdSquared(0.)
9 , m_minSpeed(0)
10 , m_maxSilenceTime(200)
11 , m_silenceTime(0)
12@@ -162,7 +163,14 @@
13 return;
14
15 m_wideningAngle = angle;
16- m_wideningFactor = qTan(angle * M_PI / 180.0);
17+
18+ // wideningFactor = pow(cosine(angle), 2)
19+ {
20+ qreal angleRadians = angle * M_PI / 180.0;
21+ m_wideningFactor = qCos(angleRadians);
22+ m_wideningFactor = m_wideningFactor * m_wideningFactor;
23+ }
24+
25 Q_EMIT wideningAngleChanged(angle);
26 }
27
28@@ -170,6 +178,7 @@
29 {
30 if (m_distanceThreshold != value) {
31 m_distanceThreshold = value;
32+ m_distanceThresholdSquared = m_distanceThreshold * m_distanceThreshold;
33 Q_EMIT distanceThresholdChanged(value);
34 }
35 }
36@@ -237,13 +246,15 @@
37 }
38 }
39
40+void DirectionalDragArea::updateSceneDistance()
41+{
42+ QPointF totalMovement = m_previousScenePos - m_startScenePos;
43+ m_sceneDistance = projectOntoDirectionVector(totalMovement);
44+}
45+
46 qreal DirectionalDragArea::sceneDistance() const
47 {
48- if (Direction::isHorizontal(m_direction)) {
49- return m_previousScenePos.x() - m_startScenePos.x();
50- } else {
51- return m_previousScenePos.y() - m_startScenePos.y();
52- }
53+ return m_sceneDistance;
54 }
55
56 qreal DirectionalDragArea::touchX() const
57@@ -335,12 +346,13 @@
58 m_startScenePos = newTouchPoint->scenePos();
59 m_touchId = newTouchPoint->id();
60 m_dampedScenePos.reset(m_startScenePos);
61- updateVelocityCalculator(m_startScenePos);
62+ m_velocityCalculator->setTrackedPosition(0.);
63 m_velocityCalculator->reset();
64 m_numSamplesOnLastSpeedCheck = 0;
65 m_silenceTime = 0;
66 setPreviousPos(m_startPos);
67 setPreviousScenePos(m_startScenePos);
68+ updateSceneDirectionVector();
69
70 setStatus(Undecided);
71 }
72@@ -441,44 +453,53 @@
73
74 bool DirectionalDragArea::pointInsideAllowedArea() const
75 {
76- qreal dX = m_dampedScenePos.x() - m_startScenePos.x();
77- qreal dY = m_dampedScenePos.y() - m_startScenePos.y();
78-
79- switch (m_direction) {
80- case Direction::Upwards:
81- return dY <= 0 && qFabs(dX) <= qFabs(dY) * m_wideningFactor;
82- case Direction::Downwards:
83- return dY >= 0 && qFabs(dX) <= dY * m_wideningFactor;
84- case Direction::Leftwards:
85- return dX <= 0 && qFabs(dY) <= qFabs(dX) * m_wideningFactor;
86- default: // Direction::Rightwards:
87- return dX >= 0 && qFabs(dY) <= dX * m_wideningFactor;
88+ // NB: Using squared values to avoid computing the square root to find
89+ // the length totalMovement
90+
91+ QPointF totalMovement(m_dampedScenePos.x() - m_startScenePos.x(),
92+ m_dampedScenePos.y() - m_startScenePos.y());
93+
94+ qreal squaredTotalMovSize = totalMovement.x() * totalMovement.x() +
95+ totalMovement.y() * totalMovement.y();
96+
97+ if (squaredTotalMovSize == 0.) {
98+ // didn't move
99+ return true;
100 }
101+
102+ qreal projectedMovement = projectOntoDirectionVector(totalMovement);
103+
104+
105+ qreal cosineAngleSquared = (projectedMovement * projectedMovement) / squaredTotalMovSize;
106+
107+ // Same as:
108+ // angle_between_movement_vector_and_gesture_direction_vector <= widening_angle
109+ return cosineAngleSquared >= m_wideningFactor;
110 }
111
112 bool DirectionalDragArea::movingInRightDirection() const
113 {
114- switch (m_direction) {
115- case Direction::Upwards:
116- return m_dampedScenePos.y() <= m_previousDampedScenePos.y();
117- case Direction::Downwards:
118- return m_dampedScenePos.y() >= m_previousDampedScenePos.y();
119- case Direction::Leftwards:
120- return m_dampedScenePos.x() <= m_previousDampedScenePos.x();
121- default: // Direction::Rightwards:
122- return m_dampedScenePos.x() >= m_previousDampedScenePos.x();
123- }
124+ QPointF movementVector(m_dampedScenePos.x() - m_previousDampedScenePos.x(),
125+ m_dampedScenePos.y() - m_previousDampedScenePos.y());
126+
127+ qreal scalarProjection = projectOntoDirectionVector(movementVector);
128+
129+ return scalarProjection >= 0.;
130 }
131
132 bool DirectionalDragArea::movedFarEnough(const QPointF &point) const
133 {
134- if (m_distanceThreshold > 0) {
135- if (Direction::isHorizontal(m_direction))
136- return qFabs(point.x() - m_startScenePos.x()) > m_distanceThreshold;
137- else
138- return qFabs(point.y() - m_startScenePos.y()) > m_distanceThreshold;
139+ if (m_distanceThreshold <= 0.) {
140+ // distance threshold check is disabled
141+ return true;
142 } else {
143- return true;
144+ QPointF totalMovement(point.x() - m_startScenePos.x(),
145+ point.y() - m_startScenePos.y());
146+
147+ qreal squaredTotalMovSize = totalMovement.x() * totalMovement.x() +
148+ totalMovement.y() * totalMovement.y();
149+
150+ return squaredTotalMovSize > m_distanceThresholdSquared;
151 }
152 }
153
154@@ -568,28 +589,33 @@
155 bool xChanged = m_previousScenePos.x() != point.x();
156 bool yChanged = m_previousScenePos.y() != point.y();
157
158+ if (!xChanged && !yChanged)
159+ return;
160+
161+ qreal oldSceneDistance = sceneDistance();
162 m_previousScenePos = point;
163+ updateSceneDistance();
164+
165+ if (oldSceneDistance != sceneDistance()) {
166+ Q_EMIT sceneDistanceChanged(sceneDistance());
167+ }
168
169 if (xChanged) {
170 Q_EMIT touchSceneXChanged(point.x());
171- if (Direction::isHorizontal(m_direction))
172- Q_EMIT sceneDistanceChanged(sceneDistance());
173 }
174
175 if (yChanged) {
176 Q_EMIT touchSceneYChanged(point.y());
177- if (Direction::isVertical(m_direction))
178- Q_EMIT sceneDistanceChanged(sceneDistance());
179 }
180 }
181
182-void DirectionalDragArea::updateVelocityCalculator(const QPointF &point)
183+void DirectionalDragArea::updateVelocityCalculator(const QPointF &scenePos)
184 {
185- if (Direction::isHorizontal(m_direction)) {
186- m_velocityCalculator->setTrackedPosition(point.x());
187- } else {
188- m_velocityCalculator->setTrackedPosition(point.y());
189- }
190+ QPointF totalSceneMovement = scenePos - m_startScenePos;
191+
192+ qreal scalarProjection = projectOntoDirectionVector(totalSceneMovement);
193+
194+ m_velocityCalculator->setTrackedPosition(scalarProjection);
195 }
196
197 bool DirectionalDragArea::isWithinTouchCompositionWindow()
198@@ -693,5 +719,39 @@
199 return highestStartTime;
200 }
201
202+void DirectionalDragArea::updateSceneDirectionVector()
203+{
204+ QPointF localOrigin(0., 0.);
205+ QPointF localDirection;
206+ switch (m_direction) {
207+ case Direction::Upwards:
208+ localDirection.rx() = 0.;
209+ localDirection.ry() = -1.;
210+ break;
211+ case Direction::Downwards:
212+ localDirection.rx() = 0.;
213+ localDirection.ry() = 1;
214+ break;
215+ case Direction::Leftwards:
216+ localDirection.rx() = -1.;
217+ localDirection.ry() = 0.;
218+ break;
219+ default: // Direction::Rightwards:
220+ localDirection.rx() = 1.;
221+ localDirection.ry() = 0.;
222+ break;
223+ }
224+ QPointF sceneOrigin = mapToScene(localOrigin);
225+ QPointF sceneDirection = mapToScene(localDirection);
226+ m_sceneDirectionVector = sceneDirection - sceneOrigin;
227+}
228+
229+qreal DirectionalDragArea::projectOntoDirectionVector(const QPointF &sceneVector) const
230+{
231+ // same as dot product as m_sceneDirectionVector is a unit vector
232+ return sceneVector.x() * m_sceneDirectionVector.x() +
233+ sceneVector.y() * m_sceneDirectionVector.y();
234+}
235+
236 // Because we are defining a new QObject-based class (RecognitionTimer) here.
237 #include "DirectionalDragArea.moc"
238
239=== modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea.h'
240--- plugins/Ubuntu/Gestures/DirectionalDragArea.h 2013-10-23 13:09:39 +0000
241+++ plugins/Ubuntu/Gestures/DirectionalDragArea.h 2014-02-12 22:13:40 +0000
242@@ -160,6 +160,7 @@
243
244 qreal distance() const;
245 qreal sceneDistance() const;
246+ void updateSceneDistance();
247
248 qreal touchX() const;
249 qreal touchY() const;
250@@ -231,6 +232,10 @@
251 void setPreviousScenePos(const QPointF &point);
252 void updateVelocityCalculator(const QPointF &point);
253 bool isWithinTouchCompositionWindow();
254+ void updateSceneDirectionVector();
255+ // returns the scalar projection between the given vector (in scene coordinates)
256+ // and m_sceneDirectionVector
257+ qreal projectOntoDirectionVector(const QPointF &sceneVector) const;
258
259 Status m_status;
260
261@@ -238,6 +243,7 @@
262 QPointF m_startScenePos;
263 QPointF m_previousPos;
264 QPointF m_previousScenePos;
265+ qreal m_sceneDistance;
266 int m_touchId;
267
268 // A movement damper is used in some of the gesture recognition calculations
269@@ -245,10 +251,14 @@
270 DampedPointF m_dampedScenePos;
271 QPointF m_previousDampedScenePos;
272
273+ // Unit vector in scene coordinates describing the direction of the gesture recognition
274+ QPointF m_sceneDirectionVector;
275+
276 Direction::Type m_direction;
277 qreal m_wideningAngle; // in degrees
278- qreal m_wideningFactor; // it's tan(degreesToRadian(m_wideningAngle))
279+ qreal m_wideningFactor; // it's pow(cosine(m_wideningAngle), 2)
280 qreal m_distanceThreshold;
281+ qreal m_distanceThresholdSquared; // it's pow(m_distanceThreshold, 2)
282 qreal m_minSpeed;
283 int m_maxSilenceTime; // in milliseconds
284 int m_silenceTime; // in milliseconds
285
286=== modified file 'qml/Components/DragHandle.qml'
287--- qml/Components/DragHandle.qml 2014-01-21 15:30:06 +0000
288+++ qml/Components/DragHandle.qml 2014-02-12 22:13:40 +0000
289@@ -167,7 +167,8 @@
290 EdgeDragEvaluator {
291 objectName: "edgeDragEvaluator"
292 id: dragEvaluator
293- trackedPosition: sceneDistance
294+ // Effectively convert distance into the drag position projected onto the gesture direction axis
295+ trackedPosition: Direction.isPositive(dragArea.direction) ? sceneDistance : -sceneDistance
296 maxDragDistance: maxTotalDragDistance
297 direction: dragArea.direction
298 }
299
300=== modified file 'tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml'
301--- tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml 2013-10-22 15:56:37 +0000
302+++ tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml 2014-02-12 22:13:40 +0000
303@@ -63,7 +63,7 @@
304 dragAreaRect.opacity = 0.3
305 launcher.y = Qt.binding(launcher.followDragArea)
306 break;
307- defaut: // DirectionalDragArea.Recognized:
308+ default: // DirectionalDragArea.Recognized:
309 dragAreaRect.color = "green"
310 dragAreaRect.opacity = 0.5
311 break;
312@@ -76,4 +76,11 @@
313 top: parent.top
314 }
315 }
316+
317+ Label {
318+ text: "Downwards"
319+ anchors.top: parent.top
320+ anchors.horizontalCenter: parent.horizontalCenter
321+ anchors.topMargin: units.gu(1)
322+ }
323 }
324
325=== modified file 'tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml'
326--- tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml 2013-10-22 15:56:37 +0000
327+++ tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml 2014-02-12 22:13:40 +0000
328@@ -79,4 +79,11 @@
329 bottom: parent.bottom
330 }
331 }
332+
333+ Label {
334+ text: "Leftwards"
335+ anchors.right: parent.right
336+ anchors.verticalCenter: parent.verticalCenter
337+ anchors.rightMargin: units.gu(1)
338+ }
339 }
340
341=== modified file 'tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml'
342--- tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml 2013-10-22 15:56:37 +0000
343+++ tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml 2014-02-12 22:13:40 +0000
344@@ -77,4 +77,11 @@
345 bottom: parent.bottom
346 }
347 }
348+
349+ Label {
350+ text: "Rightwards"
351+ anchors.left: parent.left
352+ anchors.verticalCenter: parent.verticalCenter
353+ anchors.leftMargin: units.gu(1)
354+ }
355 }
356
357=== modified file 'tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml'
358--- tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml 2013-10-22 15:56:37 +0000
359+++ tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml 2014-02-12 22:13:40 +0000
360@@ -79,4 +79,11 @@
361 bottom: parent.bottom
362 }
363 }
364+
365+ Label {
366+ text: "Upwards"
367+ anchors.bottom: parent.bottom
368+ anchors.horizontalCenter: parent.horizontalCenter
369+ anchors.bottomMargin: units.gu(1)
370+ }
371 }
372
373=== modified file 'tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp'
374--- tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp 2013-11-22 13:37:25 +0000
375+++ tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp 2014-02-12 22:13:40 +0000
376@@ -83,6 +83,9 @@
377 void twoFingerTap();
378 void movingDDA();
379 void ignoreOldFinger();
380+ void rotated();
381+ void sceneDistance();
382+ void sceneDistance_data();
383
384 private:
385 void passTime(qint64 timeSpan);
386@@ -131,18 +134,10 @@
387 }
388
389 namespace {
390-QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea, QQuickView *view)
391+QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea)
392 {
393- switch (edgeDragArea->direction()) {
394- case Direction::Upwards:
395- return QPointF(view->width()/2.0f, view->height() - (edgeDragArea->height()/2.0f));
396- case Direction::Downwards:
397- return QPointF(view->width()/2.0f, edgeDragArea->height()/2.0f);
398- case Direction::Leftwards:
399- return QPointF(view->width() - (edgeDragArea->width()/2.0f), view->height()/2.0f);
400- default: // Direction::Rightwards:
401- return QPointF(edgeDragArea->width()/2.0f, view->height()/2.0f);
402- }
403+ QPointF localCenter(edgeDragArea->width() / 2., edgeDragArea->height() / 2.);
404+ return edgeDragArea->mapToScene(localCenter);
405 }
406
407 QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea,
408@@ -193,7 +188,7 @@
409
410 QSignalSpy draggingSpy(edgeDragArea, SIGNAL(draggingChanged(bool)));
411
412- QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
413+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
414 QPointF touchPoint = initialTouchPos;
415
416 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*dragDistanceFactor;
417@@ -300,7 +295,7 @@
418 edgeDragArea->setRecognitionTimer(fakeTimer);
419 edgeDragArea->setTimeSource(fakeTimeSource);
420
421- QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
422+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
423 QPointF touchPoint = initialTouchPos;
424
425 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0;
426@@ -360,7 +355,7 @@
427
428 edgeDragArea->setMinSpeed(minSpeed);
429
430- QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
431+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
432 QPointF touchPoint = initialTouchPos;
433
434 QPointF dragDirectionVector(1.0, 0.0);
435@@ -408,7 +403,7 @@
436
437 int timeStepMs = 5; // some arbitrary small value.
438
439- QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
440+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
441 QPointF touchPoint = initialTouchPos;
442
443 QPointF dragDirectionVector(1.0, 0.0);
444@@ -452,7 +447,7 @@
445 // Make sure this property is not disabled
446 edgeDragArea->setMaxSilenceTime(100);
447
448- QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
449+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
450 QPointF touchPoint = initialTouchPos;
451
452 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
453@@ -620,7 +615,7 @@
454 edgeDragArea->setRecognitionTimer(fakeTimer);
455 edgeDragArea->setTimeSource(fakeTimeSource);
456
457- QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
458+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
459 QPointF touchPoint = initialTouchPos;
460
461 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
462@@ -704,6 +699,102 @@
463 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
464 }
465
466+/*
467+ A Rightwards DDA that is rotated 90 degrees clockwise should recognize gestures
468+ that are done downwards in scene coordinates. I.e. the gesture recognition direction
469+ should be in local coordinates, not scene coordinates.
470+ */
471+void tst_DirectionalDragArea::rotated()
472+{
473+ QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
474+ baseItem->setRotation(90.);
475+
476+ QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
477+ Q_ASSERT(rightwardsLauncher != 0);
478+
479+ DirectionalDragArea *edgeDragArea =
480+ rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
481+ Q_ASSERT(edgeDragArea != 0);
482+ edgeDragArea->setRecognitionTimer(fakeTimer);
483+ edgeDragArea->setTimeSource(fakeTimeSource);
484+
485+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
486+ QPointF touchPoint = initialTouchPos;
487+
488+ qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
489+ QPointF dragDirectionVector(0.0f, 1.0f);
490+
491+ qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
492+ QPointF touchMovement = dragDirectionVector * movementStepDistance;
493+ int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
494+ int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
495+
496+ QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
497+
498+ for (int i = 0; i < totalMovementSteps; ++i) {
499+ touchPoint += touchMovement;
500+ passTime(movementTimeStepMs);
501+ QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
502+ }
503+
504+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
505+
506+ QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
507+}
508+
509+void tst_DirectionalDragArea::sceneDistance()
510+{
511+ QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
512+ QFETCH(qreal, rotation);
513+ QFETCH(QPointF, dragDirectionVector);
514+ baseItem->setRotation(rotation);
515+
516+ QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
517+ Q_ASSERT(rightwardsLauncher != 0);
518+
519+ DirectionalDragArea *edgeDragArea =
520+ rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
521+ Q_ASSERT(edgeDragArea != 0);
522+ edgeDragArea->setRecognitionTimer(fakeTimer);
523+ edgeDragArea->setTimeSource(fakeTimeSource);
524+
525+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
526+ QPointF touchPoint = initialTouchPos;
527+
528+ qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
529+
530+ qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
531+ QPointF touchMovement = dragDirectionVector * movementStepDistance;
532+ int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
533+ int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
534+
535+ QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
536+
537+ for (int i = 0; i < totalMovementSteps; ++i) {
538+ touchPoint += touchMovement;
539+ passTime(movementTimeStepMs);
540+ QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
541+ }
542+
543+ qreal actualDragDistance = ((qreal)totalMovementSteps) * movementStepDistance;
544+
545+ // DirectionalDragArea::sceneDistance() must match the actual drag distance as the
546+ // drag was aligned with the gesture direction
547+ // NB: qFuzzyCompare(), used internally by QCOMPARE(), is broken.
548+ QVERIFY(qAbs(edgeDragArea->sceneDistance() - actualDragDistance) < 0.001);
549+
550+ QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
551+}
552+
553+void tst_DirectionalDragArea::sceneDistance_data()
554+{
555+ QTest::addColumn<qreal>("rotation");
556+ QTest::addColumn<QPointF>("dragDirectionVector");
557+
558+ QTest::newRow("not rotated") << 0. << QPointF(1., 0.);
559+ QTest::newRow("rotated by 90 degrees") << 90. << QPointF(0., 1.);
560+}
561+
562 QTEST_MAIN(tst_DirectionalDragArea)
563
564 #include "tst_DirectionalDragArea.moc"
565
566=== modified file 'tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml'
567--- tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml 2013-11-22 11:28:28 +0000
568+++ tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml 2014-02-12 22:13:40 +0000
569@@ -18,8 +18,8 @@
570 import Ubuntu.Components 0.1
571
572 Rectangle {
573- width: units.gu(40)
574- height: units.gu(71)
575+ width: units.gu(60)
576+ height: units.gu(60)
577 color: "white"
578
579 MouseArea {
580@@ -33,14 +33,36 @@
581 }
582 }
583
584- // NB: Do not anchor it as we will move it programmatically from the test
585- RightwardsLauncher {
586- id: hpLauncher;
587+ Item {
588+ id: baseItem
589+ objectName: "baseItem"
590 width: parent.width
591 height: parent.height
592- }
593-
594- LeftwardsLauncher { id: hnLauncher; anchors.fill: parent }
595- DownwardsLauncher { id: vpLauncher; anchors.fill: parent }
596- UpwardsLauncher { id: vnLauncher; anchors.fill: parent }
597+
598+ // NB: Do not anchor it as we will move it programmatically from the test
599+ RightwardsLauncher {
600+ id: hpLauncher;
601+ width: parent.width
602+ height: parent.height
603+ }
604+
605+ LeftwardsLauncher { id: hnLauncher; anchors.fill: parent }
606+ DownwardsLauncher { id: vpLauncher; anchors.fill: parent }
607+ UpwardsLauncher { id: vnLauncher; anchors.fill: parent }
608+ }
609+
610+ Button {
611+ anchors.bottom: parent.bottom
612+ anchors.left: parent.left
613+ anchors.margins: units.gu(1)
614+
615+ text: "rotation: " + baseItem.rotation
616+ onClicked: {
617+ if (baseItem.rotation === 0.0) {
618+ baseItem.rotation = 90.0
619+ } else {
620+ baseItem.rotation = 0.0
621+ }
622+ }
623+ }
624 }
625
626=== modified file 'tests/qmltests/Components/tst_DragHandle.cpp'
627--- tests/qmltests/Components/tst_DragHandle.cpp 2014-01-21 15:29:34 +0000
628+++ tests/qmltests/Components/tst_DragHandle.cpp 2014-02-12 22:13:40 +0000
629@@ -58,7 +58,9 @@
630 void cleanup(); // called right after each and every test function is executed
631
632 void dragThreshold_horizontal();
633+ void dragThreshold_horizontal_data();
634 void dragThreshold_vertical();
635+ void dragThreshold_vertical_data();
636 void stretch_horizontal();
637 void stretch_vertical();
638 void hintingAnimation();
639@@ -145,17 +147,29 @@
640 namespace {
641 QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
642 {
643-
644+ QPointF localOrigin(0., 0.);
645+ QPointF localDirection;
646 switch (edgeDragArea->direction()) {
647 case Direction::Upwards:
648- return QPointF(0, -1);
649+ localDirection.rx() = 0.;
650+ localDirection.ry() = -1.;
651+ break;
652 case Direction::Downwards:
653- return QPointF(0, 1);
654+ localDirection.rx() = 0.;
655+ localDirection.ry() = 1;
656+ break;
657 case Direction::Leftwards:
658- return QPointF(-1, 0);
659+ localDirection.rx() = -1.;
660+ localDirection.ry() = 0.;
661+ break;
662 default: // Direction::Rightwards:
663- return QPointF(1, 0);
664+ localDirection.rx() = 1.;
665+ localDirection.ry() = 0.;
666+ break;
667 }
668+ QPointF sceneOrigin = edgeDragArea->mapToScene(localOrigin);
669+ QPointF sceneDirection = edgeDragArea->mapToScene(localDirection);
670+ return sceneDirection - sceneOrigin;
671 }
672 }
673
674@@ -222,6 +236,11 @@
675 */
676 void tst_DragHandle::dragThreshold_horizontal()
677 {
678+ QFETCH(qreal, rotation);
679+
680+ QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
681+ baseItem->setRotation(rotation);
682+
683 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
684
685 qreal dragThreshold = fetchDragThreshold(dragHandle);
686@@ -260,8 +279,21 @@
687 QCOMPARE(parentItem->property("shown").toBool(), false);
688 }
689
690+void tst_DragHandle::dragThreshold_horizontal_data()
691+{
692+ QTest::addColumn<qreal>("rotation");
693+
694+ QTest::newRow("not rotated") << 0.;
695+ QTest::newRow("rotated 90") << 90.;
696+}
697+
698 void tst_DragHandle::dragThreshold_vertical()
699 {
700+ QFETCH(qreal, rotation);
701+
702+ QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
703+ baseItem->setRotation(rotation);
704+
705 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
706
707 qreal dragThreshold = fetchDragThreshold(dragHandle);
708@@ -300,6 +332,14 @@
709 QCOMPARE(parentItem->property("shown").toBool(), false);
710 }
711
712+void tst_DragHandle::dragThreshold_vertical_data()
713+{
714+ QTest::addColumn<qreal>("rotation");
715+
716+ QTest::newRow("not rotated") << 0.;
717+ QTest::newRow("rotated 90") << 90.;
718+}
719+
720 /*
721 Checks that when the stretch property is true, dragging the DragHandle increases
722 the width or height (depending on its direction) of its parent Showable
723
724=== modified file 'tests/qmltests/Components/tst_DragHandle.qml'
725--- tests/qmltests/Components/tst_DragHandle.qml 2013-12-17 16:04:47 +0000
726+++ tests/qmltests/Components/tst_DragHandle.qml 2014-02-12 22:13:40 +0000
727@@ -29,62 +29,68 @@
728 */
729 Item {
730 id: root
731- width: 700
732- height: 500
733+ width: units.gu(70)
734+ height: units.gu(70)
735
736 property var dragHandle
737
738 property bool stretch: false
739 property real hintDisplacement: 0
740
741- VerticalShowable {
742- onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
743- stretch: root.stretch
744- hintDisplacement: root.hintDisplacement
745- }
746-
747- HorizontalShowable {
748- onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
749- stretch: root.stretch
750- hintDisplacement: root.hintDisplacement
751- }
752-
753- // Visually mark drag threshold
754- Rectangle {
755- color: "black"
756- width: 2
757- height: parent.height
758-
759- visible: dragHandle !== undefined && Direction.isHorizontal(dragHandle.direction)
760-
761- x: {
762- if (dragHandle) {
763- if (dragHandle.direction === Direction.Rightwards) {
764- dragHandle.edgeDragEvaluator.dragThreshold;
765+ Item {
766+ id: baseItem
767+ objectName: "baseItem"
768+ anchors.fill: parent
769+
770+ VerticalShowable {
771+ onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
772+ stretch: root.stretch
773+ hintDisplacement: root.hintDisplacement
774+ }
775+
776+ HorizontalShowable {
777+ onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
778+ stretch: root.stretch
779+ hintDisplacement: root.hintDisplacement
780+ }
781+
782+ // Visually mark drag threshold
783+ Rectangle {
784+ color: "black"
785+ width: 2
786+ height: parent.height
787+
788+ visible: dragHandle !== undefined && Direction.isHorizontal(dragHandle.direction)
789+
790+ x: {
791+ if (dragHandle) {
792+ if (dragHandle.direction === Direction.Rightwards) {
793+ dragHandle.edgeDragEvaluator.dragThreshold;
794+ } else {
795+ parent.width - dragHandle.edgeDragEvaluator.dragThreshold;
796+ }
797 } else {
798- parent.width - dragHandle.edgeDragEvaluator.dragThreshold;
799+ 0
800 }
801- } else {
802- 0
803 }
804 }
805- }
806- Rectangle {
807- color: "black";
808- height: 2
809- width: parent.width
810-
811- visible: dragHandle !== undefined && Direction.isVertical(dragHandle.direction)
812-
813- y: {
814- if (dragHandle) {
815- if (dragHandle.direction === Direction.Downwards) {
816- dragHandle.edgeDragEvaluator.dragThreshold;
817+ Rectangle {
818+ color: "black";
819+ height: 2
820+ width: parent.width
821+
822+ visible: dragHandle !== undefined && Direction.isVertical(dragHandle.direction)
823+
824+ y: {
825+ if (dragHandle) {
826+ if (dragHandle.direction === Direction.Downwards) {
827+ dragHandle.edgeDragEvaluator.dragThreshold;
828+ } else {
829+ parent.height - dragHandle.edgeDragEvaluator.dragThreshold;
830+ }
831 } else {
832- parent.height - dragHandle.edgeDragEvaluator.dragThreshold;
833+ 0
834 }
835- } else {
836- 0
837 }
838 }
839 }
840@@ -119,27 +125,37 @@
841 }
842 }
843
844- TestButton {
845- id: stretchButton
846+ Row {
847 anchors.bottom: parent.bottom
848 anchors.left: parent.left
849 anchors.margins: units.gu(1)
850-
851- text: root.stretch ? "stretch" : "move"
852- onClicked: { root.stretch = !root.stretch; }
853- }
854-
855- TestButton {
856- anchors.bottom: parent.bottom
857- anchors.left: stretchButton.right
858- anchors.margins: units.gu(1)
859-
860- text: root.hintDisplacement > 0 ? "hint" : "no hint"
861- onClicked: {
862- if (root.hintDisplacement > 0) {
863- root.hintDisplacement = 0;
864- } else {
865- root.hintDisplacement = units.gu(6);
866+ spacing: units.gu(1)
867+
868+ Button {
869+ id: stretchButton
870+ text: root.stretch ? "stretch" : "move"
871+ onClicked: { root.stretch = !root.stretch; }
872+ }
873+
874+ Button {
875+ text: root.hintDisplacement > 0 ? "hint" : "no hint"
876+ onClicked: {
877+ if (root.hintDisplacement > 0) {
878+ root.hintDisplacement = 0;
879+ } else {
880+ root.hintDisplacement = units.gu(6);
881+ }
882+ }
883+ }
884+
885+ Button {
886+ text: "rotation: " + baseItem.rotation
887+ onClicked: {
888+ if (baseItem.rotation === 0.0) {
889+ baseItem.rotation = 90.0
890+ } else {
891+ baseItem.rotation = 0.0
892+ }
893 }
894 }
895 }
896
897=== removed file 'tests/qmltests/Components/tst_DragHandle/TestButton.qml'
898--- tests/qmltests/Components/tst_DragHandle/TestButton.qml 2013-07-01 16:32:00 +0000
899+++ tests/qmltests/Components/tst_DragHandle/TestButton.qml 1970-01-01 00:00:00 +0000
900@@ -1,41 +0,0 @@
901-/*
902- * Copyright (C) 2013 Canonical, Ltd.
903- *
904- * This program is free software; you can redistribute it and/or modify
905- * it under the terms of the GNU General Public License as published by
906- * the Free Software Foundation; version 3.
907- *
908- * This program is distributed in the hope that it will be useful,
909- * but WITHOUT ANY WARRANTY; without even the implied warranty of
910- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
911- * GNU General Public License for more details.
912- *
913- * You should have received a copy of the GNU General Public License
914- * along with this program. If not, see <http://www.gnu.org/licenses/>.
915- */
916-
917-import QtQuick 2.0
918-import Ubuntu.Components 0.1
919-
920-Rectangle {
921- id: rect
922- width: childrenRect.width
923- height: childrenRect.height
924-
925- property alias text: textComponent.text
926-
927- signal clicked
928-
929- color: "yellow"
930- Text {
931- id: textComponent
932- font.pixelSize: units.gu(2)
933- text: root.stretch ? "stretch" : "move"
934- MouseArea {
935- anchors.fill: parent
936- onClicked: {
937- rect.clicked()
938- }
939- }
940- }
941-}

Subscribers

People subscribed via source and target branches