Merge lp:~dandrader/unity8/ddaImprovements into lp:unity8
- ddaImprovements
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~dandrader/unity8/ddaImprovements |
Merge into: | lp:unity8 |
Diff against target: |
5424 lines (+1721/-1505) 47 files modified
libs/UbuntuGestures/CMakeLists.txt (+1/-0) libs/UbuntuGestures/CandidateInactivityTimer.h (+1/-1) libs/UbuntuGestures/TimeSource.h (+14/-4) libs/UbuntuGestures/Timer.cpp (+67/-14) libs/UbuntuGestures/Timer.h (+15/-3) libs/UbuntuGestures/TouchRegistry.cpp (+12/-14) libs/UbuntuGestures/TouchRegistry.h (+18/-4) plugins/Ubuntu/Gestures/CMakeLists.txt (+1/-1) plugins/Ubuntu/Gestures/Damper.cpp (+24/-0) plugins/Ubuntu/Gestures/Damper.h (+2/-0) plugins/Ubuntu/Gestures/DirectionalDragArea.cpp (+349/-363) plugins/Ubuntu/Gestures/DirectionalDragArea.h (+19/-208) plugins/Ubuntu/Gestures/DirectionalDragArea_p.h (+167/-0) plugins/Ubuntu/Gestures/TouchDispatcher.cpp (+88/-53) plugins/Ubuntu/Gestures/TouchDispatcher.h (+16/-9) plugins/Ubuntu/Gestures/TouchGate.cpp (+87/-63) plugins/Ubuntu/Gestures/TouchGate.h (+18/-5) qml/Components/DragHandle.qml (+20/-35) qml/Components/EdgeDragArea.qml (+0/-46) qml/Dash/Dash.qml (+5/-12) qml/Greeter/CoverPage.qml (+1/-0) qml/Launcher/Launcher.qml (+6/-14) qml/Panel/IndicatorsMenu.qml (+12/-2) qml/Stages/PhoneStage.qml (+33/-43) qml/Stages/TabletStage.qml (+19/-21) qml/Tutorial/TutorialBottom.qml (+1/-1) tests/libs/UbuntuGestures/tst_TouchRegistry.cpp (+68/-2) tests/plugins/Ubuntu/Gestures/CMakeLists.txt (+3/-1) tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml (+5/-19) tests/plugins/Ubuntu/Gestures/GestureTest.cpp (+13/-3) tests/plugins/Ubuntu/Gestures/GestureTest.h (+4/-0) tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml (+6/-19) tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml (+5/-19) tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml (+6/-19) tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp (+496/-461) tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml (+8/-1) tests/plugins/Ubuntu/Gestures/tst_TouchDispatcher.cpp (+5/-6) tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp (+56/-1) tests/qmltests/Components/CMakeLists.txt (+3/-1) tests/qmltests/Components/tst_DragHandle.cpp (+15/-13) tests/qmltests/Components/tst_DragHandle.qml (+7/-0) tests/qmltests/Components/tst_DragHandle/BidirectionalShowable.qml (+2/-2) tests/qmltests/Components/tst_DragHandle/HorizontalShowable.qml (+4/-4) tests/qmltests/Components/tst_DragHandle/VerticalShowable.qml (+4/-4) tests/qmltests/Stages/tst_PhoneStage.qml (+8/-8) tests/qmltests/Tutorial/tst_Tutorial.qml (+5/-1) tests/utils/modules/Unity/Test/UnityTestCase.qml (+2/-5) |
To merge this branch: | bzr merge lp:~dandrader/unity8/ddaImprovements |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Albert Astals Cid (community) | Approve | ||
Michał Sawicz | Abstain | ||
Review via email: mp+254964@code.launchpad.net |
This proposal has been superseded by a proposal from 2015-04-10.
Commit message
Several improvements to Ubuntu.Gestures
-Simplified DirectionalDragArea gesture recognition
- The widening angle property was dropped. Didn't really work
as in real life swipes might start up in very different directions
before finally turning to the final overall direction. That's specially
bad when you have to conclude the recognition in a short amount
of time so that you can still play animations to follow the user's finger
- minSpeed as well. Went for a simpler way of expressing and evaluating it
which is having maxTime and maxDistance.
-EdgeDragArea
- Fine-tuned parameters and made them based on physical size.
- Added tests with input from real gestures to catch those annoying
false-negatives and false-positives introduced by badly set recognition parameters
-Improved debug output
-UnownedTouchEvents are no longer sent to interim owners
-Fixed issue when TouchGate got disabled while holding an active touch
Description of the change
Need for fixing bug 1417920.
The way parameters are currently set in EdgeDragArea, a gesture gets recognized regardless of its direction, it only have to be dragged far enough.
* Are there any related MPs required for this MP to build/function as expected? Please list.
No.
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes.
* Did you make sure that your branch does not contain spurious tags?
Yes.
* 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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1706
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1705. By Launchpad Translations on behalf of unity-team
-
Launchpad automatic translations update.
Michał Sawicz (saviq) wrote : | # |
Failed QML tests:
qmltestrunn
qmltestrunn
qmltestrunn
Daniel d'Andrada (dandrader) wrote : | # |
> Failed QML tests:
> qmltestrunner.
> qmltestrunner.
> qmltestrunner.
Fixed.
Michał Sawicz (saviq) : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1707
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1706. By Launchpad Translations on behalf of unity-team
-
Launchpad automatic translations update.
- 1707. By Launchpad Translations on behalf of unity-team
-
Launchpad automatic translations update.
- 1708. By Launchpad Translations on behalf of unity-team
-
Launchpad automatic translations update.
- 1709. By Launchpad Translations on behalf of unity-team
-
Launchpad automatic translations update.
Albert Astals Cid (aacid) wrote : | # |
This does not actually fix the linked bug right?
Any way to test this change?
Daniel d'Andrada (dandrader) wrote : | # |
> This does not actually fix the linked bug right?
>
> Any way to test this change?
It does, but you have to make Launcher's EdgeDragArea cover the whole launcher in order to notice it.
=== modified file 'qml/Launcher/
--- qml/Launcher/
+++ qml/Launcher/
@@ -280,7 +280,7 @@ Item {
enabled: root.available
x: -root.x // so if launcher is adjusted relative to screen, we stay put (like tutorial does when teasing)
- width: root.dragAreaWidth
+ width: root.panelWidth
height: root.height
Apply diff the diff above to trunk and try to scroll the launcher icons. It won't work.
Then merge this branch and try again. It will work.
And check that all DDAs still work normally
- show and hide indicators panel
- right-edge drag to show the spread
- left-edge drag to show launcher
- horizontal drag to dismiss the greeter
- bottom edge drag to show the "manage dash" UI.
Albert Astals Cid (aacid) wrote : | # |
Can you confirm that doing http://
I just tried and it still closes when i swipe vertically over an open Launcher.
Daniel d'Andrada (dandrader) wrote : | # |
On 07/04/15 11:08, Albert Astals Cid wrote:
> Review: Needs Information
>
> Can you confirm that doing http://
>
> I just tried and it still closes when i swipe vertically over an open Launcher.
Sorry, this is the full patch:
"""
=== modified file 'qml/Launcher/
--- qml/Launcher/
+++ qml/Launcher/
@@ -280,7 +280,7 @@ Item {
enabled: root.available
x: -root.x // so if launcher is adjusted relative to screen, we
stay put (like tutorial does when teasing)
- width: root.dragAreaWidth
+ width: root.panelWidth
height: root.height
@@ -306,8 +306,9 @@ Item {
- } else {
- root.switchToNe
+ } else if (root.state === "") {
+ // didn't drag far enough. rollback
+ root.switchToNe
}
}
}
"""
And you don't have to do it on the phone. Doing it in "make tryShell" is
enough. Apply this patch in trunk and you won't be able to scroll the
launcher as the DDA in front of it is recognizing even those vertical
swiped. Apply it on top of ddaImprovements branch and you will see you
can scroll launcher icons just fine as the DDA rejects vertical drags.
Albert Astals Cid (aacid) wrote : | # |
Hmmm, the code looks ok, can't see anything wrong, but i think some parameter changes need some tweaking, with the old code i can show the launcher with a small drag and it'll show the margin of the launcher and very few of the icons, with this i need to do a bigger drag and it'll in consequence show more part of the launcher.
On the other hand not sure this is problematic either. Can you try it yourself and see what you think?
Daniel d'Andrada (dandrader) wrote : | # |
On 08/04/15 08:18, Albert Astals Cid wrote:
> Review: Needs Information
>
> Hmmm, the code looks ok, can't see anything wrong, but i think some parameter changes need some tweaking, with the old code i can show the launcher with a small drag and it'll show the margin of the launcher and very few of the icons, with this i need to do a bigger drag and it'll in consequence show more part of the launcher.
>
> On the other hand not sure this is problematic either. Can you try it yourself and see what you think?
I get what you mean. But this is not relevant as you only do those very
short drags when you're testing the edge drag feature, ie when you're
checking how much drag it needs to kick in etc. In real usage no one
would do a very short edge drag expose the launcher just a little bit. :)
In any case I reduced the distance threshold a bit so that the gesture
kicks in a bit sooner, if that makes you feel better. :) But it does
help smoothing out the very beginning of the right edge drag (to show
the spread) as it is not animated like the left edge one. It just jumps
to the current drag position instead of animating towards it. Which
makes the larger drag threshold noticeable. But that's an issue with the
"show the spread with right-edge gesture" qml code, not with DDA per se.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1708
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Approving since code looks good and the behaviour change is acceptable to me but i'd like someone else to give it a try on the phone before top approving.
* Did you perform an exploratory manual test run of the code change and any related functionality?
Yes
* Did CI run pass?
known autopilot fixed elsewhere
* Did you make sure that the branch does not contain spurious tags?
Yes
Daniel d'Andrada (dandrader) wrote : | # |
right-edge animation start is now smooth as silk
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1709
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
Broken tests again:
qmltestrunn
qmltestrunn
qmltestrunn
Daniel d'Andrada (dandrader) wrote : | # |
On 09/04/15 15:35, Michał Sawicz wrote:
> Broken tests again:
> qmltestrunner.
> qmltestrunner.
> qmltestrunner.
Fixed
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1710
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1710. By Launchpad Translations on behalf of unity-team
-
Launchpad automatic translations update.
Michael Zanetti (mzanetti) wrote : | # |
> right-edge animation start is now smooth as silk
If this would just be unity8, I'd be totally happy with it (Except that you're missing TabletStage.qml). But given that the DDA should be an upstream component, I'm hesitant to make all the app developers do that magic as you added in the Phone stage. They won't, and as a result we'll have the jumpiness every time an app uses the DDA.
- 1711. By Daniel d'Andrada
-
DirectionalDragArea & friends: various improvements & API grooming
-Simplified DirectionalDragArea gesture recognition
* The widening angle property was dropped. Didn't really work
as in real life swipes might start up in very different directions
before finally turning to the final overall direction. That's specially
bad when you have to conclude the recognition in a short amount
of time so that you can still play animations to follow the user's finger
* minSpeed as well. Went for a simpler way of expressing and evaluating it
which is having maxTime and maxDistance.-EdgeDragArea got absorbed by DirectionalDragArea
-Privatized all gesture recognition parameters.
-Privatized DirectionalDrag
Area.status property. All apps need is
DirectionalDragArea.dragging. Modified qml code using DDA accordingly. -Modified DirectionalDrag
Area.dragging semantics a bit. It goes to true only
once a gesture is recognized-Moved code that smooths out touch movement into DirectionalDragArea so all users
get it for free.-Cleaned up DirectionalDrag
Area.h of all implementation details, getting it ready
to be moved out of unity8, into the SDK.-Removed DirectionalDrag
Area.tapped( ) signal as it doesn't belong to it. -Fine-tuned gesture recognition parameters and made them based on physical size.
-Added tests with input from real gestures to catch those annoying
false-negatives and false-positives introduced by badly set recognition parameters-Improved debug output
-UnownedTouchEvents are no longer sent to interim owners
-Fixed issue when TouchGate got disabled while holding an active touch
-Made "make tryDirectionalD
ragArea" and "make tryDragHandle" work with mouse again. - 1712. By Daniel d'Andrada
-
Fix whitespace issues
- 1713. By Daniel d'Andrada
-
Fix UnityTestCase.
removeTimeConst raintsFromDirec tionalDragAreas () - 1714. By Daniel d'Andrada
-
Fix tst_Shell:
:test_leftEdgeD ragFullscreen - 1715. By Daniel d'Andrada
-
fix shell tests
- 1716. By Daniel d'Andrada
-
Added DirectionalDrag
Area.pressed property - 1717. By Daniel d'Andrada
-
Fix tst_ShellWithPin
- 1718. By Daniel d'Andrada
-
Tweak launcher animation
Unmerged revisions
- 1710. By Launchpad Translations on behalf of unity-team
-
Launchpad automatic translations update.
Preview Diff
1 | === modified file 'libs/UbuntuGestures/CMakeLists.txt' |
2 | --- libs/UbuntuGestures/CMakeLists.txt 2014-10-01 13:20:32 +0000 |
3 | +++ libs/UbuntuGestures/CMakeLists.txt 2015-04-10 21:17:56 +0000 |
4 | @@ -5,6 +5,7 @@ |
5 | CandidateInactivityTimer.cpp |
6 | DebugHelpers.cpp |
7 | Timer.cpp |
8 | + TimeSource.cpp |
9 | TouchOwnershipEvent.cpp |
10 | TouchRegistry.cpp |
11 | UnownedTouchEvent.cpp |
12 | |
13 | === modified file 'libs/UbuntuGestures/CandidateInactivityTimer.h' |
14 | --- libs/UbuntuGestures/CandidateInactivityTimer.h 2014-10-01 13:20:32 +0000 |
15 | +++ libs/UbuntuGestures/CandidateInactivityTimer.h 2015-04-10 21:17:56 +0000 |
16 | @@ -32,7 +32,7 @@ |
17 | AbstractTimerFactory &timerFactory, |
18 | QObject *parent = nullptr); |
19 | |
20 | - const int durationMs = 350; |
21 | + const int durationMs = 1000; |
22 | |
23 | Q_SIGNALS: |
24 | void candidateDefaulted(int touchId, QQuickItem *candidate); |
25 | |
26 | === renamed file 'plugins/Ubuntu/Gestures/TimeSource.cpp' => 'libs/UbuntuGestures/TimeSource.cpp' |
27 | === renamed file 'plugins/Ubuntu/Gestures/TimeSource.h' => 'libs/UbuntuGestures/TimeSource.h' |
28 | --- plugins/Ubuntu/Gestures/TimeSource.h 2014-10-01 13:20:32 +0000 |
29 | +++ libs/UbuntuGestures/TimeSource.h 2015-04-10 21:17:56 +0000 |
30 | @@ -1,5 +1,5 @@ |
31 | /* |
32 | - * Copyright (C) 2013 - Canonical Ltd. |
33 | + * Copyright (C) 2013,2015 Canonical Ltd. |
34 | * |
35 | * This program is free software: you can redistribute it and/or modify it |
36 | * under the terms of the GNU Lesser General Public License, as |
37 | @@ -21,14 +21,14 @@ |
38 | #ifndef UBUNTUGESTURES_TIMESOURCE_H |
39 | #define UBUNTUGESTURES_TIMESOURCE_H |
40 | |
41 | -#include "UbuntuGesturesQmlGlobal.h" |
42 | +#include "UbuntuGesturesGlobal.h" |
43 | #include <QSharedPointer> |
44 | |
45 | namespace UbuntuGestures { |
46 | /* |
47 | Interface for a time source. |
48 | */ |
49 | -class UBUNTUGESTURESQML_EXPORT TimeSource { |
50 | +class UBUNTUGESTURES_EXPORT TimeSource { |
51 | public: |
52 | virtual ~TimeSource() {} |
53 | /* Returns the current time in milliseconds since some reference time in the past. */ |
54 | @@ -40,7 +40,7 @@ |
55 | Implementation of a time source |
56 | */ |
57 | class RealTimeSourcePrivate; |
58 | -class RealTimeSource : public TimeSource { |
59 | +class UBUNTUGESTURES_EXPORT RealTimeSource : public TimeSource { |
60 | public: |
61 | RealTimeSource(); |
62 | virtual ~RealTimeSource(); |
63 | @@ -49,6 +49,16 @@ |
64 | RealTimeSourcePrivate *d; |
65 | }; |
66 | |
67 | +/* |
68 | + A fake time source, useful for tests |
69 | + */ |
70 | +class FakeTimeSource : public TimeSource { |
71 | +public: |
72 | + FakeTimeSource() { m_msecsSinceReference = 0; } |
73 | + qint64 msecsSinceReference() override { return m_msecsSinceReference; } |
74 | + qint64 m_msecsSinceReference; |
75 | +}; |
76 | + |
77 | } // namespace UbuntuGestures |
78 | |
79 | #endif // UBUNTUGESTURES_TIMESOURCE_H |
80 | |
81 | === modified file 'libs/UbuntuGestures/Timer.cpp' |
82 | --- libs/UbuntuGestures/Timer.cpp 2014-10-01 13:20:32 +0000 |
83 | +++ libs/UbuntuGestures/Timer.cpp 2015-04-10 21:17:56 +0000 |
84 | @@ -1,5 +1,5 @@ |
85 | /* |
86 | - * Copyright (C) 2014 Canonical, Ltd. |
87 | + * Copyright (C) 2014-2015 Canonical, Ltd. |
88 | * |
89 | * This program is free software; you can redistribute it and/or modify |
90 | * it under the terms of the GNU General Public License as published by |
91 | @@ -58,11 +58,34 @@ |
92 | |
93 | /////////////////////////////////// FakeTimer ////////////////////////////////// |
94 | |
95 | -FakeTimer::FakeTimer(QObject *parent) |
96 | +FakeTimer::FakeTimer(const SharedTimeSource &timeSource, QObject *parent) |
97 | : UbuntuGestures::AbstractTimer(parent) |
98 | , m_interval(0) |
99 | , m_singleShot(false) |
100 | -{ |
101 | + , m_timeSource(timeSource) |
102 | +{ |
103 | +} |
104 | + |
105 | +void FakeTimer::update() |
106 | +{ |
107 | + if (!isRunning()) { |
108 | + return; |
109 | + } |
110 | + |
111 | + if (m_nextTimeoutTime <= m_timeSource->msecsSinceReference()) { |
112 | + if (isSingleShot()) { |
113 | + stop(); |
114 | + } else { |
115 | + m_nextTimeoutTime += interval(); |
116 | + } |
117 | + Q_EMIT timeout(); |
118 | + } |
119 | +} |
120 | + |
121 | +void FakeTimer::start() |
122 | +{ |
123 | + AbstractTimer::start(); |
124 | + m_nextTimeoutTime = m_timeSource->msecsSinceReference() + (qint64)interval(); |
125 | } |
126 | |
127 | int FakeTimer::interval() const |
128 | @@ -87,23 +110,53 @@ |
129 | |
130 | /////////////////////////////////// FakeTimerFactory ////////////////////////////////// |
131 | |
132 | +FakeTimerFactory::FakeTimerFactory() |
133 | +{ |
134 | + m_timeSource.reset(new FakeTimeSource); |
135 | +} |
136 | + |
137 | +FakeTimerFactory::~FakeTimerFactory() |
138 | +{ |
139 | + for (int i = 0; i < timers.count(); ++i) { |
140 | + FakeTimer *timer = timers[i].data(); |
141 | + if (timer) { |
142 | + delete timer; |
143 | + } |
144 | + } |
145 | +} |
146 | + |
147 | +void FakeTimerFactory::updateTime(qint64 targetTime) |
148 | +{ |
149 | + qint64 minTimeoutTime = targetTime; |
150 | + |
151 | + for (int i = 0; i < timers.count(); ++i) { |
152 | + FakeTimer *timer = timers[i].data(); |
153 | + if (timer && timer->isRunning() && timer->nextTimeoutTime() < minTimeoutTime) { |
154 | + minTimeoutTime = timer->nextTimeoutTime(); |
155 | + } |
156 | + } |
157 | + |
158 | + m_timeSource->m_msecsSinceReference = minTimeoutTime; |
159 | + |
160 | + for (int i = 0; i < timers.count(); ++i) { |
161 | + FakeTimer *timer = timers[i].data(); |
162 | + if (timer) { |
163 | + timer->update(); |
164 | + } |
165 | + } |
166 | + |
167 | + if (m_timeSource->msecsSinceReference() < targetTime) { |
168 | + updateTime(targetTime); |
169 | + } |
170 | +} |
171 | + |
172 | AbstractTimer *FakeTimerFactory::createTimer(QObject *parent) |
173 | { |
174 | - FakeTimer *fakeTimer = new FakeTimer(parent); |
175 | + FakeTimer *fakeTimer = new FakeTimer(m_timeSource, parent); |
176 | |
177 | timers.append(fakeTimer); |
178 | |
179 | return fakeTimer; |
180 | } |
181 | |
182 | -void FakeTimerFactory::makeRunningTimersTimeout() |
183 | -{ |
184 | - for (int i = 0; i < timers.count(); ++i) { |
185 | - FakeTimer *timer = timers[i].data(); |
186 | - if (timer && timer->isRunning()) { |
187 | - timer->emitTimeout(); |
188 | - } |
189 | - } |
190 | -} |
191 | - |
192 | } // namespace UbuntuGestures |
193 | |
194 | === modified file 'libs/UbuntuGestures/Timer.h' |
195 | --- libs/UbuntuGestures/Timer.h 2014-10-01 13:20:32 +0000 |
196 | +++ libs/UbuntuGestures/Timer.h 2015-04-10 21:17:56 +0000 |
197 | @@ -18,6 +18,7 @@ |
198 | #define UBUNTUGESTURES_TIMER_H |
199 | |
200 | #include "UbuntuGesturesGlobal.h" |
201 | +#include "TimeSource.h" |
202 | |
203 | #include <QObject> |
204 | #include <QPointer> |
205 | @@ -66,17 +67,21 @@ |
206 | { |
207 | Q_OBJECT |
208 | public: |
209 | - FakeTimer(QObject *parent = nullptr); |
210 | + FakeTimer(const SharedTimeSource &timeSource, QObject *parent = nullptr); |
211 | |
212 | - virtual void emitTimeout() { Q_EMIT timeout(); } |
213 | + void update(); |
214 | + qint64 nextTimeoutTime() const { return m_nextTimeoutTime; } |
215 | |
216 | int interval() const override; |
217 | void setInterval(int msecs) override; |
218 | + void start() override; |
219 | bool isSingleShot() const override; |
220 | void setSingleShot(bool value) override; |
221 | private: |
222 | int m_interval; |
223 | bool m_singleShot; |
224 | + SharedTimeSource m_timeSource; |
225 | + qint64 m_nextTimeoutTime; |
226 | }; |
227 | |
228 | class UBUNTUGESTURES_EXPORT AbstractTimerFactory |
229 | @@ -95,9 +100,16 @@ |
230 | class UBUNTUGESTURES_EXPORT FakeTimerFactory : public AbstractTimerFactory |
231 | { |
232 | public: |
233 | + FakeTimerFactory(); |
234 | + virtual ~FakeTimerFactory(); |
235 | + |
236 | + void updateTime(qint64 msecsSinceReference); |
237 | + QSharedPointer<TimeSource> timeSource() { return m_timeSource; } |
238 | + |
239 | AbstractTimer *createTimer(QObject *parent = nullptr) override; |
240 | - void makeRunningTimersTimeout(); |
241 | QList<QPointer<FakeTimer>> timers; |
242 | +private: |
243 | + QSharedPointer<FakeTimeSource> m_timeSource; |
244 | }; |
245 | |
246 | } // namespace UbuntuGestures |
247 | |
248 | === modified file 'libs/UbuntuGestures/TouchRegistry.cpp' |
249 | --- libs/UbuntuGestures/TouchRegistry.cpp 2014-10-01 13:20:32 +0000 |
250 | +++ libs/UbuntuGestures/TouchRegistry.cpp 2015-04-10 21:17:56 +0000 |
251 | @@ -1,5 +1,5 @@ |
252 | /* |
253 | - * Copyright (C) 2014 Canonical, Ltd. |
254 | + * Copyright (C) 2014-2015 Canonical, Ltd. |
255 | * |
256 | * This program is free software; you can redistribute it and/or modify |
257 | * it under the terms of the GNU General Public License as published by |
258 | @@ -95,10 +95,6 @@ |
259 | // for each point and there should not be many active points at any given moment. |
260 | // But having three nested for-loops does scare. |
261 | |
262 | - // TODO: Don't send it to the object that is already receiving the regular event |
263 | - // because QQuickWindow is sending it to him (i.e., he's the touch owner from Qt's point of view) |
264 | - // Problem is, we cannnot easily get this information. |
265 | - |
266 | const QList<QTouchEvent::TouchPoint> &updatedTouchPoints = event->touchPoints(); |
267 | |
268 | // Maps an item to the touches in this event he should be informed about. |
269 | @@ -118,7 +114,9 @@ |
270 | for (int i = 0; i < touchInfo->candidates.count(); ++i) { |
271 | CandidateInfo &candidate = touchInfo->candidates[i]; |
272 | Q_ASSERT(!candidate.item.isNull()); |
273 | - touchIdsForItems[candidate.item.data()].append(touchInfo->id); |
274 | + if (candidate.state != CandidateInfo::InterimOwner) { |
275 | + touchIdsForItems[candidate.item.data()].append(touchInfo->id); |
276 | + } |
277 | } |
278 | } |
279 | |
280 | @@ -260,7 +258,7 @@ |
281 | // TODO: Check if candidate already exists |
282 | |
283 | CandidateInfo candidateInfo; |
284 | - candidateInfo.undecided = true; |
285 | + candidateInfo.state = CandidateInfo::Undecided; |
286 | candidateInfo.item = candidate; |
287 | candidateInfo.inactivityTimer = new CandidateInactivityTimer(id, candidate, |
288 | *m_timerFactory, |
289 | @@ -301,8 +299,8 @@ |
290 | for (int i = 0; i < touchInfo->candidates.count() && indexRemoved == -1; ++i) { |
291 | CandidateInfo &candidateInfo = touchInfo->candidates[i]; |
292 | if (candidateInfo.item == candidate) { |
293 | - Q_ASSERT(i > 0 || candidateInfo.undecided); |
294 | - if (i == 0 && !candidateInfo.undecided) { |
295 | + Q_ASSERT(i > 0 || candidateInfo.state == CandidateInfo::Undecided); |
296 | + if (i == 0 && candidateInfo.state != CandidateInfo::Undecided) { |
297 | qCritical("TouchRegistry: touch owner is being removed."); |
298 | } |
299 | delete candidateInfo.inactivityTimer; |
300 | @@ -340,7 +338,7 @@ |
301 | for (int i = 0; i < touchInfo->candidates.count(); ++i) { |
302 | CandidateInfo &candidateInfo = touchInfo->candidates[i]; |
303 | if (candidateInfo.item == candidate) { |
304 | - candidateInfo.undecided = false; |
305 | + candidateInfo.state = CandidateInfo::Requested; |
306 | delete candidateInfo.inactivityTimer; |
307 | candidateInfo.inactivityTimer = nullptr; |
308 | candidateIndex = i; |
309 | @@ -351,7 +349,7 @@ |
310 | // add it as a candidate if not present yet |
311 | if (candidateIndex < 0) { |
312 | CandidateInfo candidateInfo; |
313 | - candidateInfo.undecided = false; |
314 | + candidateInfo.state = CandidateInfo::InterimOwner; |
315 | candidateInfo.item = candidate; |
316 | candidateInfo.inactivityTimer = nullptr; |
317 | touchInfo->candidates.append(candidateInfo); |
318 | @@ -407,8 +405,8 @@ |
319 | for (int i = 0; i < touchInfo->candidates.count() && rejectedCandidateIndex == -1; ++i) { |
320 | CandidateInfo &candidateInfo = touchInfo->candidates[i]; |
321 | if (candidateInfo.item == candidate) { |
322 | - Q_ASSERT(i > 0 || candidateInfo.undecided); |
323 | - if (i == 0 && !candidateInfo.undecided) { |
324 | + Q_ASSERT(i > 0 || candidateInfo.state == CandidateInfo::Undecided); |
325 | + if (i == 0 && candidateInfo.state != CandidateInfo::Undecided) { |
326 | qCritical() << "TouchRegistry: Can't reject item (" << (void*)candidate |
327 | << ") as it already owns touch" << id; |
328 | return; |
329 | @@ -467,7 +465,7 @@ |
330 | |
331 | bool TouchRegistry::TouchInfo::isOwned() const |
332 | { |
333 | - return !candidates.isEmpty() && !candidates.first().undecided; |
334 | + return !candidates.isEmpty() && candidates.first().state != CandidateInfo::Undecided; |
335 | } |
336 | |
337 | bool TouchRegistry::TouchInfo::ended() const |
338 | |
339 | === modified file 'libs/UbuntuGestures/TouchRegistry.h' |
340 | --- libs/UbuntuGestures/TouchRegistry.h 2014-10-02 12:47:07 +0000 |
341 | +++ libs/UbuntuGestures/TouchRegistry.h 2015-04-10 21:17:56 +0000 |
342 | @@ -79,9 +79,11 @@ |
343 | If an item wants ownership over touches as soon as he receives the TouchBegin for them, his step 1 |
344 | would be instead: |
345 | TouchRegistry::instance()->requestTouchOwnership(touchId, this); |
346 | - return true; |
347 | - He would then be notified once ownership has been granted to him, from which point onwards he could |
348 | - safely assume other TouchRegistry users wouldn't snatch this touch away from him. |
349 | + touchEvent->accept(); |
350 | + He won't get any UnownedTouchEvent for that touch as he is already the interim owner (ie, QQuickWindow |
351 | + will keep sending touch updates to him already). Eventually he will be notified once ownership has |
352 | + been granted to him (from TouchRegistry perspective), from which point onwards he could safely assume |
353 | + other TouchRegistry users wouldn't snatch this touch away from him. |
354 | |
355 | Items oblivious to TouchRegistry will lose their touch points without warning, just like in plain Qt. |
356 | |
357 | @@ -132,7 +134,19 @@ |
358 | private: |
359 | class CandidateInfo { |
360 | public: |
361 | - bool undecided; |
362 | + enum { |
363 | + // A candidate owner that doesn't yet know for sure whether he wants the touch point |
364 | + // (gesture recognition is stilll going on) |
365 | + Undecided = 0, |
366 | + // A candidate owner that wants the touch but hasn't been granted it yet, |
367 | + // most likely because there's an undecided candidate with higher priority |
368 | + Requested = 1, |
369 | + // An item that is the interim owner of the touch, receiving QTouchEvents of it |
370 | + // from QQuickWindow. Ie, it's the actual touch owner from Qt's point of view. |
371 | + // It wants to keep its touch ownership but hasn't been granted it by TouchRegistry |
372 | + // yet because of undecided candidates higher up. |
373 | + InterimOwner = 2 |
374 | + } state; |
375 | // TODO: Prune candidates that become null and resolve ownership accordingly. |
376 | QPointer<QQuickItem> item; |
377 | QPointer<UbuntuGestures::CandidateInactivityTimer> inactivityTimer; |
378 | |
379 | === modified file 'plugins/Ubuntu/Gestures/CMakeLists.txt' |
380 | --- plugins/Ubuntu/Gestures/CMakeLists.txt 2014-10-17 11:01:53 +0000 |
381 | +++ plugins/Ubuntu/Gestures/CMakeLists.txt 2015-04-10 21:17:56 +0000 |
382 | @@ -4,10 +4,10 @@ |
383 | set(UbuntuGesturesQml_SOURCES |
384 | plugin.cpp |
385 | AxisVelocityCalculator.cpp |
386 | + Damper.cpp |
387 | Direction.cpp |
388 | DirectionalDragArea.cpp |
389 | PressedOutsideNotifier.cpp |
390 | - TimeSource.cpp |
391 | TouchDispatcher.cpp |
392 | TouchGate.cpp |
393 | ) |
394 | |
395 | === added file 'plugins/Ubuntu/Gestures/Damper.cpp' |
396 | --- plugins/Ubuntu/Gestures/Damper.cpp 1970-01-01 00:00:00 +0000 |
397 | +++ plugins/Ubuntu/Gestures/Damper.cpp 2015-04-10 21:17:56 +0000 |
398 | @@ -0,0 +1,24 @@ |
399 | +/* |
400 | + * Copyright (C) 2015 Canonical, Ltd. |
401 | + * |
402 | + * This program is free software; you can redistribute it and/or modify |
403 | + * it under the terms of the GNU General Public License as published by |
404 | + * the Free Software Foundation; version 3. |
405 | + * |
406 | + * This program is distributed in the hope that it will be useful, |
407 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
408 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
409 | + * GNU General Public License for more details. |
410 | + * |
411 | + * You should have received a copy of the GNU General Public License |
412 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
413 | + */ |
414 | + |
415 | +#include "Damper.h" |
416 | +#include <QDebug> |
417 | + |
418 | +QDebug operator<<(QDebug dbg, const DampedPointF &p) |
419 | +{ |
420 | + dbg.nospace() << "(" << p.x() << ", " << p.y() << ")"; |
421 | + return dbg.space(); |
422 | +} |
423 | |
424 | === modified file 'plugins/Ubuntu/Gestures/Damper.h' |
425 | --- plugins/Ubuntu/Gestures/Damper.h 2013-08-06 13:18:34 +0000 |
426 | +++ plugins/Ubuntu/Gestures/Damper.h 2015-04-10 21:17:56 +0000 |
427 | @@ -84,4 +84,6 @@ |
428 | Damper<qreal> m_y; |
429 | }; |
430 | |
431 | +QDebug operator<<(QDebug dbg, const DampedPointF &p); |
432 | + |
433 | #endif // UBUNTU_GESTURES_DAMPER_H |
434 | |
435 | === modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea.cpp' |
436 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2014-12-09 11:00:37 +0000 |
437 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2015-04-10 21:17:56 +0000 |
438 | @@ -1,5 +1,5 @@ |
439 | /* |
440 | - * Copyright (C) 2013-2014 Canonical, Ltd. |
441 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
442 | * |
443 | * This program is free software; you can redistribute it and/or modify |
444 | * it under the terms of the GNU General Public License as published by |
445 | @@ -21,6 +21,7 @@ |
446 | |
447 | #include <QQuickWindow> |
448 | #include <QtCore/qmath.h> |
449 | +#include <QScreen> |
450 | #include <QDebug> |
451 | |
452 | #pragma GCC diagnostic push |
453 | @@ -33,6 +34,8 @@ |
454 | #include "TouchRegistry.h" |
455 | #include "UnownedTouchEvent.h" |
456 | |
457 | +#include "DirectionalDragArea_p.h" |
458 | + |
459 | using namespace UbuntuGestures; |
460 | |
461 | #if DIRECTIONALDRAGAREA_DEBUG |
462 | @@ -40,11 +43,11 @@ |
463 | #include "DebugHelpers.h" |
464 | |
465 | namespace { |
466 | -const char *statusToString(DirectionalDragArea::Status status) |
467 | +const char *statusToString(DirectionalDragAreaPrivate::Status status) |
468 | { |
469 | - if (status == DirectionalDragArea::WaitingForTouch) { |
470 | + if (status == DirectionalDragAreaPrivate::WaitingForTouch) { |
471 | return "WaitingForTouch"; |
472 | - } else if (status == DirectionalDragArea::Undecided) { |
473 | + } else if (status == DirectionalDragAreaPrivate::Undecided) { |
474 | return "Undecided"; |
475 | } else { |
476 | return "Recognized"; |
477 | @@ -56,205 +59,156 @@ |
478 | #define ddaDebug(params) ((void)0) |
479 | #endif // DIRECTIONALDRAGAREA_DEBUG |
480 | |
481 | - |
482 | DirectionalDragArea::DirectionalDragArea(QQuickItem *parent) |
483 | : QQuickItem(parent) |
484 | - , m_status(WaitingForTouch) |
485 | - , m_sceneDistance(0) |
486 | - , m_touchId(-1) |
487 | - , m_direction(Direction::Rightwards) |
488 | - , m_wideningAngle(0) |
489 | - , m_wideningFactor(0) |
490 | - , m_distanceThreshold(0) |
491 | - , m_distanceThresholdSquared(0.) |
492 | - , m_minSpeed(0) |
493 | - , m_maxSilenceTime(200) |
494 | - , m_silenceTime(0) |
495 | - , m_compositionTime(60) |
496 | - , m_numSamplesOnLastSpeedCheck(0) |
497 | - , m_recognitionTimer(0) |
498 | - , m_velocityCalculator(0) |
499 | - , m_timeSource(new RealTimeSource) |
500 | - , m_activeTouches(m_timeSource) |
501 | + , d(new DirectionalDragAreaPrivate(this)) |
502 | { |
503 | - setRecognitionTimer(new Timer(this)); |
504 | - m_recognitionTimer->setInterval(60); |
505 | - m_recognitionTimer->setSingleShot(false); |
506 | - |
507 | - m_velocityCalculator = new AxisVelocityCalculator(this); |
508 | - |
509 | - connect(this, &QQuickItem::enabledChanged, this, &DirectionalDragArea::giveUpIfDisabledOrInvisible); |
510 | - connect(this, &QQuickItem::visibleChanged, this, &DirectionalDragArea::giveUpIfDisabledOrInvisible); |
511 | + d->setRecognitionTimer(new Timer(this)); |
512 | + d->recognitionTimer->setInterval(d->maxTime); |
513 | + d->recognitionTimer->setSingleShot(true); |
514 | + |
515 | + connect(this, &QQuickItem::enabledChanged, d, &DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible); |
516 | + connect(this, &QQuickItem::visibleChanged, d, &DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible); |
517 | } |
518 | |
519 | Direction::Type DirectionalDragArea::direction() const |
520 | { |
521 | - return m_direction; |
522 | + return d->direction; |
523 | } |
524 | |
525 | void DirectionalDragArea::setDirection(Direction::Type direction) |
526 | { |
527 | - if (direction != m_direction) { |
528 | - m_direction = direction; |
529 | - Q_EMIT directionChanged(m_direction); |
530 | - } |
531 | -} |
532 | - |
533 | -void DirectionalDragArea::setMaxDeviation(qreal value) |
534 | -{ |
535 | - if (m_dampedScenePos.maxDelta() != value) { |
536 | - m_dampedScenePos.setMaxDelta(value); |
537 | - Q_EMIT maxDeviationChanged(value); |
538 | - } |
539 | -} |
540 | - |
541 | -qreal DirectionalDragArea::wideningAngle() const |
542 | -{ |
543 | - return m_wideningAngle; |
544 | -} |
545 | - |
546 | -void DirectionalDragArea::setWideningAngle(qreal angle) |
547 | -{ |
548 | - if (angle == m_wideningAngle) |
549 | - return; |
550 | - |
551 | - m_wideningAngle = angle; |
552 | - |
553 | - // wideningFactor = pow(cosine(angle), 2) |
554 | - { |
555 | - qreal angleRadians = angle * M_PI / 180.0; |
556 | - m_wideningFactor = qCos(angleRadians); |
557 | - m_wideningFactor = m_wideningFactor * m_wideningFactor; |
558 | - } |
559 | - |
560 | - Q_EMIT wideningAngleChanged(angle); |
561 | -} |
562 | - |
563 | -void DirectionalDragArea::setDistanceThreshold(qreal value) |
564 | -{ |
565 | - if (m_distanceThreshold != value) { |
566 | - m_distanceThreshold = value; |
567 | - m_distanceThresholdSquared = m_distanceThreshold * m_distanceThreshold; |
568 | - Q_EMIT distanceThresholdChanged(value); |
569 | - } |
570 | -} |
571 | - |
572 | -void DirectionalDragArea::setMinSpeed(qreal value) |
573 | -{ |
574 | - if (m_minSpeed != value) { |
575 | - m_minSpeed = value; |
576 | - Q_EMIT minSpeedChanged(value); |
577 | - } |
578 | -} |
579 | - |
580 | -void DirectionalDragArea::setMaxSilenceTime(int value) |
581 | -{ |
582 | - if (m_maxSilenceTime != value) { |
583 | - m_maxSilenceTime = value; |
584 | - Q_EMIT maxSilenceTimeChanged(value); |
585 | - } |
586 | -} |
587 | - |
588 | -void DirectionalDragArea::setCompositionTime(int value) |
589 | -{ |
590 | - if (m_compositionTime != value) { |
591 | - m_compositionTime = value; |
592 | - Q_EMIT compositionTimeChanged(value); |
593 | - } |
594 | -} |
595 | - |
596 | -void DirectionalDragArea::setRecognitionTimer(UbuntuGestures::AbstractTimer *timer) |
597 | + if (direction != d->direction) { |
598 | + d->direction = direction; |
599 | + Q_EMIT directionChanged(d->direction); |
600 | + } |
601 | +} |
602 | + |
603 | +void DirectionalDragAreaPrivate::setDistanceThreshold(qreal value) |
604 | +{ |
605 | + if (distanceThreshold != value) { |
606 | + distanceThreshold = value; |
607 | + distanceThresholdSquared = distanceThreshold * distanceThreshold; |
608 | + } |
609 | +} |
610 | + |
611 | +void DirectionalDragAreaPrivate::setMaxTime(int value) |
612 | +{ |
613 | + if (maxTime != value) { |
614 | + maxTime = value; |
615 | + recognitionTimer->setInterval(maxTime); |
616 | + } |
617 | +} |
618 | + |
619 | +void DirectionalDragAreaPrivate::setRecognitionTimer(UbuntuGestures::AbstractTimer *timer) |
620 | { |
621 | int interval = 0; |
622 | bool timerWasRunning = false; |
623 | bool wasSingleShot = false; |
624 | |
625 | // can be null when called from the constructor |
626 | - if (m_recognitionTimer) { |
627 | - interval = m_recognitionTimer->interval(); |
628 | - timerWasRunning = m_recognitionTimer->isRunning(); |
629 | - if (m_recognitionTimer->parent() == this) { |
630 | - delete m_recognitionTimer; |
631 | + if (recognitionTimer) { |
632 | + interval = recognitionTimer->interval(); |
633 | + timerWasRunning = recognitionTimer->isRunning(); |
634 | + if (recognitionTimer->parent() == this) { |
635 | + delete recognitionTimer; |
636 | } |
637 | } |
638 | |
639 | - m_recognitionTimer = timer; |
640 | + recognitionTimer = timer; |
641 | timer->setInterval(interval); |
642 | timer->setSingleShot(wasSingleShot); |
643 | connect(timer, &UbuntuGestures::AbstractTimer::timeout, |
644 | - this, &DirectionalDragArea::checkSpeed); |
645 | + this, &DirectionalDragAreaPrivate::rejectGesture); |
646 | if (timerWasRunning) { |
647 | - m_recognitionTimer->start(); |
648 | + recognitionTimer->start(); |
649 | } |
650 | } |
651 | |
652 | -void DirectionalDragArea::setTimeSource(const SharedTimeSource &timeSource) |
653 | +void DirectionalDragAreaPrivate::setTimeSource(const SharedTimeSource &timeSource) |
654 | { |
655 | - m_timeSource = timeSource; |
656 | - m_velocityCalculator->setTimeSource(timeSource); |
657 | - m_activeTouches.m_timeSource = timeSource; |
658 | + this->timeSource = timeSource; |
659 | + activeTouches.m_timeSource = timeSource; |
660 | } |
661 | |
662 | qreal DirectionalDragArea::distance() const |
663 | { |
664 | - if (Direction::isHorizontal(m_direction)) { |
665 | - return m_previousPos.x() - m_startPos.x(); |
666 | + if (Direction::isHorizontal(d->direction)) { |
667 | + return d->publicPos.x() - d->startPos.x(); |
668 | } else { |
669 | - return m_previousPos.y() - m_startPos.y(); |
670 | + return d->publicPos.y() - d->startPos.y(); |
671 | } |
672 | } |
673 | |
674 | -void DirectionalDragArea::updateSceneDistance() |
675 | +void DirectionalDragAreaPrivate::updateSceneDistance() |
676 | { |
677 | - QPointF totalMovement = m_previousScenePos - m_startScenePos; |
678 | - m_sceneDistance = projectOntoDirectionVector(totalMovement); |
679 | + QPointF totalMovement = publicScenePos - startScenePos; |
680 | + sceneDistance = projectOntoDirectionVector(totalMovement); |
681 | } |
682 | |
683 | qreal DirectionalDragArea::sceneDistance() const |
684 | { |
685 | - return m_sceneDistance; |
686 | + return d->sceneDistance; |
687 | } |
688 | |
689 | qreal DirectionalDragArea::touchX() const |
690 | { |
691 | - return m_previousPos.x(); |
692 | + return d->publicPos.x(); |
693 | } |
694 | |
695 | qreal DirectionalDragArea::touchY() const |
696 | { |
697 | - return m_previousPos.y(); |
698 | + return d->publicPos.y(); |
699 | } |
700 | |
701 | qreal DirectionalDragArea::touchSceneX() const |
702 | { |
703 | - return m_previousScenePos.x(); |
704 | + return d->publicScenePos.x(); |
705 | } |
706 | |
707 | qreal DirectionalDragArea::touchSceneY() const |
708 | { |
709 | - return m_previousScenePos.y(); |
710 | + return d->publicScenePos.y(); |
711 | +} |
712 | + |
713 | +bool DirectionalDragArea::dragging() const |
714 | +{ |
715 | + return d->status == DirectionalDragAreaPrivate::Recognized; |
716 | +} |
717 | + |
718 | +bool DirectionalDragArea::immediateRecognition() const |
719 | +{ |
720 | + return d->immediateRecognition; |
721 | +} |
722 | + |
723 | +void DirectionalDragArea::setImmediateRecognition(bool enabled) |
724 | +{ |
725 | + if (d->immediateRecognition != enabled) { |
726 | + d->immediateRecognition = enabled; |
727 | + Q_EMIT immediateRecognitionChanged(enabled); |
728 | + } |
729 | } |
730 | |
731 | bool DirectionalDragArea::event(QEvent *event) |
732 | { |
733 | if (event->type() == TouchOwnershipEvent::touchOwnershipEventType()) { |
734 | - touchOwnershipEvent(static_cast<TouchOwnershipEvent *>(event)); |
735 | + d->touchOwnershipEvent(static_cast<TouchOwnershipEvent *>(event)); |
736 | return true; |
737 | } else if (event->type() == UnownedTouchEvent::unownedTouchEventType()) { |
738 | - unownedTouchEvent(static_cast<UnownedTouchEvent *>(event)); |
739 | + d->unownedTouchEvent(static_cast<UnownedTouchEvent *>(event)); |
740 | return true; |
741 | } else { |
742 | return QQuickItem::event(event); |
743 | } |
744 | } |
745 | |
746 | -void DirectionalDragArea::touchOwnershipEvent(TouchOwnershipEvent *event) |
747 | +void DirectionalDragAreaPrivate::touchOwnershipEvent(TouchOwnershipEvent *event) |
748 | { |
749 | if (event->gained()) { |
750 | QVector<int> ids; |
751 | ids.append(event->touchId()); |
752 | ddaDebug("grabbing touch"); |
753 | - grabTouchPoints(ids); |
754 | + q->grabTouchPoints(ids); |
755 | |
756 | // Work around for Qt bug. If we grab a touch that is being used for mouse pointer |
757 | // emulation it will cause the emulation logic to go nuts. |
758 | @@ -262,35 +216,35 @@ |
759 | // |
760 | // The fix for this bug has landed in Qt 5.4 (https://codereview.qt-project.org/96887) |
761 | // TODO: Remove this workaround once we start using Qt 5.4 |
762 | - if (window()) { |
763 | - QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(window()); |
764 | - if (windowPrivate->touchMouseId == event->touchId() && window()->mouseGrabberItem()) { |
765 | + if (q->window()) { |
766 | + QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(q->window()); |
767 | + if (windowPrivate->touchMouseId == event->touchId() && q->window()->mouseGrabberItem()) { |
768 | ddaDebug("removing mouse grabber"); |
769 | - window()->mouseGrabberItem()->ungrabMouse(); |
770 | + q->window()->mouseGrabberItem()->ungrabMouse(); |
771 | } |
772 | } |
773 | } else { |
774 | // We still wanna know when it ends for keeping the composition time window up-to-date |
775 | - TouchRegistry::instance()->addTouchWatcher(m_touchId, this); |
776 | + TouchRegistry::instance()->addTouchWatcher(touchId, q); |
777 | |
778 | setStatus(WaitingForTouch); |
779 | } |
780 | } |
781 | |
782 | -void DirectionalDragArea::unownedTouchEvent(UnownedTouchEvent *unownedTouchEvent) |
783 | +void DirectionalDragAreaPrivate::unownedTouchEvent(UnownedTouchEvent *unownedTouchEvent) |
784 | { |
785 | QTouchEvent *event = unownedTouchEvent->touchEvent(); |
786 | |
787 | Q_ASSERT(!event->touchPointStates().testFlag(Qt::TouchPointPressed)); |
788 | |
789 | - ddaDebug("Unowned " << m_timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event))); |
790 | + ddaDebug("Unowned " << timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event))); |
791 | |
792 | - switch (m_status) { |
793 | + switch (status) { |
794 | case WaitingForTouch: |
795 | // do nothing |
796 | break; |
797 | case Undecided: |
798 | - Q_ASSERT(isEnabled() && isVisible()); |
799 | + Q_ASSERT(q->isEnabled() && q->isVisible()); |
800 | unownedTouchEvent_undecided(unownedTouchEvent); |
801 | break; |
802 | default: // Recognized: |
803 | @@ -298,18 +252,18 @@ |
804 | break; |
805 | } |
806 | |
807 | - m_activeTouches.update(event); |
808 | + activeTouches.update(event); |
809 | } |
810 | |
811 | -void DirectionalDragArea::unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent) |
812 | +void DirectionalDragAreaPrivate::unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent) |
813 | { |
814 | const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(unownedTouchEvent->touchEvent()); |
815 | if (!touchPoint) { |
816 | - qCritical() << "DirectionalDragArea[status=Undecided]: touch " << m_touchId |
817 | + qCritical() << "DirectionalDragArea[status=Undecided]: touch " << touchId |
818 | << "missing from UnownedTouchEvent without first reaching state Qt::TouchPointReleased. " |
819 | "Considering it as released."; |
820 | |
821 | - TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this); |
822 | + TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); |
823 | setStatus(WaitingForTouch); |
824 | return; |
825 | } |
826 | @@ -319,48 +273,42 @@ |
827 | if (touchPoint->state() == Qt::TouchPointReleased) { |
828 | // touch has ended before recognition concluded |
829 | ddaDebug("Touch has ended before recognition concluded"); |
830 | - TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this); |
831 | - emitSignalIfTapped(); |
832 | - setStatus(WaitingForTouch); |
833 | - return; |
834 | - } |
835 | - |
836 | - m_previousDampedScenePos.setX(m_dampedScenePos.x()); |
837 | - m_previousDampedScenePos.setY(m_dampedScenePos.y()); |
838 | - m_dampedScenePos.update(touchScenePos); |
839 | - updateVelocityCalculator(touchScenePos); |
840 | - |
841 | - if (!pointInsideAllowedArea()) { |
842 | - ddaDebug("Rejecting gesture because touch point is outside allowed area."); |
843 | - TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this); |
844 | - // We still wanna know when it ends for keeping the composition time window up-to-date |
845 | - TouchRegistry::instance()->addTouchWatcher(m_touchId, this); |
846 | - setStatus(WaitingForTouch); |
847 | - return; |
848 | - } |
849 | + TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); |
850 | + setStatus(WaitingForTouch); |
851 | + return; |
852 | + } |
853 | + |
854 | + previousDampedScenePos.setX(dampedScenePos.x()); |
855 | + previousDampedScenePos.setY(dampedScenePos.y()); |
856 | + dampedScenePos.update(touchScenePos); |
857 | |
858 | if (!movingInRightDirection()) { |
859 | ddaDebug("Rejecting gesture because touch point is moving in the wrong direction."); |
860 | - TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this); |
861 | + TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); |
862 | // We still wanna know when it ends for keeping the composition time window up-to-date |
863 | - TouchRegistry::instance()->addTouchWatcher(m_touchId, this); |
864 | + TouchRegistry::instance()->addTouchWatcher(touchId, q); |
865 | setStatus(WaitingForTouch); |
866 | return; |
867 | } |
868 | |
869 | - setPreviousPos(touchPoint->pos()); |
870 | - setPreviousScenePos(touchScenePos); |
871 | - |
872 | if (isWithinTouchCompositionWindow()) { |
873 | // There's still time for some new touch to appear and ruin our party as it would be combined |
874 | - // with our m_touchId one and therefore deny the possibility of a single-finger gesture. |
875 | + // with our touchId one and therefore deny the possibility of a single-finger gesture. |
876 | ddaDebug("Sill within composition window. Let's wait more."); |
877 | return; |
878 | } |
879 | |
880 | - if (movedFarEnough(touchScenePos)) { |
881 | - TouchRegistry::instance()->requestTouchOwnership(m_touchId, this); |
882 | + if (movedFarEnoughAlongGestureAxis()) { |
883 | + TouchRegistry::instance()->requestTouchOwnership(touchId, q); |
884 | setStatus(Recognized); |
885 | + setPublicPos(touchPoint->pos()); |
886 | + setPublicScenePos(touchScenePos); |
887 | + } else if (isPastMaxDistance()) { |
888 | + ddaDebug("Rejecting gesture because it went farther than maxDistance without getting recognized."); |
889 | + TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); |
890 | + // We still wanna know when it ends for keeping the composition time window up-to-date |
891 | + TouchRegistry::instance()->addTouchWatcher(touchId, q); |
892 | + setStatus(WaitingForTouch); |
893 | } else { |
894 | ddaDebug("Didn't move far enough yet. Let's wait more."); |
895 | } |
896 | @@ -371,29 +319,29 @@ |
897 | // TODO: Consider when more than one touch starts in the same event (although it's not possible |
898 | // with Mir's android-input). Have to track them all. Consider it a plus/bonus. |
899 | |
900 | - ddaDebug(m_timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event))); |
901 | + ddaDebug(d->timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event))); |
902 | |
903 | if (!isEnabled() || !isVisible()) { |
904 | QQuickItem::touchEvent(event); |
905 | return; |
906 | } |
907 | |
908 | - switch (m_status) { |
909 | - case WaitingForTouch: |
910 | - touchEvent_absent(event); |
911 | + switch (d->status) { |
912 | + case DirectionalDragAreaPrivate::WaitingForTouch: |
913 | + d->touchEvent_absent(event); |
914 | break; |
915 | - case Undecided: |
916 | - touchEvent_undecided(event); |
917 | + case DirectionalDragAreaPrivate::Undecided: |
918 | + d->touchEvent_undecided(event); |
919 | break; |
920 | default: // Recognized: |
921 | - touchEvent_recognized(event); |
922 | + d->touchEvent_recognized(event); |
923 | break; |
924 | } |
925 | |
926 | - m_activeTouches.update(event); |
927 | + d->activeTouches.update(event); |
928 | } |
929 | |
930 | -void DirectionalDragArea::touchEvent_absent(QTouchEvent *event) |
931 | +void DirectionalDragAreaPrivate::touchEvent_absent(QTouchEvent *event) |
932 | { |
933 | // TODO: accept/reject is for the whole event, not per touch id. See how that affects us. |
934 | |
935 | @@ -423,36 +371,41 @@ |
936 | allGood = false; |
937 | } else { |
938 | // that's our candidate |
939 | - m_touchId = touchPoint.id(); |
940 | + touchId = touchPoint.id(); |
941 | newTouchPoint = &touchPoint; |
942 | } |
943 | } |
944 | } |
945 | |
946 | if (allGood) { |
947 | + allGood = sanityCheckRecognitionProperties(); |
948 | + if (!allGood) { |
949 | + qWarning("DirectionalDragArea: recognition properties are wrongly set. Gesture recognition" |
950 | + " is impossible"); |
951 | + } |
952 | + } |
953 | + |
954 | + if (allGood) { |
955 | Q_ASSERT(newTouchPoint); |
956 | |
957 | - m_startPos = newTouchPoint->pos(); |
958 | - m_startScenePos = newTouchPoint->scenePos(); |
959 | - m_touchId = newTouchPoint->id(); |
960 | - m_dampedScenePos.reset(m_startScenePos); |
961 | - m_velocityCalculator->setTrackedPosition(0.); |
962 | - m_velocityCalculator->reset(); |
963 | - m_numSamplesOnLastSpeedCheck = 0; |
964 | - m_silenceTime = 0; |
965 | - setPreviousPos(m_startPos); |
966 | - setPreviousScenePos(m_startScenePos); |
967 | + startPos = newTouchPoint->pos(); |
968 | + startScenePos = newTouchPoint->scenePos(); |
969 | + touchId = newTouchPoint->id(); |
970 | + dampedScenePos.reset(startScenePos); |
971 | + setPublicPos(startPos); |
972 | + |
973 | + setPublicScenePos(startScenePos); |
974 | updateSceneDirectionVector(); |
975 | |
976 | if (recognitionIsDisabled()) { |
977 | // Behave like a dumb TouchArea |
978 | ddaDebug("Gesture recognition is disabled. Requesting touch ownership immediately."); |
979 | - TouchRegistry::instance()->requestTouchOwnership(m_touchId, this); |
980 | + TouchRegistry::instance()->requestTouchOwnership(touchId, q); |
981 | setStatus(Recognized); |
982 | event->accept(); |
983 | } else { |
984 | // just monitor the touch points for now. |
985 | - TouchRegistry::instance()->addCandidateOwnerForTouch(m_touchId, this); |
986 | + TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, q); |
987 | |
988 | setStatus(Undecided); |
989 | // Let the item below have it. We will monitor it and grab it later if a gesture |
990 | @@ -465,12 +418,11 @@ |
991 | } |
992 | } |
993 | |
994 | -void DirectionalDragArea::touchEvent_undecided(QTouchEvent *event) |
995 | +void DirectionalDragAreaPrivate::touchEvent_undecided(QTouchEvent *event) |
996 | { |
997 | - Q_ASSERT(event->type() == QEvent::TouchBegin); |
998 | Q_ASSERT(fetchTargetTouchPoint(event) == nullptr); |
999 | |
1000 | - // We're not interested in new touch points. We already have our candidate (m_touchId). |
1001 | + // We're not interested in new touch points. We already have our candidate (touchId). |
1002 | // But we do want to know when those new touches end for keeping the composition time |
1003 | // window up-to-date |
1004 | event->ignore(); |
1005 | @@ -480,63 +432,60 @@ |
1006 | // multi-finger drags are not accepted |
1007 | ddaDebug("Multi-finger drags are not accepted"); |
1008 | |
1009 | - TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this); |
1010 | + TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); |
1011 | // We still wanna know when it ends for keeping the composition time window up-to-date |
1012 | - TouchRegistry::instance()->addTouchWatcher(m_touchId, this); |
1013 | + TouchRegistry::instance()->addTouchWatcher(touchId, q); |
1014 | |
1015 | setStatus(WaitingForTouch); |
1016 | } |
1017 | } |
1018 | |
1019 | -void DirectionalDragArea::touchEvent_recognized(QTouchEvent *event) |
1020 | +void DirectionalDragAreaPrivate::touchEvent_recognized(QTouchEvent *event) |
1021 | { |
1022 | const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event); |
1023 | |
1024 | if (!touchPoint) { |
1025 | - qCritical() << "DirectionalDragArea[status=Recognized]: touch " << m_touchId |
1026 | + qCritical() << "DirectionalDragArea[status=Recognized]: touch " << touchId |
1027 | << "missing from QTouchEvent without first reaching state Qt::TouchPointReleased. " |
1028 | "Considering it as released."; |
1029 | setStatus(WaitingForTouch); |
1030 | } else { |
1031 | - setPreviousPos(touchPoint->pos()); |
1032 | - setPreviousScenePos(touchPoint->scenePos()); |
1033 | + setPublicPos(touchPoint->pos()); |
1034 | + setPublicScenePos(touchPoint->scenePos()); |
1035 | |
1036 | if (touchPoint->state() == Qt::TouchPointReleased) { |
1037 | - emitSignalIfTapped(); |
1038 | setStatus(WaitingForTouch); |
1039 | } |
1040 | } |
1041 | } |
1042 | |
1043 | -void DirectionalDragArea::watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints) |
1044 | +void DirectionalDragAreaPrivate::watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints) |
1045 | { |
1046 | for (int i = 0; i < touchPoints.count(); ++i) { |
1047 | const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i); |
1048 | if (touchPoint.state() == Qt::TouchPointPressed) { |
1049 | - TouchRegistry::instance()->addTouchWatcher(touchPoint.id(), this); |
1050 | + TouchRegistry::instance()->addTouchWatcher(touchPoint.id(), q); |
1051 | } |
1052 | } |
1053 | } |
1054 | |
1055 | -bool DirectionalDragArea::recognitionIsDisabled() const |
1056 | -{ |
1057 | - return distanceThreshold() <= 0 && compositionTime() <= 0; |
1058 | -} |
1059 | - |
1060 | -void DirectionalDragArea::emitSignalIfTapped() |
1061 | -{ |
1062 | - qint64 touchDuration = m_timeSource->msecsSinceReference() - m_activeTouches.touchStartTime(m_touchId); |
1063 | - if (touchDuration <= maxTapDuration()) { |
1064 | - Q_EMIT tapped(); |
1065 | - } |
1066 | -} |
1067 | - |
1068 | -const QTouchEvent::TouchPoint *DirectionalDragArea::fetchTargetTouchPoint(QTouchEvent *event) |
1069 | +bool DirectionalDragAreaPrivate::recognitionIsDisabled() const |
1070 | +{ |
1071 | + return immediateRecognition || (distanceThreshold <= 0 && compositionTime <= 0); |
1072 | +} |
1073 | + |
1074 | +bool DirectionalDragAreaPrivate::sanityCheckRecognitionProperties() |
1075 | +{ |
1076 | + return recognitionIsDisabled() |
1077 | + || (distanceThreshold < maxDistance && compositionTime < maxTime); |
1078 | +} |
1079 | + |
1080 | +const QTouchEvent::TouchPoint *DirectionalDragAreaPrivate::fetchTargetTouchPoint(QTouchEvent *event) |
1081 | { |
1082 | const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints(); |
1083 | const QTouchEvent::TouchPoint *touchPoint = 0; |
1084 | for (int i = 0; i < touchPoints.size(); ++i) { |
1085 | - if (touchPoints.at(i).id() == m_touchId) { |
1086 | + if (touchPoints.at(i).id() == touchId) { |
1087 | touchPoint = &touchPoints.at(i); |
1088 | break; |
1089 | } |
1090 | @@ -544,39 +493,13 @@ |
1091 | return touchPoint; |
1092 | } |
1093 | |
1094 | -bool DirectionalDragArea::pointInsideAllowedArea() const |
1095 | -{ |
1096 | - // NB: Using squared values to avoid computing the square root to find |
1097 | - // the length totalMovement |
1098 | - |
1099 | - QPointF totalMovement(m_dampedScenePos.x() - m_startScenePos.x(), |
1100 | - m_dampedScenePos.y() - m_startScenePos.y()); |
1101 | - |
1102 | - qreal squaredTotalMovSize = totalMovement.x() * totalMovement.x() + |
1103 | - totalMovement.y() * totalMovement.y(); |
1104 | - |
1105 | - if (squaredTotalMovSize == 0.) { |
1106 | - // didn't move |
1107 | - return true; |
1108 | - } |
1109 | - |
1110 | - qreal projectedMovement = projectOntoDirectionVector(totalMovement); |
1111 | - |
1112 | - |
1113 | - qreal cosineAngleSquared = (projectedMovement * projectedMovement) / squaredTotalMovSize; |
1114 | - |
1115 | - // Same as: |
1116 | - // angle_between_movement_vector_and_gesture_direction_vector <= widening_angle |
1117 | - return cosineAngleSquared >= m_wideningFactor; |
1118 | -} |
1119 | - |
1120 | -bool DirectionalDragArea::movingInRightDirection() const |
1121 | -{ |
1122 | - if (m_direction == Direction::Horizontal) { |
1123 | +bool DirectionalDragAreaPrivate::movingInRightDirection() const |
1124 | +{ |
1125 | + if (direction == Direction::Horizontal) { |
1126 | return true; |
1127 | } else { |
1128 | - QPointF movementVector(m_dampedScenePos.x() - m_previousDampedScenePos.x(), |
1129 | - m_dampedScenePos.y() - m_previousDampedScenePos.y()); |
1130 | + QPointF movementVector(dampedScenePos.x() - previousDampedScenePos.x(), |
1131 | + dampedScenePos.y() - previousDampedScenePos.y()); |
1132 | |
1133 | qreal scalarProjection = projectOntoDirectionVector(movementVector); |
1134 | |
1135 | @@ -584,96 +507,93 @@ |
1136 | } |
1137 | } |
1138 | |
1139 | -bool DirectionalDragArea::movedFarEnough(const QPointF &point) const |
1140 | +bool DirectionalDragAreaPrivate::movedFarEnoughAlongGestureAxis() const |
1141 | { |
1142 | - if (m_distanceThreshold <= 0.) { |
1143 | + if (distanceThreshold <= 0.) { |
1144 | // distance threshold check is disabled |
1145 | return true; |
1146 | } else { |
1147 | - QPointF totalMovement(point.x() - m_startScenePos.x(), |
1148 | - point.y() - m_startScenePos.y()); |
1149 | - |
1150 | - qreal squaredTotalMovSize = totalMovement.x() * totalMovement.x() + |
1151 | - totalMovement.y() * totalMovement.y(); |
1152 | - |
1153 | - return squaredTotalMovSize > m_distanceThresholdSquared; |
1154 | - } |
1155 | -} |
1156 | - |
1157 | -void DirectionalDragArea::checkSpeed() |
1158 | -{ |
1159 | - Q_ASSERT(m_status == Undecided); |
1160 | - |
1161 | - if (m_velocityCalculator->numSamples() >= AxisVelocityCalculator::MIN_SAMPLES_NEEDED) { |
1162 | - qreal speed = qFabs(m_velocityCalculator->calculate()); |
1163 | - qreal minSpeedMsecs = m_minSpeed / 1000.0; |
1164 | - |
1165 | - if (speed < minSpeedMsecs) { |
1166 | - ddaDebug("Rejecting gesture because it's below minimum speed."); |
1167 | - TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this); |
1168 | - TouchRegistry::instance()->addTouchWatcher(m_touchId, this); |
1169 | - setStatus(WaitingForTouch); |
1170 | - } |
1171 | - } |
1172 | - |
1173 | - if (m_velocityCalculator->numSamples() == m_numSamplesOnLastSpeedCheck) { |
1174 | - m_silenceTime += m_recognitionTimer->interval(); |
1175 | - |
1176 | - if (m_silenceTime > m_maxSilenceTime) { |
1177 | - ddaDebug("Rejecting gesture because its silence time has been exceeded."); |
1178 | - TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this); |
1179 | - TouchRegistry::instance()->addTouchWatcher(m_touchId, this); |
1180 | - setStatus(WaitingForTouch); |
1181 | - } |
1182 | - } else { |
1183 | - m_silenceTime = 0; |
1184 | - } |
1185 | - m_numSamplesOnLastSpeedCheck = m_velocityCalculator->numSamples(); |
1186 | -} |
1187 | - |
1188 | -void DirectionalDragArea::giveUpIfDisabledOrInvisible() |
1189 | -{ |
1190 | - if (!isEnabled() || !isVisible()) { |
1191 | - if (m_status == Undecided) { |
1192 | - TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this); |
1193 | + QPointF totalMovement(dampedScenePos.x() - startScenePos.x(), |
1194 | + dampedScenePos.y() - startScenePos.y()); |
1195 | + |
1196 | + qreal scalarProjection = projectOntoDirectionVector(totalMovement); |
1197 | + |
1198 | + ddaDebug(" movedFarEnoughAlongGestureAxis: scalarProjection=" << scalarProjection |
1199 | + << ", distanceThreshold=" << distanceThreshold); |
1200 | + |
1201 | + if (direction == Direction::Horizontal) { |
1202 | + return qAbs(scalarProjection) > distanceThreshold; |
1203 | + } else { |
1204 | + return scalarProjection > distanceThreshold; |
1205 | + } |
1206 | + } |
1207 | +} |
1208 | + |
1209 | +bool DirectionalDragAreaPrivate::isPastMaxDistance() const |
1210 | +{ |
1211 | + QPointF totalMovement(dampedScenePos.x() - startScenePos.x(), |
1212 | + dampedScenePos.y() - startScenePos.y()); |
1213 | + |
1214 | + qreal squaredDistance = totalMovement.x()*totalMovement.x() + totalMovement.y()*totalMovement.y(); |
1215 | + return squaredDistance > maxDistance*maxDistance; |
1216 | +} |
1217 | + |
1218 | +void DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible() |
1219 | +{ |
1220 | + if (!q->isEnabled() || !q->isVisible()) { |
1221 | + if (status == Undecided) { |
1222 | + TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); |
1223 | // We still wanna know when it ends for keeping the composition time window up-to-date |
1224 | - TouchRegistry::instance()->addTouchWatcher(m_touchId, this); |
1225 | + TouchRegistry::instance()->addTouchWatcher(touchId, q); |
1226 | } |
1227 | |
1228 | - if (m_status != WaitingForTouch) { |
1229 | + if (status != WaitingForTouch) { |
1230 | ddaDebug("Resetting status because got disabled or made invisible"); |
1231 | setStatus(WaitingForTouch); |
1232 | } |
1233 | } |
1234 | } |
1235 | |
1236 | -void DirectionalDragArea::setStatus(DirectionalDragArea::Status newStatus) |
1237 | -{ |
1238 | - if (newStatus == m_status) |
1239 | +void DirectionalDragAreaPrivate::rejectGesture() |
1240 | +{ |
1241 | + if (status == Undecided) { |
1242 | + ddaDebug("Rejecting gesture because it's taking too long to drag beyond the threshold."); |
1243 | + |
1244 | + TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); |
1245 | + // We still wanna know when it ends for keeping the composition time window up-to-date |
1246 | + TouchRegistry::instance()->addTouchWatcher(touchId, q); |
1247 | + |
1248 | + setStatus(WaitingForTouch); |
1249 | + } |
1250 | +} |
1251 | + |
1252 | +void DirectionalDragAreaPrivate::setStatus(Status newStatus) |
1253 | +{ |
1254 | + if (newStatus == status) |
1255 | return; |
1256 | |
1257 | - DirectionalDragArea::Status oldStatus = m_status; |
1258 | + Status oldStatus = status; |
1259 | |
1260 | if (oldStatus == Undecided) { |
1261 | - m_recognitionTimer->stop(); |
1262 | + recognitionTimer->stop(); |
1263 | } |
1264 | |
1265 | - m_status = newStatus; |
1266 | - Q_EMIT statusChanged(m_status); |
1267 | + status = newStatus; |
1268 | + Q_EMIT statusChanged(status); |
1269 | |
1270 | ddaDebug(statusToString(oldStatus) << " -> " << statusToString(newStatus)); |
1271 | |
1272 | switch (newStatus) { |
1273 | case WaitingForTouch: |
1274 | - Q_EMIT draggingChanged(false); |
1275 | + if (oldStatus == Recognized) { |
1276 | + Q_EMIT q->draggingChanged(false); |
1277 | + } |
1278 | break; |
1279 | case Undecided: |
1280 | - m_recognitionTimer->start(); |
1281 | - Q_EMIT draggingChanged(true); |
1282 | + recognitionTimer->start(); |
1283 | break; |
1284 | case Recognized: |
1285 | - if (oldStatus == WaitingForTouch) |
1286 | - Q_EMIT draggingChanged(true); |
1287 | + Q_EMIT q->draggingChanged(true); |
1288 | break; |
1289 | default: |
1290 | // no-op |
1291 | @@ -681,77 +601,126 @@ |
1292 | } |
1293 | } |
1294 | |
1295 | -void DirectionalDragArea::setPreviousPos(const QPointF &point) |
1296 | +void DirectionalDragAreaPrivate::setPublicPos(const QPointF &point) |
1297 | { |
1298 | - bool xChanged = m_previousPos.x() != point.x(); |
1299 | - bool yChanged = m_previousPos.y() != point.y(); |
1300 | - |
1301 | - m_previousPos = point; |
1302 | + bool xChanged = publicPos.x() != point.x(); |
1303 | + bool yChanged = publicPos.y() != point.y(); |
1304 | + |
1305 | + // Public position should not get updated while the gesture is still being recognized |
1306 | + // (ie, Undecided status). |
1307 | + Q_ASSERT(status == WaitingForTouch || status == Recognized); |
1308 | + |
1309 | + if (status == Recognized && !recognitionIsDisabled()) { |
1310 | + // When the gesture finally gets recognized, the finger will likely be |
1311 | + // reasonably far from the edge. If we made the contentX immediately |
1312 | + // follow the finger position it would be visually unpleasant as it |
1313 | + // would appear right next to the user's finger out of nowhere (ie, |
1314 | + // it would jump). Instead, we make contentX go towards the user's |
1315 | + // finger in several steps. ie., in an animated way. |
1316 | + QPointF delta = point - publicPos; |
1317 | + // the trick is not to go all the way (1.0) as it would cause a sudden jump |
1318 | + publicPos.rx() += 0.4 * delta.x(); |
1319 | + publicPos.ry() += 0.4 * delta.y(); |
1320 | + } else { |
1321 | + // no smoothing when initializing or if gesture recognition was immediate as there will |
1322 | + // be no jump. |
1323 | + publicPos = point; |
1324 | + } |
1325 | |
1326 | if (xChanged) { |
1327 | - Q_EMIT touchXChanged(point.x()); |
1328 | - if (Direction::isHorizontal(m_direction)) |
1329 | - Q_EMIT distanceChanged(distance()); |
1330 | + Q_EMIT q->touchXChanged(publicPos.x()); |
1331 | + if (Direction::isHorizontal(direction)) |
1332 | + Q_EMIT q->distanceChanged(q->distance()); |
1333 | } |
1334 | |
1335 | if (yChanged) { |
1336 | - Q_EMIT touchYChanged(point.y()); |
1337 | - if (Direction::isVertical(m_direction)) |
1338 | - Q_EMIT distanceChanged(distance()); |
1339 | + Q_EMIT q->touchYChanged(publicPos.y()); |
1340 | + if (Direction::isVertical(direction)) |
1341 | + Q_EMIT q->distanceChanged(q->distance()); |
1342 | } |
1343 | } |
1344 | |
1345 | -void DirectionalDragArea::setPreviousScenePos(const QPointF &point) |
1346 | +void DirectionalDragAreaPrivate::setPublicScenePos(const QPointF &point) |
1347 | { |
1348 | - bool xChanged = m_previousScenePos.x() != point.x(); |
1349 | - bool yChanged = m_previousScenePos.y() != point.y(); |
1350 | + bool xChanged = publicScenePos.x() != point.x(); |
1351 | + bool yChanged = publicScenePos.y() != point.y(); |
1352 | |
1353 | if (!xChanged && !yChanged) |
1354 | return; |
1355 | |
1356 | - qreal oldSceneDistance = sceneDistance(); |
1357 | - m_previousScenePos = point; |
1358 | + // Public position should not get updated while the gesture is still being recognized |
1359 | + // (ie, Undecided status). |
1360 | + Q_ASSERT(status == WaitingForTouch || status == Recognized); |
1361 | + |
1362 | + qreal oldSceneDistance = sceneDistance; |
1363 | + |
1364 | + if (status == Recognized && !recognitionIsDisabled()) { |
1365 | + // When the gesture finally gets recognized, the finger will likely be |
1366 | + // reasonably far from the edge. If we made the contentX immediately |
1367 | + // follow the finger position it would be visually unpleasant as it |
1368 | + // would appear right next to the user's finger out of nowhere (ie, |
1369 | + // it would jump). Instead, we make contentX go towards the user's |
1370 | + // finger in several steps. ie., in an animated way. |
1371 | + QPointF delta = point - publicScenePos; |
1372 | + // the trick is not to go all the way (1.0) as it would cause a sudden jump |
1373 | + publicScenePos.rx() += 0.4 * delta.x(); |
1374 | + publicScenePos.ry() += 0.4 * delta.y(); |
1375 | + } else { |
1376 | + // no smoothing when initializing or if gesture recognition was immediate as there will |
1377 | + // be no jump. |
1378 | + publicScenePos = point; |
1379 | + } |
1380 | + |
1381 | updateSceneDistance(); |
1382 | |
1383 | - if (oldSceneDistance != sceneDistance()) { |
1384 | - Q_EMIT sceneDistanceChanged(sceneDistance()); |
1385 | + if (oldSceneDistance != sceneDistance) { |
1386 | + Q_EMIT q->sceneDistanceChanged(sceneDistance); |
1387 | } |
1388 | |
1389 | if (xChanged) { |
1390 | - Q_EMIT touchSceneXChanged(point.x()); |
1391 | + Q_EMIT q->touchSceneXChanged(publicScenePos.x()); |
1392 | } |
1393 | |
1394 | if (yChanged) { |
1395 | - Q_EMIT touchSceneYChanged(point.y()); |
1396 | + Q_EMIT q->touchSceneYChanged(publicScenePos.y()); |
1397 | } |
1398 | } |
1399 | |
1400 | -void DirectionalDragArea::updateVelocityCalculator(const QPointF &scenePos) |
1401 | -{ |
1402 | - QPointF totalSceneMovement = scenePos - m_startScenePos; |
1403 | - |
1404 | - qreal scalarProjection = projectOntoDirectionVector(totalSceneMovement); |
1405 | - |
1406 | - m_velocityCalculator->setTrackedPosition(scalarProjection); |
1407 | -} |
1408 | - |
1409 | -bool DirectionalDragArea::isWithinTouchCompositionWindow() |
1410 | +bool DirectionalDragAreaPrivate::isWithinTouchCompositionWindow() |
1411 | { |
1412 | return |
1413 | - compositionTime() > 0 && |
1414 | - !m_activeTouches.isEmpty() && |
1415 | - m_timeSource->msecsSinceReference() <= |
1416 | - m_activeTouches.mostRecentStartTime() + (qint64)compositionTime(); |
1417 | + compositionTime > 0 && |
1418 | + !activeTouches.isEmpty() && |
1419 | + timeSource->msecsSinceReference() <= |
1420 | + activeTouches.mostRecentStartTime() + (qint64)compositionTime; |
1421 | +} |
1422 | + |
1423 | +void DirectionalDragArea::itemChange(ItemChange change, const ItemChangeData &value) |
1424 | +{ |
1425 | + if (change == QQuickItem::ItemSceneChange) { |
1426 | + if (value.window != nullptr) { |
1427 | + // TODO: Handle window->screen() changes (ie window changing screens) |
1428 | + qreal pixelsPerMm = value.window->screen()->physicalDotsPerInch() / 25.4; |
1429 | + d->setPixelsPerMm(pixelsPerMm); |
1430 | + } |
1431 | + } |
1432 | +} |
1433 | + |
1434 | +void DirectionalDragAreaPrivate::setPixelsPerMm(qreal pixelsPerMm) |
1435 | +{ |
1436 | + dampedScenePos.setMaxDelta(1. * pixelsPerMm); |
1437 | + setDistanceThreshold(4. * pixelsPerMm); |
1438 | + maxDistance = 10. * pixelsPerMm; |
1439 | } |
1440 | |
1441 | //************************** ActiveTouchesInfo ************************** |
1442 | |
1443 | -DirectionalDragArea::ActiveTouchesInfo::ActiveTouchesInfo(const SharedTimeSource &timeSource) |
1444 | +ActiveTouchesInfo::ActiveTouchesInfo(const SharedTimeSource &timeSource) |
1445 | : m_timeSource(timeSource) |
1446 | { |
1447 | } |
1448 | |
1449 | -void DirectionalDragArea::ActiveTouchesInfo::update(QTouchEvent *event) |
1450 | +void ActiveTouchesInfo::update(QTouchEvent *event) |
1451 | { |
1452 | if (!(event->touchPointStates() & (Qt::TouchPointPressed | Qt::TouchPointReleased))) { |
1453 | // nothing to update |
1454 | @@ -773,7 +742,7 @@ |
1455 | } |
1456 | |
1457 | #if ACTIVETOUCHESINFO_DEBUG |
1458 | -QString DirectionalDragArea::ActiveTouchesInfo::toString() |
1459 | +QString ActiveTouchesInfo::toString() |
1460 | { |
1461 | QString string = "("; |
1462 | |
1463 | @@ -791,7 +760,7 @@ |
1464 | } |
1465 | #endif // ACTIVETOUCHESINFO_DEBUG |
1466 | |
1467 | -void DirectionalDragArea::ActiveTouchesInfo::addTouchPoint(int touchId) |
1468 | +void ActiveTouchesInfo::addTouchPoint(int touchId) |
1469 | { |
1470 | ActiveTouchInfo &activeTouchInfo = m_touchInfoPool.getEmptySlot(); |
1471 | activeTouchInfo.id = touchId; |
1472 | @@ -802,7 +771,7 @@ |
1473 | #endif |
1474 | } |
1475 | |
1476 | -qint64 DirectionalDragArea::ActiveTouchesInfo::touchStartTime(int touchId) |
1477 | +qint64 ActiveTouchesInfo::touchStartTime(int touchId) |
1478 | { |
1479 | qint64 result = -1; |
1480 | |
1481 | @@ -819,7 +788,7 @@ |
1482 | return result; |
1483 | } |
1484 | |
1485 | -void DirectionalDragArea::ActiveTouchesInfo::removeTouchPoint(int touchId) |
1486 | +void ActiveTouchesInfo::removeTouchPoint(int touchId) |
1487 | { |
1488 | m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) { |
1489 | if (touchId == touchInfo->id) { |
1490 | @@ -835,7 +804,7 @@ |
1491 | #endif |
1492 | } |
1493 | |
1494 | -qint64 DirectionalDragArea::ActiveTouchesInfo::mostRecentStartTime() |
1495 | +qint64 ActiveTouchesInfo::mostRecentStartTime() |
1496 | { |
1497 | Q_ASSERT(!m_touchInfoPool.isEmpty()); |
1498 | |
1499 | @@ -851,11 +820,11 @@ |
1500 | return highestStartTime; |
1501 | } |
1502 | |
1503 | -void DirectionalDragArea::updateSceneDirectionVector() |
1504 | +void DirectionalDragAreaPrivate::updateSceneDirectionVector() |
1505 | { |
1506 | QPointF localOrigin(0., 0.); |
1507 | QPointF localDirection; |
1508 | - switch (m_direction) { |
1509 | + switch (direction) { |
1510 | case Direction::Upwards: |
1511 | localDirection.rx() = 0.; |
1512 | localDirection.ry() = -1.; |
1513 | @@ -873,14 +842,31 @@ |
1514 | localDirection.ry() = 0.; |
1515 | break; |
1516 | } |
1517 | - QPointF sceneOrigin = mapToScene(localOrigin); |
1518 | - QPointF sceneDirection = mapToScene(localDirection); |
1519 | - m_sceneDirectionVector = sceneDirection - sceneOrigin; |
1520 | -} |
1521 | - |
1522 | -qreal DirectionalDragArea::projectOntoDirectionVector(const QPointF &sceneVector) const |
1523 | -{ |
1524 | - // same as dot product as m_sceneDirectionVector is a unit vector |
1525 | - return sceneVector.x() * m_sceneDirectionVector.x() + |
1526 | - sceneVector.y() * m_sceneDirectionVector.y(); |
1527 | + QPointF sceneOrigin = q->mapToScene(localOrigin); |
1528 | + QPointF sceneDirection = q->mapToScene(localDirection); |
1529 | + sceneDirectionVector = sceneDirection - sceneOrigin; |
1530 | +} |
1531 | + |
1532 | +qreal DirectionalDragAreaPrivate::projectOntoDirectionVector(const QPointF &sceneVector) const |
1533 | +{ |
1534 | + // same as dot product as sceneDirectionVector is a unit vector |
1535 | + return sceneVector.x() * sceneDirectionVector.x() + |
1536 | + sceneVector.y() * sceneDirectionVector.y(); |
1537 | +} |
1538 | + |
1539 | +DirectionalDragAreaPrivate::DirectionalDragAreaPrivate(DirectionalDragArea *q) |
1540 | + : q(q) |
1541 | + , status(WaitingForTouch) |
1542 | + , sceneDistance(0) |
1543 | + , touchId(-1) |
1544 | + , direction(Direction::Rightwards) |
1545 | + , distanceThreshold(0) |
1546 | + , distanceThresholdSquared(0.) |
1547 | + , maxTime(400) |
1548 | + , compositionTime(60) |
1549 | + , immediateRecognition(false) |
1550 | + , recognitionTimer(nullptr) |
1551 | + , timeSource(new RealTimeSource) |
1552 | + , activeTouches(timeSource) |
1553 | +{ |
1554 | } |
1555 | |
1556 | === modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea.h' |
1557 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.h 2014-10-01 13:20:32 +0000 |
1558 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.h 2015-04-10 21:17:56 +0000 |
1559 | @@ -18,7 +18,6 @@ |
1560 | #define DIRECTIONAL_DRAG_AREA_H |
1561 | |
1562 | #include <QtQuick/QQuickItem> |
1563 | -#include "AxisVelocityCalculator.h" |
1564 | #include "UbuntuGesturesQmlGlobal.h" |
1565 | #include "Damper.h" |
1566 | #include "Direction.h" |
1567 | @@ -29,6 +28,7 @@ |
1568 | |
1569 | class TouchOwnershipEvent; |
1570 | class UnownedTouchEvent; |
1571 | +class DirectionalDragAreaPrivate; |
1572 | |
1573 | /* |
1574 | An area that detects axis-aligned single-finger drag gestures |
1575 | @@ -61,95 +61,28 @@ |
1576 | Q_PROPERTY(qreal touchSceneX READ touchSceneX NOTIFY touchSceneXChanged) |
1577 | Q_PROPERTY(qreal touchSceneY READ touchSceneY NOTIFY touchSceneYChanged) |
1578 | |
1579 | - // The current status of the directional drag gesture area. |
1580 | - Q_PROPERTY(Status status READ status NOTIFY statusChanged) |
1581 | - |
1582 | // Whether a drag gesture is taking place |
1583 | - // This will be true as long as status is Undecided or Recognized |
1584 | - // When a gesture gets rejected, dragging turns to false. |
1585 | Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) |
1586 | |
1587 | - ///// |
1588 | - // stuff that will be set in stone at some point |
1589 | - |
1590 | - // How far the touch point can move away from its expected position before |
1591 | - // it causes a rejection in the gesture recognition. This is to compensate |
1592 | - // for both noise in the touch input signal and for the natural irregularities |
1593 | - // in the finger movement. |
1594 | - // Proper value is likely device-specific. |
1595 | - Q_PROPERTY(qreal maxDeviation READ maxDeviation WRITE setMaxDeviation NOTIFY maxDeviationChanged) |
1596 | - |
1597 | - // Widening angle, in degrees |
1598 | - // It's roughly the maximum angle a touch point can make relative to the |
1599 | - // axis defined by the compoment's direction for it to be recognized as a |
1600 | - // directional drag. |
1601 | - Q_PROPERTY(qreal wideningAngle READ wideningAngle WRITE setWideningAngle |
1602 | - NOTIFY wideningAngleChanged) |
1603 | - |
1604 | - // How far a touch point has to move from its initial position in order for |
1605 | - // it to be recognized as a directional drag. |
1606 | - Q_PROPERTY(qreal distanceThreshold READ distanceThreshold WRITE setDistanceThreshold |
1607 | - NOTIFY distanceThresholdChanged) |
1608 | - |
1609 | - // Minimum speed a gesture needs to have in order to be recognized as a |
1610 | - // directional drag. |
1611 | - // In pixels per second |
1612 | - Q_PROPERTY(qreal minSpeed READ minSpeed WRITE setMinSpeed NOTIFY minSpeedChanged) |
1613 | - |
1614 | - // A gesture will be rejected if more than maxSilenceTime milliseconds has |
1615 | - // passed since we last got an input event from it (during Undecided state). |
1616 | - // |
1617 | - // Silence (i.e., lack of new input events) doesn't necessarily mean that the user's |
1618 | - // finger is still (zero drag speed). In some cases the finger might be moving but |
1619 | - // the driver's high noise filtering might cause those silence periods, specially |
1620 | - // in the moments succeeding a press (talking about Galaxy Nexus here). |
1621 | - Q_PROPERTY(int maxSilenceTime READ maxSilenceTime |
1622 | - WRITE setMaxSilenceTime |
1623 | - NOTIFY maxSilenceTimeChanged) |
1624 | - |
1625 | - // |
1626 | - ///// |
1627 | - |
1628 | - // Maximum time (in milliseconds) after the start of a given touch point where |
1629 | - // subsequent touch starts are grouped with the first one into an N-touches gesture |
1630 | - // (e.g. a two-fingers tap or drag). |
1631 | - Q_PROPERTY(int compositionTime READ compositionTime |
1632 | - WRITE setCompositionTime |
1633 | - NOTIFY compositionTimeChanged) |
1634 | + // Whether a gesture should be Recognized as soon a touch lands on the area. |
1635 | + // With this property enabled it will work pretty much like a MultiPointTouchArea, |
1636 | + // just with a different API. |
1637 | + // |
1638 | + // It's false by default. In most cases you will not want that enabled. |
1639 | + Q_PROPERTY(bool immediateRecognition |
1640 | + READ immediateRecognition |
1641 | + WRITE setImmediateRecognition |
1642 | + NOTIFY immediateRecognitionChanged) |
1643 | |
1644 | Q_ENUMS(Direction) |
1645 | - Q_ENUMS(Status) |
1646 | public: |
1647 | DirectionalDragArea(QQuickItem *parent = 0); |
1648 | |
1649 | Direction::Type direction() const; |
1650 | void setDirection(Direction::Type); |
1651 | |
1652 | - // Describes the state of the directional drag gesture. |
1653 | - enum Status { |
1654 | - // Waiting for a new touch point to land on this area. No gesture is being processed |
1655 | - // or tracked. |
1656 | - WaitingForTouch, |
1657 | - |
1658 | - // A touch point has landed on this area but it's not know yet whether it is |
1659 | - // performing a drag in the correct direction. |
1660 | - // If it's decided that the touch point is not performing a directional drag gesture, |
1661 | - // it will be rejected/ignored and status will return to WaitingForTouch. |
1662 | - Undecided, //Recognizing, |
1663 | - |
1664 | - // There's a touch point in this area and it performed a drag in the correct |
1665 | - // direction. |
1666 | - // |
1667 | - // Once recognized, the gesture state will move back to WaitingForTouch only once |
1668 | - // that touch point ends. The gesture will remain in the Recognized state even if |
1669 | - // the touch point starts moving in other directions or halts. |
1670 | - Recognized, |
1671 | - }; |
1672 | - Status status() const { return m_status; } |
1673 | - |
1674 | qreal distance() const; |
1675 | qreal sceneDistance() const; |
1676 | - void updateSceneDistance(); |
1677 | |
1678 | qreal touchX() const; |
1679 | qreal touchY() const; |
1680 | @@ -157,152 +90,30 @@ |
1681 | qreal touchSceneX() const; |
1682 | qreal touchSceneY() const; |
1683 | |
1684 | - bool dragging() const { return (m_status == Undecided) || (m_status == Recognized); } |
1685 | - |
1686 | - qreal maxDeviation() const { return m_dampedScenePos.maxDelta(); } |
1687 | - void setMaxDeviation(qreal value); |
1688 | - |
1689 | - qreal wideningAngle() const; |
1690 | - void setWideningAngle(qreal value); |
1691 | - |
1692 | - qreal distanceThreshold() const { return m_distanceThreshold; } |
1693 | - void setDistanceThreshold(qreal value); |
1694 | - |
1695 | - qreal minSpeed() const { return m_minSpeed; } |
1696 | - void setMinSpeed(qreal value); |
1697 | - |
1698 | - int maxSilenceTime() const { return m_maxSilenceTime; } |
1699 | - void setMaxSilenceTime(int value); |
1700 | - |
1701 | - int compositionTime() const { return m_compositionTime; } |
1702 | - void setCompositionTime(int value); |
1703 | - |
1704 | - // Replaces the existing Timer with the given one. |
1705 | - // |
1706 | - // Useful for providing a fake timer when testing. |
1707 | - void setRecognitionTimer(UbuntuGestures::AbstractTimer *timer); |
1708 | - |
1709 | - // Useful for testing, where a fake time source can be supplied |
1710 | - void setTimeSource(const UbuntuGestures::SharedTimeSource &timeSource); |
1711 | + bool dragging() const; |
1712 | + |
1713 | + bool immediateRecognition() const; |
1714 | + void setImmediateRecognition(bool enabled); |
1715 | |
1716 | bool event(QEvent *e) override; |
1717 | |
1718 | - // Maximum time, in milliseconds, between a press and a release, for a touch |
1719 | - // sequence to be considered a tap. |
1720 | - int maxTapDuration() const { return 300; } |
1721 | - |
1722 | Q_SIGNALS: |
1723 | void directionChanged(Direction::Type direction); |
1724 | - void statusChanged(Status value); |
1725 | void draggingChanged(bool value); |
1726 | void distanceChanged(qreal value); |
1727 | void sceneDistanceChanged(qreal value); |
1728 | - void maxDeviationChanged(qreal value); |
1729 | - void wideningAngleChanged(qreal value); |
1730 | - void distanceThresholdChanged(qreal value); |
1731 | - void minSpeedChanged(qreal value); |
1732 | - void maxSilenceTimeChanged(int value); |
1733 | - void compositionTimeChanged(int value); |
1734 | void touchXChanged(qreal value); |
1735 | void touchYChanged(qreal value); |
1736 | void touchSceneXChanged(qreal value); |
1737 | void touchSceneYChanged(qreal value); |
1738 | - |
1739 | - // TODO: I would rather not have such signal as it has nothing to do with drag gestures. |
1740 | - // Remove when no longer used or move its implementation to the QML code that uses it |
1741 | - // See maxTapDuration() |
1742 | - void tapped(); |
1743 | + void immediateRecognitionChanged(bool value); |
1744 | |
1745 | protected: |
1746 | virtual void touchEvent(QTouchEvent *event); |
1747 | - |
1748 | -private Q_SLOTS: |
1749 | - void checkSpeed(); |
1750 | - void giveUpIfDisabledOrInvisible(); |
1751 | - |
1752 | -private: |
1753 | - void touchEvent_absent(QTouchEvent *event); |
1754 | - void touchEvent_undecided(QTouchEvent *event); |
1755 | - void touchEvent_recognized(QTouchEvent *event); |
1756 | - bool pointInsideAllowedArea() const; |
1757 | - bool movingInRightDirection() const; |
1758 | - bool movedFarEnough(const QPointF &point) const; |
1759 | - const QTouchEvent::TouchPoint *fetchTargetTouchPoint(QTouchEvent *event); |
1760 | - void setStatus(Status newStatus); |
1761 | - void setPreviousPos(const QPointF &point); |
1762 | - void setPreviousScenePos(const QPointF &point); |
1763 | - void updateVelocityCalculator(const QPointF &point); |
1764 | - bool isWithinTouchCompositionWindow(); |
1765 | - void updateSceneDirectionVector(); |
1766 | - // returns the scalar projection between the given vector (in scene coordinates) |
1767 | - // and m_sceneDirectionVector |
1768 | - qreal projectOntoDirectionVector(const QPointF &sceneVector) const; |
1769 | - void touchOwnershipEvent(TouchOwnershipEvent *event); |
1770 | - void unownedTouchEvent(UnownedTouchEvent *event); |
1771 | - void unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent); |
1772 | - void watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints); |
1773 | - bool recognitionIsDisabled() const; |
1774 | - void emitSignalIfTapped(); |
1775 | - |
1776 | - Status m_status; |
1777 | - |
1778 | - QPointF m_startPos; |
1779 | - QPointF m_startScenePos; |
1780 | - QPointF m_previousPos; |
1781 | - QPointF m_previousScenePos; |
1782 | - qreal m_sceneDistance; |
1783 | - int m_touchId; |
1784 | - |
1785 | - // A movement damper is used in some of the gesture recognition calculations |
1786 | - // to get rid of noise or small oscillations in the touch position. |
1787 | - DampedPointF m_dampedScenePos; |
1788 | - QPointF m_previousDampedScenePos; |
1789 | - |
1790 | - // Unit vector in scene coordinates describing the direction of the gesture recognition |
1791 | - QPointF m_sceneDirectionVector; |
1792 | - |
1793 | - Direction::Type m_direction; |
1794 | - qreal m_wideningAngle; // in degrees |
1795 | - qreal m_wideningFactor; // it's pow(cosine(m_wideningAngle), 2) |
1796 | - qreal m_distanceThreshold; |
1797 | - qreal m_distanceThresholdSquared; // it's pow(m_distanceThreshold, 2) |
1798 | - qreal m_minSpeed; |
1799 | - int m_maxSilenceTime; // in milliseconds |
1800 | - int m_silenceTime; // in milliseconds |
1801 | - int m_compositionTime; // in milliseconds |
1802 | - int m_numSamplesOnLastSpeedCheck; |
1803 | - UbuntuGestures::AbstractTimer *m_recognitionTimer; |
1804 | - AxisVelocityCalculator *m_velocityCalculator; |
1805 | - |
1806 | - UbuntuGestures::SharedTimeSource m_timeSource; |
1807 | - |
1808 | - // Information about an active touch point |
1809 | - struct ActiveTouchInfo { |
1810 | - ActiveTouchInfo() : id(-1), startTime(-1) {} |
1811 | - bool isValid() const { return id != -1; } |
1812 | - void reset() { id = -1; } |
1813 | - int id; |
1814 | - qint64 startTime; |
1815 | - }; |
1816 | - class ActiveTouchesInfo { |
1817 | - public: |
1818 | - ActiveTouchesInfo(const UbuntuGestures::SharedTimeSource &timeSource); |
1819 | - void update(QTouchEvent *event); |
1820 | - qint64 touchStartTime(int id); |
1821 | - bool isEmpty() const { return m_touchInfoPool.isEmpty(); } |
1822 | - qint64 mostRecentStartTime(); |
1823 | - UbuntuGestures::SharedTimeSource m_timeSource; |
1824 | - private: |
1825 | - void addTouchPoint(int touchId); |
1826 | - void removeTouchPoint(int touchId); |
1827 | - #if ACTIVETOUCHESINFO_DEBUG |
1828 | - QString toString(); |
1829 | - #endif |
1830 | - |
1831 | - Pool<ActiveTouchInfo> m_touchInfoPool; |
1832 | - } m_activeTouches; |
1833 | - |
1834 | - friend class tst_DirectionalDragArea; |
1835 | + virtual void itemChange(ItemChange change, const ItemChangeData &value); |
1836 | + |
1837 | +public: // so tests can access it |
1838 | + DirectionalDragAreaPrivate *d; |
1839 | }; |
1840 | |
1841 | #endif // DIRECTIONAL_DRAG_AREA_H |
1842 | |
1843 | === added file 'plugins/Ubuntu/Gestures/DirectionalDragArea_p.h' |
1844 | --- plugins/Ubuntu/Gestures/DirectionalDragArea_p.h 1970-01-01 00:00:00 +0000 |
1845 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea_p.h 2015-04-10 21:17:56 +0000 |
1846 | @@ -0,0 +1,167 @@ |
1847 | +/* |
1848 | + * Copyright (C) 2015 Canonical, Ltd. |
1849 | + * |
1850 | + * This program is free software; you can redistribute it and/or modify |
1851 | + * it under the terms of the GNU General Public License as published by |
1852 | + * the Free Software Foundation; version 3. |
1853 | + * |
1854 | + * This program is distributed in the hope that it will be useful, |
1855 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1856 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1857 | + * GNU General Public License for more details. |
1858 | + * |
1859 | + * You should have received a copy of the GNU General Public License |
1860 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1861 | + */ |
1862 | + |
1863 | +#ifndef DIRECTIONAL_DRAG_AREA_PRIV_H |
1864 | +#define DIRECTIONAL_DRAG_AREA_PRIV_H |
1865 | + |
1866 | +// Information about an active touch point |
1867 | +struct UBUNTUGESTURESQML_EXPORT ActiveTouchInfo { |
1868 | + ActiveTouchInfo() : id(-1), startTime(-1) {} |
1869 | + bool isValid() const { return id != -1; } |
1870 | + void reset() { id = -1; } |
1871 | + int id; |
1872 | + qint64 startTime; |
1873 | +}; |
1874 | +class UBUNTUGESTURESQML_EXPORT ActiveTouchesInfo { |
1875 | +public: |
1876 | + ActiveTouchesInfo(const UbuntuGestures::SharedTimeSource &timeSource); |
1877 | + void update(QTouchEvent *event); |
1878 | + qint64 touchStartTime(int id); |
1879 | + bool isEmpty() const { return m_touchInfoPool.isEmpty(); } |
1880 | + qint64 mostRecentStartTime(); |
1881 | + UbuntuGestures::SharedTimeSource m_timeSource; |
1882 | +private: |
1883 | + void addTouchPoint(int touchId); |
1884 | + void removeTouchPoint(int touchId); |
1885 | + #if ACTIVETOUCHESINFO_DEBUG |
1886 | + QString toString(); |
1887 | + #endif |
1888 | + |
1889 | + Pool<ActiveTouchInfo> m_touchInfoPool; |
1890 | +}; |
1891 | + |
1892 | +class UBUNTUGESTURESQML_EXPORT DirectionalDragAreaPrivate : public QObject { |
1893 | + Q_OBJECT |
1894 | + |
1895 | + Q_ENUMS(Status) |
1896 | +public: |
1897 | + DirectionalDragAreaPrivate(DirectionalDragArea *q); |
1898 | + |
1899 | +public Q_SLOTS: |
1900 | + void giveUpIfDisabledOrInvisible(); |
1901 | + void rejectGesture(); |
1902 | + |
1903 | +public: |
1904 | + // Describes the state of the directional drag gesture. |
1905 | + enum Status { |
1906 | + // Waiting for a new touch point to land on this area. No gesture is being processed |
1907 | + // or tracked. |
1908 | + WaitingForTouch, |
1909 | + |
1910 | + // A touch point has landed on this area but it's not know yet whether it is |
1911 | + // performing a drag in the correct direction. |
1912 | + // If it's decided that the touch point is not performing a directional drag gesture, |
1913 | + // it will be rejected/ignored and status will return to WaitingForTouch. |
1914 | + Undecided, //Recognizing, |
1915 | + |
1916 | + // There's a touch point in this area and it performed a drag in the correct |
1917 | + // direction. |
1918 | + // |
1919 | + // Once recognized, the gesture state will move back to WaitingForTouch only once |
1920 | + // that touch point ends. The gesture will remain in the Recognized state even if |
1921 | + // the touch point starts moving in other directions or halts. |
1922 | + Recognized, |
1923 | + }; |
1924 | + |
1925 | + void touchEvent_absent(QTouchEvent *event); |
1926 | + void touchEvent_undecided(QTouchEvent *event); |
1927 | + void touchEvent_recognized(QTouchEvent *event); |
1928 | + bool movingInRightDirection() const; |
1929 | + bool movedFarEnoughAlongGestureAxis() const; |
1930 | + bool isPastMaxDistance() const; |
1931 | + const QTouchEvent::TouchPoint *fetchTargetTouchPoint(QTouchEvent *event); |
1932 | + void setStatus(Status newStatus); |
1933 | + void setPublicPos(const QPointF &point); |
1934 | + void setPublicScenePos(const QPointF &point); |
1935 | + bool isWithinTouchCompositionWindow(); |
1936 | + void updateSceneDirectionVector(); |
1937 | + // returns the scalar projection between the given vector (in scene coordinates) |
1938 | + // and m_sceneDirectionVector |
1939 | + qreal projectOntoDirectionVector(const QPointF &sceneVector) const; |
1940 | + void touchOwnershipEvent(TouchOwnershipEvent *event); |
1941 | + void unownedTouchEvent(UnownedTouchEvent *event); |
1942 | + void unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent); |
1943 | + void watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints); |
1944 | + bool recognitionIsDisabled() const; |
1945 | + bool sanityCheckRecognitionProperties(); |
1946 | + void updateSceneDistance(); |
1947 | + void setMaxTime(int value); |
1948 | + void setDistanceThreshold(qreal value); |
1949 | + void setPixelsPerMm(qreal pixelsPerMm); |
1950 | + QString objectName() const { return q->objectName(); } |
1951 | + |
1952 | + // Replaces the existing Timer with the given one. |
1953 | + // |
1954 | + // Useful for providing a fake timer when testing. |
1955 | + void setRecognitionTimer(UbuntuGestures::AbstractTimer *timer); |
1956 | + |
1957 | + // Useful for testing, where a fake time source can be supplied |
1958 | + void setTimeSource(const UbuntuGestures::SharedTimeSource &timeSource); |
1959 | + |
1960 | + DirectionalDragArea *q; |
1961 | + |
1962 | + // The current status of the directional drag gesture area. |
1963 | + Status status; |
1964 | + |
1965 | + QPointF startPos; |
1966 | + QPointF startScenePos; |
1967 | + qreal sceneDistance; |
1968 | + int touchId; |
1969 | + |
1970 | + // The touch position exposed in the public API. |
1971 | + // It only starts to move once the gesture gets recognized. |
1972 | + QPointF publicPos; |
1973 | + QPointF publicScenePos; |
1974 | + |
1975 | + // A movement damper is used in some of the gesture recognition calculations |
1976 | + // to get rid of noise or small oscillations in the touch position. |
1977 | + DampedPointF dampedScenePos; |
1978 | + QPointF previousDampedScenePos; |
1979 | + |
1980 | + // Unit vector in scene coordinates describing the direction of the gesture recognition |
1981 | + QPointF sceneDirectionVector; |
1982 | + |
1983 | + Direction::Type direction; |
1984 | + |
1985 | + // How far a touch point has to move from its initial position along the gesture axis in order |
1986 | + // for it to be recognized as a directional drag. |
1987 | + qreal distanceThreshold; |
1988 | + qreal distanceThresholdSquared; // it's pow(distanceThreshold, 2) |
1989 | + |
1990 | + // Maximum time (in milliseconds) the gesture can take to go beyond the distance threshold |
1991 | + int maxTime; |
1992 | + |
1993 | + // Maximum distance the gesture can go without crossing the axis-aligned distance threshold |
1994 | + qreal maxDistance; |
1995 | + |
1996 | + // Maximum time (in milliseconds) after the start of a given touch point where |
1997 | + // subsequent touch starts are grouped with the first one into an N-touches gesture |
1998 | + // (e.g. a two-fingers tap or drag). |
1999 | + int compositionTime; |
2000 | + |
2001 | + bool immediateRecognition; |
2002 | + |
2003 | + UbuntuGestures::AbstractTimer *recognitionTimer; |
2004 | + |
2005 | + UbuntuGestures::SharedTimeSource timeSource; |
2006 | + |
2007 | + ActiveTouchesInfo activeTouches; |
2008 | + |
2009 | +Q_SIGNALS: |
2010 | + void statusChanged(Status value); |
2011 | +}; |
2012 | + |
2013 | +#endif // DIRECTIONAL_DRAG_AREA_PRIV_H |
2014 | |
2015 | === modified file 'plugins/Ubuntu/Gestures/TouchDispatcher.cpp' |
2016 | --- plugins/Ubuntu/Gestures/TouchDispatcher.cpp 2014-11-03 15:21:46 +0000 |
2017 | +++ plugins/Ubuntu/Gestures/TouchDispatcher.cpp 2015-04-10 21:17:56 +0000 |
2018 | @@ -1,5 +1,5 @@ |
2019 | /* |
2020 | - * Copyright (C) 2014 Canonical, Ltd. |
2021 | + * Copyright (C) 2014-2015 Canonical, Ltd. |
2022 | * |
2023 | * This program is free software; you can redistribute it and/or modify |
2024 | * it under the terms of the GNU General Public License as published by |
2025 | @@ -28,8 +28,11 @@ |
2026 | #define TOUCHDISPATCHER_DEBUG 0 |
2027 | |
2028 | #if TOUCHDISPATCHER_DEBUG |
2029 | +#define ugDebug(params) qDebug().nospace() << "[TouchDispatcher(" << this << ")] " << params |
2030 | #include <DebugHelpers.h> |
2031 | -#endif |
2032 | +#else // TOUCHDISPATCHER_DEBUG |
2033 | +#define ugDebug(params) ((void)0) |
2034 | +#endif // TOUCHDISPATCHER_DEBUG |
2035 | |
2036 | TouchDispatcher::TouchDispatcher() |
2037 | : m_status(NoActiveTouch) |
2038 | @@ -44,13 +47,12 @@ |
2039 | m_targetItem = target; |
2040 | if (m_status != NoActiveTouch) { |
2041 | qWarning("[TouchDispatcher] Changing target item in the middle of a touch stream"); |
2042 | - m_status = TargetRejectedTouches; |
2043 | + setStatus(TargetRejectedTouches); |
2044 | } |
2045 | } |
2046 | } |
2047 | |
2048 | -void TouchDispatcher::dispatch(QEvent::Type eventType, |
2049 | - QTouchDevice *device, |
2050 | +void TouchDispatcher::dispatch(QTouchDevice *device, |
2051 | Qt::KeyboardModifiers modifiers, |
2052 | const QList<QTouchEvent::TouchPoint> &touchPoints, |
2053 | QWindow *window, |
2054 | @@ -61,6 +63,8 @@ |
2055 | return; |
2056 | } |
2057 | |
2058 | + QEvent::Type eventType = resolveEventType(touchPoints); |
2059 | + |
2060 | if (eventType == QEvent::TouchBegin) { |
2061 | dispatchTouchBegin(device, modifiers, touchPoints, window, timestamp); |
2062 | |
2063 | @@ -72,15 +76,13 @@ |
2064 | dispatchAsMouse(device, modifiers, touchPoints, timestamp); |
2065 | } else { |
2066 | Q_ASSERT(m_status == TargetRejectedTouches); |
2067 | - #if TOUCHDISPATCHER_DEBUG |
2068 | - qDebug() << "[TouchDispatcher] Not dispatching touch event to" << m_targetItem.data() |
2069 | - << "because it already rejected the touch stream."; |
2070 | - #endif |
2071 | + ugDebug("Not dispatching touch event to " << m_targetItem.data() |
2072 | + << "because it already rejected the touch stream."); |
2073 | // Do nothing |
2074 | } |
2075 | |
2076 | if (eventType == QEvent::TouchEnd) { |
2077 | - m_status = NoActiveTouch; |
2078 | + setStatus(NoActiveTouch); |
2079 | m_touchMouseId = -1; |
2080 | } |
2081 | |
2082 | @@ -103,10 +105,7 @@ |
2083 | QQuickItem *targetItem = m_targetItem.data(); |
2084 | |
2085 | if (!targetItem->isEnabled() || !targetItem->isVisible()) { |
2086 | - #if TOUCHDISPATCHER_DEBUG |
2087 | - qDebug() << "[TouchDispatcher] Cannot dispatch touch event to" << targetItem |
2088 | - << "because it's disabled or invisible."; |
2089 | - #endif |
2090 | + ugDebug("Cannot dispatch touch event to " << targetItem << " because it's disabled or invisible."); |
2091 | return; |
2092 | } |
2093 | |
2094 | @@ -118,62 +117,46 @@ |
2095 | createQTouchEvent(QEvent::TouchBegin, device, modifiers, targetTouchPoints, window, timestamp)); |
2096 | |
2097 | |
2098 | - #if TOUCHDISPATCHER_DEBUG |
2099 | - qDebug() << "[TouchDispatcher] dispatching" << qPrintable(touchEventToString(touchEvent.data())) |
2100 | - << "to" << targetItem; |
2101 | - #endif |
2102 | + ugDebug("dispatching " << qPrintable(touchEventToString(touchEvent.data())) |
2103 | + << " to " << targetItem); |
2104 | QCoreApplication::sendEvent(targetItem, touchEvent.data()); |
2105 | |
2106 | |
2107 | if (touchEvent->isAccepted()) { |
2108 | - #if TOUCHDISPATCHER_DEBUG |
2109 | - qDebug() << "[TouchDispatcher] Item accepted the touch event."; |
2110 | - #endif |
2111 | - m_status = DeliveringTouchEvents; |
2112 | + ugDebug("Item accepted the touch event."); |
2113 | + setStatus(DeliveringTouchEvents); |
2114 | } else if (targetItem->acceptedMouseButtons() & Qt::LeftButton) { |
2115 | - #if TOUCHDISPATCHER_DEBUG |
2116 | - qDebug() << "[TouchDispatcher] Item rejected the touch event. Trying a QMouseEvent"; |
2117 | - #endif |
2118 | + ugDebug("Item rejected the touch event. Trying a QMouseEvent"); |
2119 | // NB: Arbitrarily chose the first touch point to emulate the mouse pointer |
2120 | QScopedPointer<QMouseEvent> mouseEvent( |
2121 | touchToMouseEvent(QEvent::MouseButtonPress, targetTouchPoints.at(0), timestamp, |
2122 | modifiers, false /* transformNeeded */)); |
2123 | Q_ASSERT(targetTouchPoints.at(0).state() == Qt::TouchPointPressed); |
2124 | |
2125 | - #if TOUCHDISPATCHER_DEBUG |
2126 | - qDebug() << "[TouchDispatcher] dispatching" << qPrintable(mouseEventToString(mouseEvent.data())) |
2127 | - << "to" << m_targetItem.data(); |
2128 | - #endif |
2129 | + ugDebug("dispatching " << qPrintable(mouseEventToString(mouseEvent.data())) |
2130 | + << " to " << m_targetItem.data()); |
2131 | QCoreApplication::sendEvent(targetItem, mouseEvent.data()); |
2132 | if (mouseEvent->isAccepted()) { |
2133 | - #if TOUCHDISPATCHER_DEBUG |
2134 | - qDebug() << "[TouchDispatcher] Item accepted the QMouseEvent."; |
2135 | - #endif |
2136 | - m_status = DeliveringMouseEvents; |
2137 | + ugDebug("Item accepted the QMouseEvent."); |
2138 | + setStatus(DeliveringMouseEvents); |
2139 | m_touchMouseId = targetTouchPoints.at(0).id(); |
2140 | |
2141 | if (checkIfDoubleClicked(timestamp)) { |
2142 | QScopedPointer<QMouseEvent> doubleClickEvent( |
2143 | touchToMouseEvent(QEvent::MouseButtonDblClick, targetTouchPoints.at(0), timestamp, |
2144 | modifiers, false /* transformNeeded */)); |
2145 | - #if TOUCHDISPATCHER_DEBUG |
2146 | - qDebug() << "[TouchDispatcher] dispatching" << qPrintable(mouseEventToString(doubleClickEvent.data())) |
2147 | - << "to" << m_targetItem.data(); |
2148 | - #endif |
2149 | + ugDebug("dispatching " << qPrintable(mouseEventToString(doubleClickEvent.data())) |
2150 | + << " to " << m_targetItem.data()); |
2151 | QCoreApplication::sendEvent(targetItem, doubleClickEvent.data()); |
2152 | } |
2153 | |
2154 | } else { |
2155 | - #if TOUCHDISPATCHER_DEBUG |
2156 | - qDebug() << "[TouchDispatcher] Item rejected the QMouseEvent."; |
2157 | - #endif |
2158 | - m_status = TargetRejectedTouches; |
2159 | + ugDebug("Item rejected the QMouseEvent."); |
2160 | + setStatus(TargetRejectedTouches); |
2161 | } |
2162 | } else { |
2163 | - #if TOUCHDISPATCHER_DEBUG |
2164 | - qDebug() << "[TouchDispatcher] Item rejected the touch event and does not accept mouse buttons."; |
2165 | - #endif |
2166 | - m_status = TargetRejectedTouches; |
2167 | + ugDebug("Item rejected the touch event and does not accept mouse buttons."); |
2168 | + setStatus(TargetRejectedTouches); |
2169 | } |
2170 | } |
2171 | |
2172 | @@ -194,10 +177,8 @@ |
2173 | createQTouchEvent(eventType, device, modifiers, targetTouchPoints, window, timestamp)); |
2174 | |
2175 | |
2176 | - #if TOUCHDISPATCHER_DEBUG |
2177 | - qDebug() << "[TouchDispatcher] dispatching" << qPrintable(touchEventToString(eventForTargetItem.data())) |
2178 | - << "to" << targetItem; |
2179 | - #endif |
2180 | + ugDebug("dispatching " << qPrintable(touchEventToString(eventForTargetItem.data())) |
2181 | + << " to " << targetItem); |
2182 | QCoreApplication::sendEvent(targetItem, eventForTargetItem.data()); |
2183 | } |
2184 | |
2185 | @@ -254,10 +235,8 @@ |
2186 | QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(eventType, *touchMouse, timestamp, modifiers, |
2187 | true /* transformNeeded */)); |
2188 | |
2189 | - #if TOUCHDISPATCHER_DEBUG |
2190 | - qDebug() << "[TouchDispatcher] dispatching" << qPrintable(mouseEventToString(mouseEvent.data())) |
2191 | - << "to" << m_targetItem.data(); |
2192 | - #endif |
2193 | + ugDebug("dispatching " << qPrintable(mouseEventToString(mouseEvent.data())) |
2194 | + << " to " << m_targetItem.data()); |
2195 | QCoreApplication::sendEvent(m_targetItem.data(), mouseEvent.data()); |
2196 | } |
2197 | } |
2198 | @@ -365,3 +344,59 @@ |
2199 | |
2200 | return doubleClicked; |
2201 | } |
2202 | + |
2203 | +void TouchDispatcher::setStatus(Status status) |
2204 | +{ |
2205 | + if (status != m_status) { |
2206 | + #if TOUCHDISPATCHER_DEBUG |
2207 | + switch (status) { |
2208 | + case NoActiveTouch: |
2209 | + ugDebug("status = NoActiveTouch"); |
2210 | + break; |
2211 | + case DeliveringTouchEvents: |
2212 | + ugDebug("status = DeliveringTouchEvents"); |
2213 | + break; |
2214 | + case DeliveringMouseEvents: |
2215 | + ugDebug("status = DeliveringMouseEvents"); |
2216 | + break; |
2217 | + case TargetRejectedTouches: |
2218 | + ugDebug("status = TargetRejectedTouches"); |
2219 | + break; |
2220 | + default: |
2221 | + ugDebug("status = " << status); |
2222 | + break; |
2223 | + } |
2224 | + #endif |
2225 | + m_status = status; |
2226 | + } |
2227 | +} |
2228 | + |
2229 | +void TouchDispatcher::reset() |
2230 | +{ |
2231 | + setStatus(NoActiveTouch); |
2232 | + m_touchMouseId = -1; |
2233 | + m_touchMousePressTimestamp =0; |
2234 | +} |
2235 | + |
2236 | +QEvent::Type TouchDispatcher::resolveEventType(const QList<QTouchEvent::TouchPoint> &touchPoints) |
2237 | +{ |
2238 | + QEvent::Type eventType; |
2239 | + |
2240 | + Qt::TouchPointStates eventStates = 0; |
2241 | + for (int i = 0; i < touchPoints.count(); i++) |
2242 | + eventStates |= touchPoints[i].state(); |
2243 | + |
2244 | + switch (eventStates) { |
2245 | + case Qt::TouchPointPressed: |
2246 | + eventType = QEvent::TouchBegin; |
2247 | + break; |
2248 | + case Qt::TouchPointReleased: |
2249 | + eventType = QEvent::TouchEnd; |
2250 | + break; |
2251 | + default: |
2252 | + eventType = QEvent::TouchUpdate; |
2253 | + break; |
2254 | + } |
2255 | + |
2256 | + return eventType; |
2257 | +} |
2258 | |
2259 | === modified file 'plugins/Ubuntu/Gestures/TouchDispatcher.h' |
2260 | --- plugins/Ubuntu/Gestures/TouchDispatcher.h 2014-11-03 15:21:46 +0000 |
2261 | +++ plugins/Ubuntu/Gestures/TouchDispatcher.h 2015-04-10 21:17:56 +0000 |
2262 | @@ -1,5 +1,5 @@ |
2263 | /* |
2264 | - * Copyright (C) 2014 Canonical, Ltd. |
2265 | + * Copyright (C) 2014-2015 Canonical, Ltd. |
2266 | * |
2267 | * This program is free software; you can redistribute it and/or modify |
2268 | * it under the terms of the GNU General Public License as published by |
2269 | @@ -36,12 +36,20 @@ |
2270 | void setTargetItem(QQuickItem *target); |
2271 | QQuickItem *targetItem() { return m_targetItem; } |
2272 | |
2273 | - void dispatch(QEvent::Type eventType, |
2274 | - QTouchDevice *device, |
2275 | + void dispatch(QTouchDevice *device, |
2276 | Qt::KeyboardModifiers modifiers, |
2277 | const QList<QTouchEvent::TouchPoint> &touchPoints, |
2278 | QWindow *window, |
2279 | ulong timestamp); |
2280 | + |
2281 | + void reset(); |
2282 | + |
2283 | + enum Status { |
2284 | + NoActiveTouch, |
2285 | + DeliveringTouchEvents, |
2286 | + DeliveringMouseEvents, |
2287 | + TargetRejectedTouches |
2288 | + }; |
2289 | private: |
2290 | void dispatchTouchBegin( |
2291 | QTouchDevice *device, |
2292 | @@ -73,14 +81,13 @@ |
2293 | |
2294 | bool checkIfDoubleClicked(ulong newPressEventTimestamp); |
2295 | |
2296 | + void setStatus(Status status); |
2297 | + |
2298 | + static QEvent::Type resolveEventType(const QList<QTouchEvent::TouchPoint> &touchPoints); |
2299 | + |
2300 | QPointer<QQuickItem> m_targetItem; |
2301 | |
2302 | - enum { |
2303 | - NoActiveTouch, |
2304 | - DeliveringTouchEvents, |
2305 | - DeliveringMouseEvents, |
2306 | - TargetRejectedTouches |
2307 | - } m_status; |
2308 | + Status m_status; |
2309 | |
2310 | int m_touchMouseId; |
2311 | ulong m_touchMousePressTimestamp; |
2312 | |
2313 | === modified file 'plugins/Ubuntu/Gestures/TouchGate.cpp' |
2314 | --- plugins/Ubuntu/Gestures/TouchGate.cpp 2015-01-28 12:59:21 +0000 |
2315 | +++ plugins/Ubuntu/Gestures/TouchGate.cpp 2015-04-10 21:17:56 +0000 |
2316 | @@ -1,5 +1,5 @@ |
2317 | /* |
2318 | - * Copyright (C) 2014 Canonical, Ltd. |
2319 | + * Copyright (C) 2014-2015 Canonical, Ltd. |
2320 | * |
2321 | * This program is free software; you can redistribute it and/or modify |
2322 | * it under the terms of the GNU General Public License as published by |
2323 | @@ -23,8 +23,18 @@ |
2324 | #include <TouchRegistry.h> |
2325 | |
2326 | #if TOUCHGATE_DEBUG |
2327 | +#define ugDebug(params) qDebug().nospace() << "[TouchGate(" << (void*)this << ")] " << params |
2328 | #include <DebugHelpers.h> |
2329 | -#endif |
2330 | +#else // TOUCHGATE_DEBUG |
2331 | +#define ugDebug(params) ((void)0) |
2332 | +#endif // TOUCHGATE_DEBUG |
2333 | + |
2334 | +TouchGate::TouchGate(QQuickItem *parent) |
2335 | + : QQuickItem(parent) |
2336 | +{ |
2337 | + connect(this, &QQuickItem::enabledChanged, |
2338 | + this, &TouchGate::onEnabledChanged); |
2339 | +} |
2340 | |
2341 | bool TouchGate::event(QEvent *e) |
2342 | { |
2343 | @@ -38,13 +48,12 @@ |
2344 | |
2345 | void TouchGate::touchEvent(QTouchEvent *event) |
2346 | { |
2347 | - #if TOUCHGATE_DEBUG |
2348 | - qDebug() << "[TouchGate] got touch event" << qPrintable(touchEventToString(event)); |
2349 | - #endif |
2350 | + ugDebug("got touch event" << qPrintable(touchEventToString(event))); |
2351 | event->accept(); |
2352 | |
2353 | const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints(); |
2354 | - bool goodToGo = true; |
2355 | + QList<QTouchEvent::TouchPoint> validTouchPoints; |
2356 | + bool ownsAllTouches = true; |
2357 | for (int i = 0; i < touchPoints.count(); ++i) { |
2358 | const QTouchEvent::TouchPoint &touchPoint = touchPoints[i]; |
2359 | |
2360 | @@ -57,31 +66,41 @@ |
2361 | Q_EMIT pressed(); |
2362 | } |
2363 | |
2364 | - goodToGo &= m_touchInfoMap.contains(touchPoint.id()) |
2365 | - && m_touchInfoMap[touchPoint.id()].ownership == OwnershipGranted; |
2366 | - |
2367 | - if (touchPoint.state() == Qt::TouchPointReleased && m_touchInfoMap.contains(touchPoint.id())) { |
2368 | - m_touchInfoMap[touchPoint.id()].ended = true; |
2369 | + if (m_touchInfoMap.contains(touchPoint.id())) { |
2370 | + validTouchPoints.append(touchPoint); |
2371 | + |
2372 | + ownsAllTouches &= m_touchInfoMap[touchPoint.id()].ownership == OwnershipGranted; |
2373 | + |
2374 | + if (touchPoint.state() == Qt::TouchPointReleased) { |
2375 | + m_touchInfoMap[touchPoint.id()].ended = true; |
2376 | + } |
2377 | } |
2378 | |
2379 | } |
2380 | |
2381 | - if (goodToGo) { |
2382 | + if (validTouchPoints.isEmpty()) { |
2383 | + // nothing to do. |
2384 | + return; |
2385 | + } |
2386 | + |
2387 | + if (ownsAllTouches) { |
2388 | if (m_storedEvents.isEmpty()) { |
2389 | // let it pass through |
2390 | - dispatchTouchEventToTarget(event); |
2391 | + removeTouchInfoForEndedTouches(validTouchPoints); |
2392 | + m_dispatcher.dispatch(event->device(), event->modifiers(), validTouchPoints, |
2393 | + event->window(), event->timestamp()); |
2394 | } else { |
2395 | // Retain the event to ensure TouchGate dispatches them in order. |
2396 | // Otherwise the current event would come before the stored ones, which are older. |
2397 | - #if TOUCHGATE_DEBUG |
2398 | - qDebug("[TouchGate] Storing event because thouches %s are still pending ownership.", |
2399 | - qPrintable(oldestPendingTouchIdsString())); |
2400 | - #endif |
2401 | - storeTouchEvent(event); |
2402 | + ugDebug("Storing event because thouches " << qPrintable(oldestPendingTouchIdsString()) |
2403 | + << " are still pending ownership."); |
2404 | + storeTouchEvent(event->device(), event->modifiers(), validTouchPoints, |
2405 | + event->window(), event->timestamp()); |
2406 | } |
2407 | } else { |
2408 | // Retain events that have unowned touches |
2409 | - storeTouchEvent(event); |
2410 | + storeTouchEvent(event->device(), event->modifiers(), validTouchPoints, |
2411 | + event->window(), event->timestamp()); |
2412 | } |
2413 | } |
2414 | |
2415 | @@ -90,24 +109,23 @@ |
2416 | // TODO: Optimization: batch those actions as TouchOwnershipEvents |
2417 | // might come one right after the other. |
2418 | |
2419 | - Q_ASSERT(m_touchInfoMap.contains(event->touchId())); |
2420 | - |
2421 | - TouchInfo &touchInfo = m_touchInfoMap[event->touchId()]; |
2422 | - |
2423 | - if (event->gained()) { |
2424 | - #if TOUCHGATE_DEBUG |
2425 | - qDebug() << "[TouchGate] Got ownership of touch " << event->touchId(); |
2426 | - #endif |
2427 | - touchInfo.ownership = OwnershipGranted; |
2428 | + if (m_touchInfoMap.contains(event->touchId())) { |
2429 | + TouchInfo &touchInfo = m_touchInfoMap[event->touchId()]; |
2430 | + |
2431 | + if (event->gained()) { |
2432 | + ugDebug("Got ownership of touch " << event->touchId()); |
2433 | + touchInfo.ownership = OwnershipGranted; |
2434 | + } else { |
2435 | + ugDebug("Lost ownership of touch " << event->touchId()); |
2436 | + m_touchInfoMap.remove(event->touchId()); |
2437 | + removeTouchFromStoredEvents(event->touchId()); |
2438 | + } |
2439 | + |
2440 | + dispatchFullyOwnedEvents(); |
2441 | } else { |
2442 | - #if TOUCHGATE_DEBUG |
2443 | - qDebug() << "[TouchGate] Lost ownership of touch " << event->touchId(); |
2444 | - #endif |
2445 | - m_touchInfoMap.remove(event->touchId()); |
2446 | - removeTouchFromStoredEvents(event->touchId()); |
2447 | + // Ignore it. It probably happened because the TouchGate got disabled |
2448 | + // between the time it requested ownership and the time it got it. |
2449 | } |
2450 | - |
2451 | - dispatchFullyOwnedEvents(); |
2452 | } |
2453 | |
2454 | bool TouchGate::isTouchPointOwned(int touchId) const |
2455 | @@ -115,14 +133,15 @@ |
2456 | return m_touchInfoMap[touchId].ownership == OwnershipGranted; |
2457 | } |
2458 | |
2459 | -void TouchGate::storeTouchEvent(const QTouchEvent *event) |
2460 | +void TouchGate::storeTouchEvent(QTouchDevice *device, |
2461 | + Qt::KeyboardModifiers modifiers, |
2462 | + const QList<QTouchEvent::TouchPoint> &touchPoints, |
2463 | + QWindow *window, |
2464 | + ulong timestamp) |
2465 | { |
2466 | - #if TOUCHGATE_DEBUG |
2467 | - qDebug() << "[TouchGate] Storing" << qPrintable(touchEventToString(event)); |
2468 | - #endif |
2469 | - |
2470 | - TouchEvent clonedEvent(event); |
2471 | - m_storedEvents.append(std::move(clonedEvent)); |
2472 | + ugDebug("Storing" << touchPoints); |
2473 | + TouchEvent event(device, modifiers, touchPoints, window, timestamp); |
2474 | + m_storedEvents.append(std::move(event)); |
2475 | } |
2476 | |
2477 | void TouchGate::removeTouchFromStoredEvents(int touchId) |
2478 | @@ -195,25 +214,13 @@ |
2479 | void TouchGate::dispatchTouchEventToTarget(const TouchEvent &event) |
2480 | { |
2481 | removeTouchInfoForEndedTouches(event.touchPoints); |
2482 | - m_dispatcher.dispatch(event.eventType, |
2483 | - event.device, |
2484 | + m_dispatcher.dispatch(event.device, |
2485 | event.modifiers, |
2486 | event.touchPoints, |
2487 | event.window, |
2488 | event.timestamp); |
2489 | } |
2490 | |
2491 | -void TouchGate::dispatchTouchEventToTarget(QTouchEvent* event) |
2492 | -{ |
2493 | - removeTouchInfoForEndedTouches(event->touchPoints()); |
2494 | - m_dispatcher.dispatch(event->type(), |
2495 | - event->device(), |
2496 | - event->modifiers(), |
2497 | - event->touchPoints(), |
2498 | - event->window(), |
2499 | - event->timestamp()); |
2500 | -} |
2501 | - |
2502 | void TouchGate::removeTouchInfoForEndedTouches(const QList<QTouchEvent::TouchPoint> &touchPoints) |
2503 | { |
2504 | for (int i = 0; i < touchPoints.size(); ++i) {\ |
2505 | @@ -228,14 +235,31 @@ |
2506 | } |
2507 | } |
2508 | |
2509 | -TouchGate::TouchEvent::TouchEvent(const QTouchEvent *event) |
2510 | - : eventType(event->type()) |
2511 | - , device(event->device()) |
2512 | - , modifiers(event->modifiers()) |
2513 | - , touchPoints(event->touchPoints()) |
2514 | - , target(qobject_cast<QQuickItem*>(event->target())) |
2515 | - , window(event->window()) |
2516 | - , timestamp(event->timestamp()) |
2517 | +void TouchGate::onEnabledChanged() |
2518 | +{ |
2519 | + ugDebug(" enabled = " << isEnabled()); |
2520 | + if (!isEnabled()) { |
2521 | + reset(); |
2522 | + } |
2523 | +} |
2524 | + |
2525 | +void TouchGate::reset() |
2526 | +{ |
2527 | + m_storedEvents.clear(); |
2528 | + m_touchInfoMap.clear(); |
2529 | + m_dispatcher.reset(); |
2530 | +} |
2531 | + |
2532 | +TouchGate::TouchEvent::TouchEvent(QTouchDevice *device, |
2533 | + Qt::KeyboardModifiers modifiers, |
2534 | + const QList<QTouchEvent::TouchPoint> &touchPoints, |
2535 | + QWindow *window, |
2536 | + ulong timestamp) |
2537 | + : device(device) |
2538 | + , modifiers(modifiers) |
2539 | + , touchPoints(touchPoints) |
2540 | + , window(window) |
2541 | + , timestamp(timestamp) |
2542 | { |
2543 | } |
2544 | |
2545 | |
2546 | === modified file 'plugins/Ubuntu/Gestures/TouchGate.h' |
2547 | --- plugins/Ubuntu/Gestures/TouchGate.h 2015-01-28 12:59:21 +0000 |
2548 | +++ plugins/Ubuntu/Gestures/TouchGate.h 2015-04-10 21:17:56 +0000 |
2549 | @@ -45,6 +45,8 @@ |
2550 | Q_PROPERTY(QQuickItem* targetItem READ targetItem WRITE setTargetItem NOTIFY targetItemChanged) |
2551 | |
2552 | public: |
2553 | + TouchGate(QQuickItem *parent = nullptr); |
2554 | + |
2555 | bool event(QEvent *e) override; |
2556 | |
2557 | QQuickItem *targetItem() { return m_dispatcher.targetItem(); } |
2558 | @@ -57,31 +59,42 @@ |
2559 | |
2560 | protected: |
2561 | void touchEvent(QTouchEvent *event) override; |
2562 | + |
2563 | +private Q_SLOTS: |
2564 | + void onEnabledChanged(); |
2565 | + |
2566 | private: |
2567 | + void reset(); |
2568 | + |
2569 | class TouchEvent { |
2570 | public: |
2571 | - TouchEvent(const QTouchEvent *event); |
2572 | + TouchEvent(QTouchDevice *device, |
2573 | + Qt::KeyboardModifiers modifiers, |
2574 | + const QList<QTouchEvent::TouchPoint> &touchPoints, |
2575 | + QWindow *window, |
2576 | + ulong timestamp); |
2577 | |
2578 | bool removeTouch(int touchId); |
2579 | |
2580 | - QEvent::Type eventType; |
2581 | QTouchDevice *device; |
2582 | Qt::KeyboardModifiers modifiers; |
2583 | QList<QTouchEvent::TouchPoint> touchPoints; |
2584 | - QQuickItem *target; |
2585 | QWindow *window; |
2586 | ulong timestamp; |
2587 | }; |
2588 | |
2589 | void touchOwnershipEvent(TouchOwnershipEvent *event); |
2590 | bool isTouchPointOwned(int touchId) const; |
2591 | - void storeTouchEvent(const QTouchEvent *event); |
2592 | + void storeTouchEvent(QTouchDevice *device, |
2593 | + Qt::KeyboardModifiers modifiers, |
2594 | + const QList<QTouchEvent::TouchPoint> &touchPoints, |
2595 | + QWindow *window, |
2596 | + ulong timestamp); |
2597 | void removeTouchFromStoredEvents(int touchId); |
2598 | void dispatchFullyOwnedEvents(); |
2599 | bool eventIsFullyOwned(const TouchEvent &event) const; |
2600 | |
2601 | void dispatchTouchEventToTarget(const TouchEvent &event); |
2602 | - void dispatchTouchEventToTarget(QTouchEvent* event); |
2603 | |
2604 | void removeTouchInfoForEndedTouches(const QList<QTouchEvent::TouchPoint> &touchPoints); |
2605 | |
2606 | |
2607 | === modified file 'qml/Components/DragHandle.qml' |
2608 | --- qml/Components/DragHandle.qml 2014-12-05 17:06:36 +0000 |
2609 | +++ qml/Components/DragHandle.qml 2015-04-10 21:17:56 +0000 |
2610 | @@ -43,16 +43,8 @@ |
2611 | } |
2612 | |
2613 | */ |
2614 | -EdgeDragArea { |
2615 | +DirectionalDragArea { |
2616 | id: dragArea |
2617 | - objectName: "dragHandle" |
2618 | - |
2619 | - // Disable gesture recognition by default when hinting is used as |
2620 | - // it conflicts with the hinting idea. |
2621 | - distanceThreshold: hintDisplacement > 0 ? 0 : defaultDistanceThreshold |
2622 | - maxSilenceTime: hintDisplacement > 0 ? 60*60*1000 : defaultMaxSilenceTime |
2623 | - maxDeviation: hintDisplacement > 0 ? 999999 : defaultMaxDeviation |
2624 | - compositionTime: hintDisplacement > 0 ? 0 : defaultCompositionTime |
2625 | |
2626 | property bool stretch: false |
2627 | |
2628 | @@ -68,6 +60,9 @@ |
2629 | } |
2630 | |
2631 | property real hintDisplacement: 0 |
2632 | + |
2633 | + immediateRecognition: hintDisplacement > 0 |
2634 | + |
2635 | property var overrideStartValue: undefined |
2636 | SmoothedAnimation { |
2637 | id: hintingAnimation |
2638 | @@ -98,7 +93,6 @@ |
2639 | // Private stuff |
2640 | QtObject { |
2641 | id: d |
2642 | - property var previousStatus: DirectionalDragArea.WaitingForTouch |
2643 | property real startValue |
2644 | property real minValue: { |
2645 | if (direction == Direction.Horizontal) { |
2646 | @@ -183,7 +177,7 @@ |
2647 | } |
2648 | |
2649 | onDistanceChanged: { |
2650 | - if (status === DirectionalDragArea.Recognized) { |
2651 | + if (dragging) { |
2652 | // don't go the whole distance in order to smooth out the movement |
2653 | var step = distance * 0.3; |
2654 | |
2655 | @@ -193,31 +187,22 @@ |
2656 | } |
2657 | } |
2658 | |
2659 | - onStatusChanged: { |
2660 | - if (status === DirectionalDragArea.WaitingForTouch) { |
2661 | + onDraggingChanged: { |
2662 | + if (dragging) { |
2663 | + dragEvaluator.reset(); |
2664 | + if (overrideStartValue !== undefined) { |
2665 | + d.startValue = overrideStartValue; |
2666 | + } else { |
2667 | + d.startValue = parent[d.targetProp]; |
2668 | + } |
2669 | + |
2670 | + if (hintDisplacement > 0) { |
2671 | + hintingAnimation.targetValue = d.startValue; |
2672 | + hintingAnimation.start(); |
2673 | + } |
2674 | + } else { |
2675 | hintingAnimation.stop(); |
2676 | - if (d.previousStatus === DirectionalDragArea.Recognized) { |
2677 | - d.onFinishedRecognizedGesture(); |
2678 | - } else /* d.previousStatus === DirectionalDragArea.Undecided */ { |
2679 | - // Gesture was rejected. |
2680 | - d.rollbackDrag(); |
2681 | - } |
2682 | - } else /* Undecided || Recognized */ { |
2683 | - if (d.previousStatus === DirectionalDragArea.WaitingForTouch) { |
2684 | - dragEvaluator.reset(); |
2685 | - if (overrideStartValue !== undefined) { |
2686 | - d.startValue = overrideStartValue; |
2687 | - } else { |
2688 | - d.startValue = parent[d.targetProp]; |
2689 | - } |
2690 | - |
2691 | - if (hintDisplacement > 0) { |
2692 | - hintingAnimation.targetValue = d.startValue; |
2693 | - hintingAnimation.start(); |
2694 | - } |
2695 | - } |
2696 | + d.onFinishedRecognizedGesture(); |
2697 | } |
2698 | - |
2699 | - d.previousStatus = status; |
2700 | } |
2701 | } |
2702 | |
2703 | === removed file 'qml/Components/EdgeDragArea.qml' |
2704 | --- qml/Components/EdgeDragArea.qml 2014-10-01 13:20:32 +0000 |
2705 | +++ qml/Components/EdgeDragArea.qml 1970-01-01 00:00:00 +0000 |
2706 | @@ -1,46 +0,0 @@ |
2707 | -/* |
2708 | - * Copyright (C) 2013 Canonical, Ltd. |
2709 | - * |
2710 | - * This program is free software; you can redistribute it and/or modify |
2711 | - * it under the terms of the GNU General Public License as published by |
2712 | - * the Free Software Foundation; version 3. |
2713 | - * |
2714 | - * This program is distributed in the hope that it will be useful, |
2715 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2716 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2717 | - * GNU General Public License for more details. |
2718 | - * |
2719 | - * You should have received a copy of the GNU General Public License |
2720 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2721 | - */ |
2722 | - |
2723 | -import QtQuick 2.0 |
2724 | -import Ubuntu.Components 0.1 |
2725 | -import Ubuntu.Gestures 0.1 |
2726 | - |
2727 | -/* |
2728 | - A DirectionalDragArea wrapper that provides some well-chosen defaults |
2729 | - for its gesture recognition parameters. |
2730 | -*/ |
2731 | -DirectionalDragArea { |
2732 | - |
2733 | - // TODO: Re-evaluate those or even the recognition heuristics itself once |
2734 | - // we have gesture cancelling/forwarding in place. |
2735 | - // |
2736 | - // The idea here is that it's better having lax rules than false negatives. |
2737 | - // False negatives are very frustrating to the user. |
2738 | - maxDeviation: defaultMaxDeviation |
2739 | - wideningAngle: defaultWideningAngle |
2740 | - distanceThreshold: defaultDistanceThreshold |
2741 | - minSpeed: defaultMinSpeed |
2742 | - maxSilenceTime: defaultMaxSilenceTime |
2743 | - compositionTime: defaultCompositionTime |
2744 | - |
2745 | - readonly property real defaultMaxDeviation: units.gu(3) |
2746 | - readonly property real defaultWideningAngle: 50 |
2747 | - readonly property real defaultDistanceThreshold: units.gu(1.5) |
2748 | - // some people were getting false negatives with it enabled. |
2749 | - readonly property real defaultMinSpeed: units.gu(0) |
2750 | - readonly property int defaultMaxSilenceTime: 200 |
2751 | - readonly property int defaultCompositionTime: 60 |
2752 | -} |
2753 | |
2754 | === modified file 'qml/Dash/Dash.qml' |
2755 | --- qml/Dash/Dash.qml 2015-02-17 08:26:20 +0000 |
2756 | +++ qml/Dash/Dash.qml 2015-04-10 21:17:56 +0000 |
2757 | @@ -140,7 +140,7 @@ |
2758 | // (as expected) but would also cause the dash content flickable to move a bit, because |
2759 | // that flickable was getting the touch events while overviewDragHandle was still undecided |
2760 | // about whether that touch was indeed performing a directional drag gesture. |
2761 | - forceNonInteractive: overviewDragHandle.status != DirectionalDragArea.WaitingForTouch |
2762 | + forceNonInteractive: overviewDragHandle.dragging |
2763 | |
2764 | enabled: bottomEdgeController.progress == 0 |
2765 | } |
2766 | @@ -317,7 +317,7 @@ |
2767 | } |
2768 | } |
2769 | |
2770 | - EdgeDragArea { |
2771 | + DirectionalDragArea { |
2772 | id: overviewDragHandle |
2773 | objectName: "overviewDragHandle" |
2774 | z: 1 |
2775 | @@ -333,21 +333,14 @@ |
2776 | height: units.gu(2) |
2777 | |
2778 | onSceneDistanceChanged: { |
2779 | - if (status == DirectionalDragArea.Recognized) { |
2780 | + if (dragging) { |
2781 | bottomEdgeController.enableAnimation = false; |
2782 | bottomEdgeController.progress = Math.max(0, Math.min(1, sceneDistance / fullMovement)); |
2783 | } |
2784 | } |
2785 | |
2786 | - property int previousStatus: -1 |
2787 | - property int currentStatus: DirectionalDragArea.WaitingForTouch |
2788 | - |
2789 | - onStatusChanged: { |
2790 | - previousStatus = currentStatus; |
2791 | - currentStatus = status; |
2792 | - |
2793 | - if (status == DirectionalDragArea.WaitingForTouch && |
2794 | - previousStatus == DirectionalDragArea.Recognized) { |
2795 | + onDraggingChanged: { |
2796 | + if (!dragging) { |
2797 | bottomEdgeController.enableAnimation = true; |
2798 | bottomEdgeController.progress = (bottomEdgeController.progress > 0.2) ? 1 : 0; |
2799 | } |
2800 | |
2801 | === modified file 'qml/Greeter/CoverPage.qml' |
2802 | --- qml/Greeter/CoverPage.qml 2015-02-17 15:54:17 +0000 |
2803 | +++ qml/Greeter/CoverPage.qml 2015-04-10 21:17:56 +0000 |
2804 | @@ -129,6 +129,7 @@ |
2805 | |
2806 | DragHandle { |
2807 | id: dragHandle |
2808 | + objectName: "coverPageDragHandle" |
2809 | anchors.fill: parent |
2810 | anchors.leftMargin: root.dragHandleLeftMargin |
2811 | enabled: root.draggable |
2812 | |
2813 | === modified file 'qml/Launcher/Launcher.qml' |
2814 | --- qml/Launcher/Launcher.qml 2015-03-12 13:04:36 +0000 |
2815 | +++ qml/Launcher/Launcher.qml 2015-04-10 21:17:56 +0000 |
2816 | @@ -210,7 +210,7 @@ |
2817 | bottom: parent.bottom |
2818 | } |
2819 | x: -width |
2820 | - visible: root.x > 0 || x > -width || dragArea.status === DirectionalDragArea.Undecided |
2821 | + visible: root.x > 0 || x > -width |
2822 | model: LauncherModel |
2823 | |
2824 | property bool animate: true |
2825 | @@ -272,7 +272,7 @@ |
2826 | } |
2827 | } |
2828 | |
2829 | - EdgeDragArea { |
2830 | + DirectionalDragArea { |
2831 | id: dragArea |
2832 | objectName: "launcherDragArea" |
2833 | |
2834 | @@ -284,19 +284,10 @@ |
2835 | height: root.height |
2836 | |
2837 | onTouchXChanged: { |
2838 | - if (status !== DirectionalDragArea.Recognized || launcher.state == "visible") |
2839 | + if (!dragging || launcher.state == "visible") |
2840 | return; |
2841 | |
2842 | - // When the gesture finally gets recognized, the finger will likely be |
2843 | - // reasonably far from the edge. If we made the panel immediately |
2844 | - // follow the finger position it would be visually unpleasant as it |
2845 | - // would appear right next to the user's finger out of nowhere. |
2846 | - // Instead, we make the panel go towards the user's finger in several |
2847 | - // steps. ie., in an animated way. |
2848 | - var targetPanelX = Math.min(0, touchX - panel.width) - root.x |
2849 | - var delta = targetPanelX - panel.x |
2850 | - // the trick is not to go all the way (1.0) as it would cause a sudden jump |
2851 | - panel.x += 0.4 * delta |
2852 | + panel.x = Math.min(0, touchX - panel.width) - root.x |
2853 | } |
2854 | |
2855 | onDraggingChanged: { |
2856 | @@ -306,7 +297,8 @@ |
2857 | if (distance > minimizeDistance) { |
2858 | root.dash(); |
2859 | } |
2860 | - } else { |
2861 | + } else if (root.state === "") { |
2862 | + // didn't drag far enough. rollback |
2863 | root.switchToNextState("") |
2864 | } |
2865 | } |
2866 | |
2867 | === modified file 'qml/Panel/IndicatorsMenu.qml' |
2868 | --- qml/Panel/IndicatorsMenu.qml 2015-03-18 10:17:21 +0000 |
2869 | +++ qml/Panel/IndicatorsMenu.qml 2015-04-10 21:17:56 +0000 |
2870 | @@ -182,9 +182,18 @@ |
2871 | enabled: !root.shown && root.available |
2872 | autoCompleteDragThreshold: maxTotalDragDistance / 2 |
2873 | stretch: true |
2874 | - distanceThreshold: enableHint ? 0 : minimizedPanelHeight |
2875 | |
2876 | - onTapped: showTapped(Qt.point(touchSceneX, touchSceneY)); |
2877 | + onDraggingChanged: { |
2878 | + if (dragging) { |
2879 | + touchPressTime = new Date().getTime(); |
2880 | + } else { |
2881 | + var touchReleaseTime = new Date().getTime(); |
2882 | + if (touchReleaseTime - touchPressTime <= 300) { |
2883 | + root.showTapped(Qt.point(touchSceneX, touchSceneY)); |
2884 | + } |
2885 | + } |
2886 | + } |
2887 | + property var touchPressTime |
2888 | |
2889 | // using hint regulates minimum to hint displacement, but in fullscreen mode, we need to do it manually. |
2890 | overrideStartValue: enableHint ? minimizedPanelHeight : expandedPanelHeight + handle.height |
2891 | @@ -200,6 +209,7 @@ |
2892 | |
2893 | DragHandle { |
2894 | id: __hideDragHandle |
2895 | + objectName: "hideDragHandle" |
2896 | anchors.fill: handle |
2897 | direction: Direction.Upwards |
2898 | enabled: root.shown && root.available |
2899 | |
2900 | === modified file 'qml/Stages/PhoneStage.qml' |
2901 | --- qml/Stages/PhoneStage.qml 2015-02-18 18:29:03 +0000 |
2902 | +++ qml/Stages/PhoneStage.qml 2015-04-10 21:17:56 +0000 |
2903 | @@ -146,14 +146,13 @@ |
2904 | id: spreadView |
2905 | objectName: "spreadView" |
2906 | anchors.fill: parent |
2907 | - interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) |
2908 | - && draggedDelegateCount === 0 |
2909 | + interactive: (spreadDragArea.dragging || phase > 1) && draggedDelegateCount === 0 |
2910 | contentWidth: spreadRow.width - shift |
2911 | contentX: -shift |
2912 | |
2913 | // This indicates when the spreadView is active. That means, all the animations |
2914 | // are activated and tiles need to line up for the spread. |
2915 | - readonly property bool active: shiftedContentX > 0 || spreadDragArea.status === DirectionalDragArea.Recognized || !root.focusFirstApp |
2916 | + readonly property bool active: shiftedContentX > 0 || spreadDragArea.dragging || !root.focusFirstApp |
2917 | |
2918 | // The flickable needs to fill the screen in order to get touch events all over. |
2919 | // However, we don't want to the user to be able to scroll back all the way. For |
2920 | @@ -450,7 +449,7 @@ |
2921 | } |
2922 | } |
2923 | |
2924 | - EdgeDragArea { |
2925 | + DirectionalDragArea { |
2926 | id: spreadDragArea |
2927 | objectName: "spreadDragArea" |
2928 | direction: Direction.Leftwards |
2929 | @@ -462,59 +461,50 @@ |
2930 | property var gesturePoints: new Array() |
2931 | |
2932 | onTouchXChanged: { |
2933 | - if (!dragging) { |
2934 | - // Initial touch. Let's reset the spreadView to the starting position. |
2935 | - spreadView.phase = 0; |
2936 | - spreadView.contentX = -spreadView.shift; |
2937 | - } |
2938 | - if (dragging && status == DirectionalDragArea.Recognized) { |
2939 | + if (dragging) { |
2940 | // Gesture recognized. Let's move the spreadView with the finger |
2941 | var dragX = Math.min(touchX + width, width); // Prevent dragging rightwards |
2942 | dragX = -dragX + spreadDragArea.width - spreadView.shift; |
2943 | // Don't allow dragging further than the animation crossing with phase2's animation |
2944 | var maxMovement = spreadView.width * spreadView.positionMarker4 - spreadView.shift; |
2945 | + |
2946 | spreadView.contentX = Math.min(dragX, maxMovement); |
2947 | + } else { |
2948 | + // Initial touch. Let's reset the spreadView to the starting position. |
2949 | + spreadView.phase = 0; |
2950 | + spreadView.contentX = -spreadView.shift; |
2951 | } |
2952 | + |
2953 | gesturePoints.push(touchX); |
2954 | } |
2955 | |
2956 | - property int previousStatus: -1 |
2957 | - property int currentStatus: DirectionalDragArea.WaitingForTouch |
2958 | - |
2959 | - onStatusChanged: { |
2960 | - previousStatus = currentStatus; |
2961 | - currentStatus = status; |
2962 | - } |
2963 | - |
2964 | onDraggingChanged: { |
2965 | if (dragging) { |
2966 | // A potential edge-drag gesture has started. Start recording it |
2967 | gesturePoints = []; |
2968 | - return; |
2969 | - } |
2970 | - |
2971 | - // Ok. The user released. Find out if it was a one-way movement. |
2972 | - var oneWayFlick = true; |
2973 | - var smallestX = spreadDragArea.width; |
2974 | - for (var i = 0; i < gesturePoints.length; i++) { |
2975 | - if (gesturePoints[i] >= smallestX) { |
2976 | - oneWayFlick = false; |
2977 | - break; |
2978 | - } |
2979 | - smallestX = gesturePoints[i]; |
2980 | - } |
2981 | - gesturePoints = []; |
2982 | - |
2983 | - if (previousStatus == DirectionalDragArea.Recognized && |
2984 | - oneWayFlick && spreadView.shiftedContentX > units.gu(2) && |
2985 | - spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width) { |
2986 | - // If it was a short one-way movement, do the Alt+Tab switch |
2987 | - // no matter if we didn't cross positionMarker1 yet. |
2988 | - spreadView.snapTo(1); |
2989 | - } else if (!dragging) { |
2990 | - // otherwise snap to the closest snap position we can find |
2991 | - // (might be back to start, to app 1 or to spread) |
2992 | - spreadView.snap(); |
2993 | + } else { |
2994 | + // Ok. The user released. Find out if it was a one-way movement. |
2995 | + var oneWayFlick = true; |
2996 | + var smallestX = spreadDragArea.width; |
2997 | + for (var i = 0; i < gesturePoints.length; i++) { |
2998 | + if (gesturePoints[i] >= smallestX) { |
2999 | + oneWayFlick = false; |
3000 | + break; |
3001 | + } |
3002 | + smallestX = gesturePoints[i]; |
3003 | + } |
3004 | + gesturePoints = []; |
3005 | + |
3006 | + if (oneWayFlick && spreadView.shiftedContentX > units.gu(2) && |
3007 | + spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width) { |
3008 | + // If it was a short one-way movement, do the Alt+Tab switch |
3009 | + // no matter if we didn't cross positionMarker1 yet. |
3010 | + spreadView.snapTo(1); |
3011 | + } else if (!dragging) { |
3012 | + // otherwise snap to the closest snap position we can find |
3013 | + // (might be back to start, to app 1 or to spread) |
3014 | + spreadView.snap(); |
3015 | + } |
3016 | } |
3017 | } |
3018 | } |
3019 | |
3020 | === modified file 'qml/Stages/TabletStage.qml' |
3021 | --- qml/Stages/TabletStage.qml 2015-02-02 16:28:03 +0000 |
3022 | +++ qml/Stages/TabletStage.qml 2015-04-10 21:17:56 +0000 |
3023 | @@ -170,8 +170,7 @@ |
3024 | Flickable { |
3025 | id: spreadView |
3026 | anchors.fill: parent |
3027 | - interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) |
3028 | - && draggedDelegateCount === 0 |
3029 | + interactive: (spreadDragArea.dragging || phase > 1) && draggedDelegateCount === 0 |
3030 | contentWidth: spreadRow.width - shift |
3031 | contentX: -shift |
3032 | |
3033 | @@ -598,7 +597,7 @@ |
3034 | } |
3035 | } |
3036 | |
3037 | - EdgeDragArea { |
3038 | + DirectionalDragArea { |
3039 | id: spreadDragArea |
3040 | anchors { top: parent.top; right: parent.right; bottom: parent.bottom } |
3041 | width: root.dragAreaWidth |
3042 | @@ -624,26 +623,25 @@ |
3043 | if (dragging) { |
3044 | // Gesture recognized. Start recording this gesture |
3045 | gesturePoints = []; |
3046 | - return; |
3047 | - } |
3048 | - |
3049 | - // Ok. The user released. Find out if it was a one-way movement. |
3050 | - var oneWayFlick = priv.evaluateOneWayFlick(gesturePoints); |
3051 | - gesturePoints = []; |
3052 | - |
3053 | - if (oneWayFlick && spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width) { |
3054 | - // If it was a short one-way movement, do the Alt+Tab switch |
3055 | - // no matter if we didn't cross positionMarker1 yet. |
3056 | - spreadView.snapTo(spreadView.nextInStack); |
3057 | - } else if (!dragging) { |
3058 | - if (spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker1) { |
3059 | - spreadView.snap(); |
3060 | - } else if (spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2) { |
3061 | + } else { |
3062 | + // Ok. The user released. Find out if it was a one-way movement. |
3063 | + var oneWayFlick = priv.evaluateOneWayFlick(gesturePoints); |
3064 | + gesturePoints = []; |
3065 | + |
3066 | + if (oneWayFlick && spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width) { |
3067 | + // If it was a short one-way movement, do the Alt+Tab switch |
3068 | + // no matter if we didn't cross positionMarker1 yet. |
3069 | spreadView.snapTo(spreadView.nextInStack); |
3070 | } else { |
3071 | - // otherwise snap to the closest snap position we can find |
3072 | - // (might be back to start, to app 1 or to spread) |
3073 | - spreadView.snap(); |
3074 | + if (spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker1) { |
3075 | + spreadView.snap(); |
3076 | + } else if (spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2) { |
3077 | + spreadView.snapTo(spreadView.nextInStack); |
3078 | + } else { |
3079 | + // otherwise snap to the closest snap position we can find |
3080 | + // (might be back to start, to app 1 or to spread) |
3081 | + spreadView.snap(); |
3082 | + } |
3083 | } |
3084 | } |
3085 | } |
3086 | |
3087 | === modified file 'qml/Tutorial/TutorialBottom.qml' |
3088 | --- qml/Tutorial/TutorialBottom.qml 2015-02-01 22:39:25 +0000 |
3089 | +++ qml/Tutorial/TutorialBottom.qml 2015-04-10 21:17:56 +0000 |
3090 | @@ -73,7 +73,7 @@ |
3091 | ] |
3092 | } |
3093 | |
3094 | - EdgeDragArea { |
3095 | + DirectionalDragArea { |
3096 | id: dragArea |
3097 | direction: Direction.Upwards |
3098 | anchors { |
3099 | |
3100 | === modified file 'tests/libs/UbuntuGestures/tst_TouchRegistry.cpp' |
3101 | --- tests/libs/UbuntuGestures/tst_TouchRegistry.cpp 2014-10-01 13:20:32 +0000 |
3102 | +++ tests/libs/UbuntuGestures/tst_TouchRegistry.cpp 2015-04-10 21:17:56 +0000 |
3103 | @@ -1,5 +1,5 @@ |
3104 | /* |
3105 | - * Copyright (C) 2014 Canonical, Ltd. |
3106 | + * Copyright (C) 2014-2015 Canonical, Ltd. |
3107 | * |
3108 | * This program is free software; you can redistribute it and/or modify |
3109 | * it under the terms of the GNU General Public License as published by |
3110 | @@ -66,6 +66,7 @@ |
3111 | void candidatesAndWatchers_2(); |
3112 | void rejectingTouchfterItsEnd(); |
3113 | void removeOldUndecidedCandidates(); |
3114 | + void interimOwnerWontGetUnownedTouchEvents(); |
3115 | }; |
3116 | |
3117 | void tst_TouchRegistry::requestWithNoCandidates() |
3118 | @@ -742,7 +743,7 @@ |
3119 | |
3120 | // Simulate that enough time has passed to cause the CandidateInactivityTimer to timeout, |
3121 | // making TouchRegistry consider that undecidedCantidate defaulted. |
3122 | - fakeTimerFactory->makeRunningTimersTimeout(); |
3123 | + fakeTimerFactory->updateTime(10000); |
3124 | |
3125 | QVERIFY(undecidedCandidate.ownedTouches.isEmpty()); |
3126 | QVERIFY(undecidedCandidate.lostTouches.contains(0)); |
3127 | @@ -752,6 +753,71 @@ |
3128 | delete touchRegistry; |
3129 | } |
3130 | |
3131 | +/* |
3132 | + An item that calls requestTouchOwnership() without first having called addCandidateOwnerForTouch() |
3133 | + is assumed to be the interim owner of the touch point, thus there's no point in sending |
3134 | + UnownedTouchEvents to him as he already gets proper QTouchEvents from QQuickWindow because |
3135 | + he didn't ignore the first QTouchEvent with that touch point. |
3136 | + */ |
3137 | +void tst_TouchRegistry::interimOwnerWontGetUnownedTouchEvents() |
3138 | +{ |
3139 | + FakeTimerFactory *fakeTimerFactory = new FakeTimerFactory; |
3140 | + TouchRegistry *touchRegistry = new TouchRegistry(nullptr, fakeTimerFactory); |
3141 | + |
3142 | + DummyCandidate undecidedCandidate; |
3143 | + undecidedCandidate.setObjectName("undecided"); |
3144 | + |
3145 | + DummyCandidate interimOwner; |
3146 | + interimOwner.setObjectName("interimOwner"); |
3147 | + |
3148 | + { |
3149 | + QList<QTouchEvent::TouchPoint> touchPoints; |
3150 | + touchPoints.append(QTouchEvent::TouchPoint(0)); |
3151 | + touchPoints[0].setState(Qt::TouchPointPressed); |
3152 | + QTouchEvent touchEvent(QEvent::TouchBegin, |
3153 | + 0 /* device */, |
3154 | + Qt::NoModifier, |
3155 | + Qt::TouchPointPressed, |
3156 | + touchPoints); |
3157 | + touchRegistry->update(&touchEvent); |
3158 | + } |
3159 | + |
3160 | + touchRegistry->addCandidateOwnerForTouch(0, &undecidedCandidate); |
3161 | + touchRegistry->requestTouchOwnership(0, &interimOwner); |
3162 | + |
3163 | + { |
3164 | + QList<QTouchEvent::TouchPoint> touchPoints; |
3165 | + touchPoints.append(QTouchEvent::TouchPoint(0)); |
3166 | + touchPoints[0].setState(Qt::TouchPointMoved); |
3167 | + QTouchEvent touchEvent(QEvent::TouchUpdate, |
3168 | + 0 /* device */, |
3169 | + Qt::NoModifier, |
3170 | + Qt::TouchPointMoved, |
3171 | + touchPoints); |
3172 | + touchRegistry->update(&touchEvent); |
3173 | + } |
3174 | + |
3175 | + QCOMPARE(undecidedCandidate.unownedTouchEvents.count(), 1); |
3176 | + QCOMPARE(interimOwner.unownedTouchEvents.count(), 0); |
3177 | + |
3178 | + { |
3179 | + QList<QTouchEvent::TouchPoint> touchPoints; |
3180 | + touchPoints.append(QTouchEvent::TouchPoint(0)); |
3181 | + touchPoints[0].setState(Qt::TouchPointMoved); |
3182 | + QTouchEvent touchEvent(QEvent::TouchUpdate, |
3183 | + 0 /* device */, |
3184 | + Qt::NoModifier, |
3185 | + Qt::TouchPointMoved, |
3186 | + touchPoints); |
3187 | + touchRegistry->update(&touchEvent); |
3188 | + } |
3189 | + |
3190 | + QCOMPARE(undecidedCandidate.unownedTouchEvents.count(), 2); |
3191 | + QCOMPARE(interimOwner.unownedTouchEvents.count(), 0); |
3192 | + |
3193 | + delete touchRegistry; |
3194 | +} |
3195 | + |
3196 | ////////////// TouchMemento ////////// |
3197 | |
3198 | TouchMemento::TouchMemento(const QTouchEvent *touchEvent) |
3199 | |
3200 | === modified file 'tests/plugins/Ubuntu/Gestures/CMakeLists.txt' |
3201 | --- tests/plugins/Ubuntu/Gestures/CMakeLists.txt 2014-10-17 11:01:53 +0000 |
3202 | +++ tests/plugins/Ubuntu/Gestures/CMakeLists.txt 2015-04-10 21:17:56 +0000 |
3203 | @@ -19,6 +19,7 @@ |
3204 | ) |
3205 | |
3206 | add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins") |
3207 | +add_definitions(-DTESTS_UTILS_MODULES_DIR="${CMAKE_BINARY_DIR}/tests/utils/modules") |
3208 | |
3209 | macro(add_gesture_ui_test CLASSNAME) |
3210 | add_executable(${CLASSNAME}TestExec tst_${CLASSNAME}.cpp GestureTest.cpp) |
3211 | @@ -26,7 +27,8 @@ |
3212 | target_link_libraries(${CLASSNAME}TestExec UbuntuGesturesQml UbuntuGestures) |
3213 | |
3214 | add_binary_qml_test(${CLASSNAME} ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures UbuntuGesturesTestQmlFiles "") |
3215 | - add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins) |
3216 | + add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins |
3217 | + ${CMAKE_BINARY_DIR}/tests/utils/modules) |
3218 | endmacro(add_gesture_ui_test) |
3219 | |
3220 | macro(add_gesture_test CLASSNAME) |
3221 | |
3222 | === modified file 'tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml' |
3223 | --- tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml 2014-02-11 20:21:24 +0000 |
3224 | +++ tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml 2015-04-10 21:17:56 +0000 |
3225 | @@ -37,8 +37,8 @@ |
3226 | |
3227 | Rectangle { |
3228 | id: dragAreaRect |
3229 | - color: "yellow" |
3230 | - opacity: 0.0 |
3231 | + opacity: dragArea.dragging ? 0.5 : 0.0 |
3232 | + color: "green" |
3233 | anchors.fill: dragArea |
3234 | } |
3235 | |
3236 | @@ -49,24 +49,10 @@ |
3237 | height: units.gu(5) |
3238 | |
3239 | direction: Direction.Downwards |
3240 | - maxDeviation: units.gu(2) |
3241 | - wideningAngle: 10 |
3242 | - distanceThreshold: units.gu(4) |
3243 | |
3244 | - onStatusChanged: { |
3245 | - switch (status) { |
3246 | - case DirectionalDragArea.WaitingForTouch: |
3247 | - dragAreaRect.opacity = 0.0 |
3248 | - break; |
3249 | - case DirectionalDragArea.Undecided: |
3250 | - dragAreaRect.color = "yellow" |
3251 | - dragAreaRect.opacity = 0.3 |
3252 | - launcher.y = Qt.binding(launcher.followDragArea) |
3253 | - break; |
3254 | - default: // DirectionalDragArea.Recognized: |
3255 | - dragAreaRect.color = "green" |
3256 | - dragAreaRect.opacity = 0.5 |
3257 | - break; |
3258 | + onDraggingChanged: { |
3259 | + if (dragging) { |
3260 | + launcher.y = Qt.binding(launcher.followDragArea) |
3261 | } |
3262 | } |
3263 | |
3264 | |
3265 | === modified file 'tests/plugins/Ubuntu/Gestures/GestureTest.cpp' |
3266 | --- tests/plugins/Ubuntu/Gestures/GestureTest.cpp 2014-11-03 15:21:46 +0000 |
3267 | +++ tests/plugins/Ubuntu/Gestures/GestureTest.cpp 2015-04-10 21:17:56 +0000 |
3268 | @@ -1,5 +1,5 @@ |
3269 | /* |
3270 | - * Copyright (C) 2013 Canonical, Ltd. |
3271 | + * Copyright (C) 2013,2015 Canonical, Ltd. |
3272 | * |
3273 | * This program is free software; you can redistribute it and/or modify |
3274 | * it under the terms of the GNU General Public License as published by |
3275 | @@ -21,8 +21,11 @@ |
3276 | #include <QQuickView> |
3277 | #include <QtTest> |
3278 | |
3279 | +#include <Timer.h> |
3280 | #include <TouchRegistry.h> |
3281 | |
3282 | +using namespace UbuntuGestures; |
3283 | + |
3284 | GestureTest::GestureTest(const QString &qmlFilename) |
3285 | : QObject(), m_device(nullptr), m_view(nullptr), m_qmlFilename(qmlFilename) |
3286 | { |
3287 | @@ -40,14 +43,17 @@ |
3288 | void GestureTest::init() |
3289 | { |
3290 | m_view = new QQuickView; |
3291 | - m_view->setResizeMode(QQuickView::SizeViewToRootObject); |
3292 | + m_view->setResizeMode(QQuickView::SizeRootObjectToView); |
3293 | m_view->engine()->addImportPath(QStringLiteral(UBUNTU_GESTURES_PLUGIN_DIR)); |
3294 | + m_view->engine()->addImportPath(QStringLiteral(TESTS_UTILS_MODULES_DIR)); |
3295 | m_view->setSource(QUrl::fromLocalFile(m_qmlFilename)); |
3296 | m_view->show(); |
3297 | QVERIFY(QTest::qWaitForWindowExposed(m_view)); |
3298 | QVERIFY(m_view->rootObject() != 0); |
3299 | |
3300 | - m_touchRegistry = new TouchRegistry; |
3301 | + m_fakeTimerFactory = new FakeTimerFactory; |
3302 | + |
3303 | + m_touchRegistry = new TouchRegistry(nullptr, m_fakeTimerFactory); |
3304 | m_view->installEventFilter(m_touchRegistry); |
3305 | |
3306 | qApp->processEvents(); |
3307 | @@ -59,6 +65,10 @@ |
3308 | delete m_touchRegistry; |
3309 | m_touchRegistry = nullptr; |
3310 | |
3311 | + // TouchRegistry will take down the timer factory along with him |
3312 | + // delete m_fakeTimerFactory; |
3313 | + m_fakeTimerFactory = nullptr; |
3314 | + |
3315 | delete m_view; |
3316 | m_view = nullptr; |
3317 | } |
3318 | |
3319 | === modified file 'tests/plugins/Ubuntu/Gestures/GestureTest.h' |
3320 | --- tests/plugins/Ubuntu/Gestures/GestureTest.h 2014-11-03 15:21:46 +0000 |
3321 | +++ tests/plugins/Ubuntu/Gestures/GestureTest.h 2015-04-10 21:17:56 +0000 |
3322 | @@ -23,6 +23,9 @@ |
3323 | class QQuickView; |
3324 | class QTouchDevice; |
3325 | |
3326 | +namespace UbuntuGestures { |
3327 | + class FakeTimerFactory; |
3328 | +} |
3329 | class TouchRegistry; |
3330 | |
3331 | // C++ std lib |
3332 | @@ -81,6 +84,7 @@ |
3333 | QTouchDevice *m_device; |
3334 | QQuickView *m_view; |
3335 | TouchRegistry *m_touchRegistry; |
3336 | + UbuntuGestures::FakeTimerFactory *m_fakeTimerFactory; |
3337 | QString m_qmlFilename; |
3338 | }; |
3339 | |
3340 | |
3341 | === modified file 'tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml' |
3342 | --- tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml 2014-02-11 20:21:24 +0000 |
3343 | +++ tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml 2015-04-10 21:17:56 +0000 |
3344 | @@ -21,7 +21,7 @@ |
3345 | Item { |
3346 | id: root |
3347 | |
3348 | - function reset() { launcher.x = root.width } |
3349 | + function reset() { launcher.x = Qt.binding(function(){return root.width;}); } |
3350 | |
3351 | Rectangle { |
3352 | id: launcher |
3353 | @@ -41,7 +41,8 @@ |
3354 | |
3355 | Rectangle { |
3356 | id: dragAreaRect |
3357 | - opacity: 0.0 |
3358 | + opacity: dragArea.dragging ? 0.5 : 0.0 |
3359 | + color: "green" |
3360 | anchors.fill: dragArea |
3361 | } |
3362 | |
3363 | @@ -52,24 +53,10 @@ |
3364 | width: units.gu(5) |
3365 | |
3366 | direction: Direction.Leftwards |
3367 | - maxDeviation: units.gu(2) |
3368 | - wideningAngle: 10 |
3369 | - distanceThreshold: units.gu(4) |
3370 | |
3371 | - onStatusChanged: { |
3372 | - switch (status) { |
3373 | - case DirectionalDragArea.WaitingForTouch: |
3374 | - dragAreaRect.opacity = 0.0 |
3375 | - break; |
3376 | - case DirectionalDragArea.Undecided: |
3377 | - dragAreaRect.color = "yellow" |
3378 | - dragAreaRect.opacity = 0.3 |
3379 | - launcher.x = Qt.binding(launcher.followDragArea) |
3380 | - break; |
3381 | - default: //case DirectionalDragArea.Recognized: |
3382 | - dragAreaRect.color = "green" |
3383 | - dragAreaRect.opacity = 0.5 |
3384 | - break; |
3385 | + onDraggingChanged: { |
3386 | + if (dragging) { |
3387 | + launcher.x = Qt.binding(launcher.followDragArea) |
3388 | } |
3389 | } |
3390 | |
3391 | |
3392 | === modified file 'tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml' |
3393 | --- tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml 2014-10-01 13:20:32 +0000 |
3394 | +++ tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml 2015-04-10 21:17:56 +0000 |
3395 | @@ -38,7 +38,8 @@ |
3396 | |
3397 | Rectangle { |
3398 | id: dragAreaRect |
3399 | - opacity: 0.0 |
3400 | + opacity: dragArea.dragging ? 0.5 : 0.0 |
3401 | + color: "green" |
3402 | anchors.fill: dragArea |
3403 | } |
3404 | |
3405 | @@ -52,25 +53,10 @@ |
3406 | width: units.gu(5) |
3407 | |
3408 | direction: Direction.Rightwards |
3409 | - maxDeviation: units.gu(2) |
3410 | - wideningAngle: 10 |
3411 | - distanceThreshold: units.gu(4) |
3412 | - minSpeed: 50 |
3413 | |
3414 | - onStatusChanged: { |
3415 | - switch (status) { |
3416 | - case DirectionalDragArea.WaitingForTouch: |
3417 | - dragAreaRect.opacity = 0.0 |
3418 | - break; |
3419 | - case DirectionalDragArea.Undecided: |
3420 | - dragAreaRect.color = "yellow" |
3421 | - dragAreaRect.opacity = 0.3 |
3422 | - launcher.x = Qt.binding(launcher.followDragArea) |
3423 | - break; |
3424 | - default: //case DirectionalDragArea.Recognized: |
3425 | - dragAreaRect.color = "green" |
3426 | - dragAreaRect.opacity = 0.5 |
3427 | - break; |
3428 | + onDraggingChanged: { |
3429 | + if (dragging) { |
3430 | + launcher.x = Qt.binding(launcher.followDragArea) |
3431 | } |
3432 | } |
3433 | |
3434 | |
3435 | === modified file 'tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml' |
3436 | --- tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml 2014-02-11 20:21:24 +0000 |
3437 | +++ tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml 2015-04-10 21:17:56 +0000 |
3438 | @@ -21,7 +21,7 @@ |
3439 | Item { |
3440 | id: root |
3441 | |
3442 | - function reset() { launcher.y = root.height } |
3443 | + function reset() { launcher.y = Qt.binding(function(){return root.height;}); } |
3444 | |
3445 | Rectangle { |
3446 | id: launcher |
3447 | @@ -41,7 +41,8 @@ |
3448 | |
3449 | Rectangle { |
3450 | id: dragAreaRect |
3451 | - opacity: 0.0 |
3452 | + opacity: dragArea.dragging ? 0.5 : 0.0 |
3453 | + color: "green" |
3454 | anchors.fill: dragArea |
3455 | } |
3456 | |
3457 | @@ -52,24 +53,10 @@ |
3458 | height: units.gu(5) |
3459 | |
3460 | direction: Direction.Upwards |
3461 | - maxDeviation: units.gu(2) |
3462 | - wideningAngle: 10 |
3463 | - distanceThreshold: units.gu(4) |
3464 | |
3465 | - onStatusChanged: { |
3466 | - switch (status) { |
3467 | - case DirectionalDragArea.WaitingForTouch: |
3468 | - dragAreaRect.opacity = 0.0 |
3469 | - break; |
3470 | - case DirectionalDragArea.Undecided: |
3471 | - dragAreaRect.color = "yellow" |
3472 | - dragAreaRect.opacity = 0.3 |
3473 | - launcher.y = Qt.binding(launcher.followDragArea) |
3474 | - break; |
3475 | - default: //case DirectionalDragArea.Recognized: |
3476 | - dragAreaRect.color = "green" |
3477 | - dragAreaRect.opacity = 0.5 |
3478 | - break; |
3479 | + onDraggingChanged: { |
3480 | + if (dragging) { |
3481 | + launcher.y = Qt.binding(launcher.followDragArea) |
3482 | } |
3483 | } |
3484 | |
3485 | |
3486 | === modified file 'tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp' |
3487 | --- tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp 2015-02-18 13:51:39 +0000 |
3488 | +++ tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp 2015-04-10 21:17:56 +0000 |
3489 | @@ -1,5 +1,5 @@ |
3490 | /* |
3491 | - * Copyright (C) 2013-2014 Canonical, Ltd. |
3492 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
3493 | * |
3494 | * This program is free software; you can redistribute it and/or modify |
3495 | * it under the terms of the GNU General Public License as published by |
3496 | @@ -20,51 +20,38 @@ |
3497 | #include <QtQml/QQmlEngine> |
3498 | #include <QPointer> |
3499 | #include <private/qquickmousearea_p.h> |
3500 | -#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) |
3501 | - #include <private/qquickwindow_p.h> |
3502 | -#endif |
3503 | +#include <private/qquickwindow_p.h> |
3504 | |
3505 | |
3506 | #include <DirectionalDragArea.h> |
3507 | +#include <DirectionalDragArea_p.h> |
3508 | #include <TouchRegistry.h> |
3509 | |
3510 | #include "GestureTest.h" |
3511 | |
3512 | using namespace UbuntuGestures; |
3513 | |
3514 | - |
3515 | -class ComplexFakeTimer : public FakeTimer |
3516 | -{ |
3517 | +// Because QSignalSpy(directionalDragArea, SIGNAL(DirectionalDragArea::Status)) simply |
3518 | +// doesn't work |
3519 | +class StatusSpy : public QObject { |
3520 | Q_OBJECT |
3521 | public: |
3522 | - ComplexFakeTimer(const SharedTimeSource &timeSource, QObject *parent = 0) |
3523 | - : FakeTimer(parent), |
3524 | - m_timeSource(timeSource) |
3525 | - {} |
3526 | - |
3527 | - void start() override { |
3528 | - AbstractTimer::start(); |
3529 | - m_nextTimeoutTime = m_timeSource->msecsSinceReference() + (qint64)interval(); |
3530 | - } |
3531 | - |
3532 | - void emitTimeout() { |
3533 | - m_nextTimeoutTime += interval(); |
3534 | - Q_EMIT timeout(); |
3535 | - } |
3536 | - |
3537 | - qint64 nextTimeoutTime() const { return m_nextTimeoutTime; } |
3538 | + StatusSpy(DirectionalDragArea *edgeDragArea) { |
3539 | + m_recognized = false; |
3540 | + connect(edgeDragArea->d, &DirectionalDragAreaPrivate::statusChanged, |
3541 | + this, &StatusSpy::onStatusChanged); |
3542 | + } |
3543 | + bool recognized() { |
3544 | + return m_recognized; |
3545 | + } |
3546 | + |
3547 | +private Q_SLOTS: |
3548 | + void onStatusChanged(DirectionalDragAreaPrivate::Status status) { |
3549 | + m_recognized |= status == DirectionalDragAreaPrivate::Recognized; |
3550 | + } |
3551 | |
3552 | private: |
3553 | - SharedTimeSource m_timeSource; |
3554 | - qint64 m_nextTimeoutTime; |
3555 | -}; |
3556 | - |
3557 | -class FakeTimeSource : public UbuntuGestures::TimeSource |
3558 | -{ |
3559 | -public: |
3560 | - FakeTimeSource() { m_msecsSinceReference = 0; } |
3561 | - virtual qint64 msecsSinceReference() {return m_msecsSinceReference;} |
3562 | - qint64 m_msecsSinceReference; |
3563 | + bool m_recognized; |
3564 | }; |
3565 | |
3566 | /* |
3567 | @@ -98,15 +85,9 @@ |
3568 | tst_DirectionalDragArea(); |
3569 | private Q_SLOTS: |
3570 | void init(); // called right before each and every test function is executed |
3571 | - void cleanup(); // called right after each and every test function is executed |
3572 | |
3573 | - void edgeDrag(); |
3574 | - void edgeDrag_data(); |
3575 | void dragWithShortDirectionChange(); |
3576 | - void minSpeed(); |
3577 | - void minSpeed_data(); |
3578 | void recognitionTimerUsage(); |
3579 | - void maxSilenceTime(); |
3580 | void sceneXAndX(); |
3581 | void sceneYAndY(); |
3582 | void twoFingerTap(); |
3583 | @@ -122,14 +103,24 @@ |
3584 | void immediateRecognitionWhenConstraintsDisabled(); |
3585 | void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition(); |
3586 | void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data(); |
3587 | - void tappedSignal(); |
3588 | - void tappedSignal_data(); |
3589 | void gettingTouchOwnershipMakesMouseAreaBehindGetCanceled(); |
3590 | + void interleavedTouches(); |
3591 | + void makoRightEdgeDrag(); |
3592 | + void makoRightEdgeDrag_verticalDownwards(); |
3593 | + void makoLeftEdgeDrag_slowStart(); |
3594 | + void makoLeftEdgeDrag_movesSlightlyBackwardsOnStart(); |
3595 | |
3596 | private: |
3597 | + // QTest::touchEvent takes QPoint instead of QPointF and I don't want to |
3598 | + // lose precision due to rounding. |
3599 | + // Besides, those helper functions lead to more compact code. |
3600 | + void sendTouchPress(qint64 timestamp, int id, QPointF pos); |
3601 | + void sendTouchUpdate(qint64 timestamp, int id, QPointF pos); |
3602 | + void sendTouchRelease(qint64 timestamp, int id, QPointF pos); |
3603 | + void sendTouch(qint64 timestamp, int id, QPointF pos, |
3604 | + Qt::TouchPointState pointState, QEvent::Type eventType); |
3605 | + |
3606 | void passTime(qint64 timeSpanMs); |
3607 | - ComplexFakeTimer *fakeTimer; |
3608 | - QSharedPointer<FakeTimeSource> fakeTimeSource; |
3609 | }; |
3610 | |
3611 | tst_DirectionalDragArea::tst_DirectionalDragArea() |
3612 | @@ -148,36 +139,49 @@ |
3613 | m_view->resize(m_view->rootObject()->width(), m_view->rootObject()->height()); |
3614 | QTRY_COMPARE(m_view->width(), (int)m_view->rootObject()->width()); |
3615 | QTRY_COMPARE(m_view->height(), (int)m_view->rootObject()->height()); |
3616 | - |
3617 | - fakeTimeSource.reset(new FakeTimeSource); |
3618 | - fakeTimer = new ComplexFakeTimer(fakeTimeSource); |
3619 | -} |
3620 | - |
3621 | -void tst_DirectionalDragArea::cleanup() |
3622 | -{ |
3623 | - delete fakeTimer; |
3624 | - fakeTimer = 0; |
3625 | - |
3626 | - fakeTimeSource.reset(); |
3627 | - |
3628 | - GestureTest::cleanup(); |
3629 | +} |
3630 | + |
3631 | +void tst_DirectionalDragArea::sendTouchPress(qint64 timestamp, int id, QPointF pos) |
3632 | +{ |
3633 | + sendTouch(timestamp, id, pos, Qt::TouchPointPressed, QEvent::TouchBegin); |
3634 | +} |
3635 | + |
3636 | +void tst_DirectionalDragArea::sendTouchUpdate(qint64 timestamp, int id, QPointF pos) |
3637 | +{ |
3638 | + sendTouch(timestamp, id, pos, Qt::TouchPointMoved, QEvent::TouchUpdate); |
3639 | +} |
3640 | + |
3641 | +void tst_DirectionalDragArea::sendTouchRelease(qint64 timestamp, int id, QPointF pos) |
3642 | +{ |
3643 | + sendTouch(timestamp, id, pos, Qt::TouchPointReleased, QEvent::TouchEnd); |
3644 | +} |
3645 | + |
3646 | +void tst_DirectionalDragArea::sendTouch(qint64 timestamp, int id, QPointF pos, |
3647 | + Qt::TouchPointState pointState, QEvent::Type eventType) |
3648 | +{ |
3649 | + m_fakeTimerFactory->updateTime(timestamp); |
3650 | + |
3651 | + QTouchEvent::TouchPoint point; |
3652 | + |
3653 | + point.setState(pointState); |
3654 | + point.setId(id); |
3655 | + point.setScenePos(pos); |
3656 | + point.setPos(pos); |
3657 | + |
3658 | + QList<QTouchEvent::TouchPoint> points; |
3659 | + points << point; |
3660 | + |
3661 | + QTouchEvent touchEvent(eventType, m_device, Qt::NoModifier, Qt::TouchPointPressed, points); |
3662 | + QCoreApplication::sendEvent(m_view, &touchEvent); |
3663 | + |
3664 | + QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(m_view); |
3665 | + windowPrivate->flushDelayedTouchEvent(); |
3666 | } |
3667 | |
3668 | void tst_DirectionalDragArea::passTime(qint64 timeSpanMs) |
3669 | { |
3670 | - qint64 finalTime = fakeTimeSource->m_msecsSinceReference + timeSpanMs; |
3671 | - |
3672 | - if (fakeTimer->isRunning() && finalTime >= fakeTimer->nextTimeoutTime()) { |
3673 | - fakeTimeSource->m_msecsSinceReference = fakeTimer->nextTimeoutTime(); |
3674 | - fakeTimer->emitTimeout(); |
3675 | - |
3676 | - qint64 timeSpanRemainder = finalTime - fakeTimeSource->m_msecsSinceReference; |
3677 | - if (timeSpanRemainder > 0) { |
3678 | - passTime(timeSpanRemainder); |
3679 | - } |
3680 | - } else { |
3681 | - fakeTimeSource->m_msecsSinceReference = finalTime; |
3682 | - } |
3683 | + qint64 finalTime = m_fakeTimerFactory->timeSource()->msecsSinceReference() + timeSpanMs; |
3684 | + m_fakeTimerFactory->updateTime(finalTime); |
3685 | } |
3686 | |
3687 | namespace { |
3688 | @@ -186,147 +190,6 @@ |
3689 | QPointF localCenter(edgeDragArea->width() / 2., edgeDragArea->height() / 2.); |
3690 | return edgeDragArea->mapToScene(localCenter); |
3691 | } |
3692 | - |
3693 | -QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea, |
3694 | - qreal wideningAngleMultiplier) |
3695 | -{ |
3696 | - qreal angleRadians = edgeDragArea->wideningAngle() * wideningAngleMultiplier |
3697 | - * M_PI / 180.0; |
3698 | - |
3699 | - qreal angleCos = qCos(angleRadians); |
3700 | - qreal angleSin = qSin(angleRadians); |
3701 | - |
3702 | - switch (edgeDragArea->direction()) { |
3703 | - case Direction::Upwards: |
3704 | - return QPointF(angleSin, -angleCos); |
3705 | - case Direction::Downwards: |
3706 | - return QPointF(angleSin, angleCos); |
3707 | - case Direction::Leftwards: |
3708 | - return QPointF(-angleCos, angleSin); |
3709 | - default: // Direction::Rightwards: |
3710 | - return QPointF(angleCos, angleSin); |
3711 | - } |
3712 | -} |
3713 | - |
3714 | -QPointF createTouchDeviation(DirectionalDragArea *edgeDragArea) |
3715 | -{ |
3716 | - qreal deviation = edgeDragArea->maxDeviation() * 0.8; |
3717 | - |
3718 | - if (Direction::isHorizontal(edgeDragArea->direction())) { |
3719 | - return QPointF(0, deviation); |
3720 | - } else { |
3721 | - return QPointF(deviation, 0); |
3722 | - } |
3723 | -} |
3724 | -} |
3725 | - |
3726 | -void tst_DirectionalDragArea::edgeDrag() |
3727 | -{ |
3728 | - QFETCH(QString, dragAreaObjectName); |
3729 | - QFETCH(qreal, wideningAngleMultiplier); |
3730 | - QFETCH(qreal, dragDistanceFactor); |
3731 | - QFETCH(bool, expectGestureRecognition); |
3732 | - |
3733 | - DirectionalDragArea *edgeDragArea = |
3734 | - m_view->rootObject()->findChild<DirectionalDragArea*>(dragAreaObjectName); |
3735 | - QVERIFY(edgeDragArea != 0); |
3736 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
3737 | - edgeDragArea->setTimeSource(fakeTimeSource); |
3738 | - |
3739 | - QSignalSpy draggingSpy(edgeDragArea, SIGNAL(draggingChanged(bool))); |
3740 | - |
3741 | - QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea); |
3742 | - QPointF touchPoint = initialTouchPos; |
3743 | - |
3744 | - qreal desiredDragDistance = edgeDragArea->distanceThreshold()*dragDistanceFactor; |
3745 | - QPointF dragDirectionVector = calculateDirectionVector(edgeDragArea, |
3746 | - wideningAngleMultiplier); |
3747 | - qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f; |
3748 | - QPointF touchMovement = dragDirectionVector * movementStepDistance; |
3749 | - int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance); |
3750 | - int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps; |
3751 | - |
3752 | - QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint()); |
3753 | - |
3754 | - QCOMPARE(draggingSpy.count(), 1); |
3755 | - QCOMPARE(edgeDragArea->dragging(), true); |
3756 | - |
3757 | - if (wideningAngleMultiplier > 0) { |
3758 | - // go close to the border of the valid area for this touch point |
3759 | - // in order to make it easier to leave it by dragging at an angle |
3760 | - // slightly bigger than the widening angle |
3761 | - touchPoint += createTouchDeviation(edgeDragArea); |
3762 | - QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint()); |
3763 | - } |
3764 | - |
3765 | - for (int i = 0; i < totalMovementSteps; ++i) { |
3766 | - touchPoint += touchMovement; |
3767 | - passTime(movementTimeStepMs); |
3768 | - QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint()); |
3769 | - } |
3770 | - |
3771 | - if (expectGestureRecognition) |
3772 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); |
3773 | - |
3774 | - if (edgeDragArea->status() == DirectionalDragArea::WaitingForTouch) { |
3775 | - QCOMPARE(edgeDragArea->dragging(), false); |
3776 | - QCOMPARE(draggingSpy.count(), 2); |
3777 | - } |
3778 | - |
3779 | - QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint()); |
3780 | - |
3781 | - QCOMPARE(draggingSpy.count(), 2); |
3782 | - QCOMPARE(edgeDragArea->dragging(), false); |
3783 | -} |
3784 | - |
3785 | -void tst_DirectionalDragArea::edgeDrag_data() |
3786 | -{ |
3787 | - QTest::addColumn<QString>("dragAreaObjectName"); |
3788 | - QTest::addColumn<qreal>("wideningAngleMultiplier"); |
3789 | - QTest::addColumn<qreal>("dragDistanceFactor"); |
3790 | - QTest::addColumn<bool>("expectGestureRecognition"); |
3791 | - |
3792 | - QTest::newRow("rightwards, tiny drag") |
3793 | - << "hpDragArea" << 0.0 << 0.2 << false; |
3794 | - |
3795 | - QTest::newRow("rightwards, straight drag") |
3796 | - << "hpDragArea" << 0.0 << 3.0 << true; |
3797 | - |
3798 | - QTest::newRow("rightwards, diagonal drag") |
3799 | - << "hpDragArea" << 0.9 << 3.0 << true; |
3800 | - |
3801 | - QTest::newRow("rightwards, overly diagonal drag") |
3802 | - << "hpDragArea" << 2.0 << 3.0 << false; |
3803 | - |
3804 | - QTest::newRow("leftwards, tiny drag") |
3805 | - << "hnDragArea" << 0.0 << 0.2 << false; |
3806 | - |
3807 | - QTest::newRow("leftwards, straight drag") |
3808 | - << "hnDragArea" << 0.0 << 3.0 << true; |
3809 | - |
3810 | - QTest::newRow("leftwards, diagonal drag") |
3811 | - << "hnDragArea" << 0.9 << 3.0 << true; |
3812 | - |
3813 | - QTest::newRow("downwards, tiny drag") |
3814 | - << "vpDragArea" << 0.0 << 0.2 << false; |
3815 | - |
3816 | - QTest::newRow("downwards, straight drag") |
3817 | - << "vpDragArea" << 0.0 << 3.0 << true; |
3818 | - |
3819 | - QTest::newRow("downwards, diagonal drag") |
3820 | - << "vpDragArea" << 0.9 << 3.0 << true; |
3821 | - |
3822 | - QTest::newRow("upwards, tiny drag") |
3823 | - << "vnDragArea" << 0.0 << 0.2 << false; |
3824 | - |
3825 | - QTest::newRow("upwards, straight drag") |
3826 | - << "vnDragArea" << 0.0 << 3.0 << true; |
3827 | - |
3828 | - QTest::newRow("upwards, diagonal drag") |
3829 | - << "vnDragArea" << 0.9 << 3.0 << true; |
3830 | - |
3831 | - QTest::newRow("upwards, overly diagonal drag") |
3832 | - << "vnDragArea" << 2.0 << 3.0 << false; |
3833 | } |
3834 | |
3835 | /* |
3836 | @@ -339,17 +202,17 @@ |
3837 | DirectionalDragArea *edgeDragArea = |
3838 | m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
3839 | QVERIFY(edgeDragArea != 0); |
3840 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
3841 | - edgeDragArea->setTimeSource(fakeTimeSource); |
3842 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
3843 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
3844 | |
3845 | QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea); |
3846 | QPointF touchPoint = initialTouchPos; |
3847 | |
3848 | - qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0; |
3849 | + qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0; |
3850 | QPointF dragDirectionVector(1.0, 0.0); |
3851 | - qreal touchStepDistance = edgeDragArea->distanceThreshold() * 0.1f; |
3852 | - // make sure we are above minimum speed |
3853 | - int touchStepTimeMs = (touchStepDistance / (edgeDragArea->minSpeed() * 5.0f)) * 1000.0f; |
3854 | + qreal touchStepDistance = edgeDragArea->d->distanceThreshold * 0.1f; |
3855 | + // make sure we are above maximum time |
3856 | + int touchStepTimeMs = edgeDragArea->d->maxTime / 20. ; |
3857 | QPointF touchMovement = dragDirectionVector * touchStepDistance; |
3858 | |
3859 | QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint()); |
3860 | @@ -373,66 +236,14 @@ |
3861 | passTime(touchStepTimeMs); |
3862 | QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint()); |
3863 | } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance |
3864 | - || fakeTimeSource->m_msecsSinceReference < (edgeDragArea->compositionTime() * 1.5f)); |
3865 | + || m_fakeTimerFactory->timeSource()->msecsSinceReference() < (edgeDragArea->d->compositionTime * 1.5f)); |
3866 | |
3867 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); |
3868 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized); |
3869 | |
3870 | QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint()); |
3871 | } |
3872 | |
3873 | /* |
3874 | - Checks that a gesture will be rejected if it's slower than minSpeed while |
3875 | - status is Undecided. |
3876 | - */ |
3877 | -void tst_DirectionalDragArea::minSpeed() |
3878 | -{ |
3879 | - QFETCH(qreal, minSpeed); |
3880 | - QFETCH(qreal, speed); |
3881 | - QFETCH(int, expectedStatusAfterSpeedCheck); |
3882 | - |
3883 | - DirectionalDragArea *edgeDragArea = |
3884 | - m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
3885 | - QVERIFY(edgeDragArea != 0); |
3886 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
3887 | - edgeDragArea->setTimeSource(fakeTimeSource); |
3888 | - |
3889 | - // A really long, unattainable, number. We don't want it getting recognized before |
3890 | - // the speed checks we want have been performed |
3891 | - edgeDragArea->setDistanceThreshold(500000); |
3892 | - |
3893 | - edgeDragArea->setMinSpeed(minSpeed); |
3894 | - |
3895 | - QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea); |
3896 | - QPointF touchPoint = initialTouchPos; |
3897 | - |
3898 | - QPointF dragDirectionVector(1.0, 0.0); |
3899 | - qint64 timeStepMsecs = 10; |
3900 | - qreal distanceStep = (speed / 1000.0f) * timeStepMsecs; |
3901 | - QPointF touchMovement = dragDirectionVector * distanceStep; |
3902 | - |
3903 | - QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint()); |
3904 | - |
3905 | - // Move for a while to ensure our speed check is performed a couple of times |
3906 | - for (int i=0; i < 20; ++i) { |
3907 | - touchPoint += touchMovement; |
3908 | - passTime(timeStepMsecs); |
3909 | - QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint()); |
3910 | - } |
3911 | - |
3912 | - QCOMPARE((int)edgeDragArea->status(), expectedStatusAfterSpeedCheck); |
3913 | -} |
3914 | - |
3915 | -void tst_DirectionalDragArea::minSpeed_data() |
3916 | -{ |
3917 | - QTest::addColumn<qreal>("minSpeed"); |
3918 | - QTest::addColumn<qreal>("speed"); |
3919 | - QTest::addColumn<int>("expectedStatusAfterSpeedCheck"); |
3920 | - |
3921 | - QTest::newRow("slower than minSpeed") << 100.0 << 50.0 << (int)DirectionalDragArea::WaitingForTouch; |
3922 | - QTest::newRow("faster than minSpeed") << 100.0 << 150.0 << (int)DirectionalDragArea::Undecided; |
3923 | -} |
3924 | - |
3925 | -/* |
3926 | Checks that the recognition timer is started and stopped appropriately. |
3927 | I.e., check that it's running only while gesture recognition is taking place |
3928 | (status == Undecided) |
3929 | @@ -442,11 +253,9 @@ |
3930 | DirectionalDragArea *edgeDragArea = |
3931 | m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
3932 | QVERIFY(edgeDragArea != 0); |
3933 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
3934 | - edgeDragArea->setTimeSource(fakeTimeSource); |
3935 | - |
3936 | - // don't let it interfere with our test |
3937 | - edgeDragArea->setMinSpeed(0.0); |
3938 | + AbstractTimer *fakeTimer = m_fakeTimerFactory->createTimer(); |
3939 | + edgeDragArea->d->setRecognitionTimer(fakeTimer); |
3940 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
3941 | |
3942 | int timeStepMs = 5; // some arbitrary small value. |
3943 | |
3944 | @@ -454,63 +263,32 @@ |
3945 | QPointF touchPoint = initialTouchPos; |
3946 | |
3947 | QPointF dragDirectionVector(1.0, 0.0); |
3948 | - QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.2f); |
3949 | + QPointF touchMovement = dragDirectionVector * (edgeDragArea->d->distanceThreshold * 0.2f); |
3950 | |
3951 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
3952 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
3953 | QVERIFY(!fakeTimer->isRunning()); |
3954 | |
3955 | QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint()); |
3956 | |
3957 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided); |
3958 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided); |
3959 | QVERIFY(fakeTimer->isRunning()); |
3960 | |
3961 | // Move beyond distance threshold and composition time to ensure recognition |
3962 | - while (fakeTimeSource->m_msecsSinceReference <= edgeDragArea->compositionTime() || |
3963 | - (touchPoint - initialTouchPos).manhattanLength() <= edgeDragArea->distanceThreshold()) { |
3964 | + while (m_fakeTimerFactory->timeSource()->msecsSinceReference() <= edgeDragArea->d->compositionTime || |
3965 | + (touchPoint - initialTouchPos).manhattanLength() <= edgeDragArea->d->distanceThreshold) { |
3966 | |
3967 | - QCOMPARE(edgeDragArea->status() == DirectionalDragArea::Undecided, fakeTimer->isRunning()); |
3968 | + QCOMPARE(edgeDragArea->d->status == DirectionalDragAreaPrivate::Undecided, fakeTimer->isRunning()); |
3969 | |
3970 | touchPoint += touchMovement; |
3971 | passTime(timeStepMs); |
3972 | QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint()); |
3973 | } |
3974 | |
3975 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); |
3976 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized); |
3977 | QVERIFY(!fakeTimer->isRunning()); |
3978 | } |
3979 | |
3980 | /* |
3981 | - A gesture should be rejected if too much time has passed without any new input |
3982 | - events from it. |
3983 | - */ |
3984 | -void tst_DirectionalDragArea::maxSilenceTime() |
3985 | -{ |
3986 | - DirectionalDragArea *edgeDragArea = |
3987 | - m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
3988 | - QVERIFY(edgeDragArea != 0); |
3989 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
3990 | - edgeDragArea->setTimeSource(fakeTimeSource); |
3991 | - |
3992 | - // Make sure this property is not disabled |
3993 | - edgeDragArea->setMaxSilenceTime(100); |
3994 | - |
3995 | - QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea); |
3996 | - QPointF touchPoint = initialTouchPos; |
3997 | - |
3998 | - QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint()); |
3999 | - |
4000 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided); |
4001 | - QVERIFY(fakeTimer->isRunning()); |
4002 | - |
4003 | - // Force timer to timeout until after maxSilenceTime has been reached |
4004 | - while (fakeTimeSource->m_msecsSinceReference < edgeDragArea->maxSilenceTime()) { |
4005 | - passTime(fakeTimer->interval()); |
4006 | - } |
4007 | - |
4008 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4009 | -} |
4010 | - |
4011 | -/* |
4012 | Checks that it informs the X coordinate of the touch point in local and scene coordinates |
4013 | correctly. |
4014 | */ |
4015 | @@ -519,18 +297,19 @@ |
4016 | DirectionalDragArea *edgeDragArea = |
4017 | m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea"); |
4018 | QVERIFY(edgeDragArea != 0); |
4019 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4020 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4021 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4022 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4023 | + edgeDragArea->setImmediateRecognition(true); |
4024 | |
4025 | QPointF touchScenePos(m_view->width() - (edgeDragArea->width()/2.0f), m_view->height()/2.0f); |
4026 | |
4027 | - QTest::touchEvent(m_view, m_device).press(0, touchScenePos.toPoint()); |
4028 | + sendTouchPress(0 /* timestamp */, 0 /* id */, touchScenePos); |
4029 | |
4030 | QSignalSpy touchXSpy(edgeDragArea, SIGNAL(touchXChanged(qreal))); |
4031 | QSignalSpy touchSceneXSpy(edgeDragArea, SIGNAL(touchSceneXChanged(qreal))); |
4032 | |
4033 | touchScenePos.rx() = m_view->width() / 2; |
4034 | - QTest::touchEvent(m_view, m_device).move(0, touchScenePos.toPoint()); |
4035 | + sendTouchUpdate(50 /* timestamp */, 0 /* id */, touchScenePos); |
4036 | |
4037 | QCOMPARE(touchXSpy.count(), 1); |
4038 | QCOMPARE(touchSceneXSpy.count(), 1); |
4039 | @@ -547,18 +326,19 @@ |
4040 | DirectionalDragArea *edgeDragArea = |
4041 | m_view->rootObject()->findChild<DirectionalDragArea*>("vnDragArea"); |
4042 | QVERIFY(edgeDragArea != 0); |
4043 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4044 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4045 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4046 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4047 | + edgeDragArea->setImmediateRecognition(true); |
4048 | |
4049 | QPointF touchScenePos(m_view->width()/2.0f, m_view->height() - (edgeDragArea->height()/2.0f)); |
4050 | |
4051 | - QTest::touchEvent(m_view, m_device).press(0, touchScenePos.toPoint()); |
4052 | + sendTouchPress(0 /* timestamp */, 0 /* id */, touchScenePos); |
4053 | |
4054 | QSignalSpy touchYSpy(edgeDragArea, SIGNAL(touchYChanged(qreal))); |
4055 | QSignalSpy touchSceneYSpy(edgeDragArea, SIGNAL(touchSceneYChanged(qreal))); |
4056 | |
4057 | touchScenePos.ry() = m_view->height() / 2; |
4058 | - QTest::touchEvent(m_view, m_device).move(0, touchScenePos.toPoint()); |
4059 | + sendTouchUpdate(50 /* timestamp */, 0 /* id */, touchScenePos); |
4060 | |
4061 | QCOMPARE(touchYSpy.count(), 1); |
4062 | QCOMPARE(touchSceneYSpy.count(), 1); |
4063 | @@ -577,8 +357,8 @@ |
4064 | DirectionalDragArea *edgeDragArea = |
4065 | m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4066 | QVERIFY(edgeDragArea != 0); |
4067 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4068 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4069 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4070 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4071 | |
4072 | // Make touches evenly spaced along the edgeDragArea |
4073 | QPoint touchAPos(edgeDragArea->width()/2.0f, m_view->height()*0.33f); |
4074 | @@ -592,7 +372,7 @@ |
4075 | QTest::touchEvent(m_view, m_device) |
4076 | .press(0, touchAPos); |
4077 | |
4078 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided); |
4079 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided); |
4080 | |
4081 | passTime(timeStepMsecs); |
4082 | QTest::touchEvent(m_view, m_device) |
4083 | @@ -601,20 +381,20 @@ |
4084 | |
4085 | // A second touch point appeared during recognition, reject immediately as this |
4086 | // can't be a single-touch gesture anymore. |
4087 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4088 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4089 | |
4090 | passTime(timeStepMsecs); |
4091 | QTest::touchEvent(m_view, m_device) |
4092 | .release(0, touchAPos) |
4093 | .move(1, touchBPos); |
4094 | |
4095 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4096 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4097 | |
4098 | passTime(timeStepMsecs); |
4099 | QTest::touchEvent(m_view, m_device) |
4100 | .release(1, touchBPos); |
4101 | |
4102 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4103 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4104 | |
4105 | // Perform the second two-finger tap |
4106 | |
4107 | @@ -622,27 +402,27 @@ |
4108 | QTest::touchEvent(m_view, m_device) |
4109 | .press(0, touchAPos); |
4110 | |
4111 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided); |
4112 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided); |
4113 | |
4114 | passTime(timeStepMsecs); |
4115 | QTest::touchEvent(m_view, m_device) |
4116 | .move(0, touchAPos) |
4117 | .press(1, touchBPos); |
4118 | |
4119 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4120 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4121 | |
4122 | passTime(timeStepMsecs); |
4123 | QTest::touchEvent(m_view, m_device) |
4124 | .release(0, touchAPos) |
4125 | .move(1, touchBPos); |
4126 | |
4127 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4128 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4129 | |
4130 | passTime(timeStepMsecs); |
4131 | QTest::touchEvent(m_view, m_device) |
4132 | .release(1, touchBPos); |
4133 | |
4134 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4135 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4136 | } |
4137 | |
4138 | /* |
4139 | @@ -659,25 +439,25 @@ |
4140 | DirectionalDragArea *edgeDragArea = |
4141 | rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea"); |
4142 | Q_ASSERT(edgeDragArea != 0); |
4143 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4144 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4145 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4146 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4147 | |
4148 | QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea); |
4149 | QPointF touchPoint = initialTouchPos; |
4150 | |
4151 | - qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f; |
4152 | + qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f; |
4153 | QPointF dragDirectionVector(1.0f, 0.0f); |
4154 | |
4155 | - qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f; |
4156 | + qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f; |
4157 | QPointF touchMovement = dragDirectionVector * movementStepDistance; |
4158 | int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance); |
4159 | - int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps; |
4160 | + int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps; |
4161 | |
4162 | QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint()); |
4163 | |
4164 | // Move it far ahead along the direction of the gesture |
4165 | // rightwardsLauncher is a parent of our DirectionalDragArea. So moving it will move our DDA |
4166 | - rightwardsLauncher->setX(rightwardsLauncher->x() + edgeDragArea->distanceThreshold() * 5.0f); |
4167 | + rightwardsLauncher->setX(rightwardsLauncher->x() + edgeDragArea->d->distanceThreshold * 5.0f); |
4168 | |
4169 | for (int i = 0; i < totalMovementSteps; ++i) { |
4170 | touchPoint += touchMovement; |
4171 | @@ -685,7 +465,7 @@ |
4172 | QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint()); |
4173 | } |
4174 | |
4175 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); |
4176 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized); |
4177 | |
4178 | QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint()); |
4179 | } |
4180 | @@ -699,8 +479,8 @@ |
4181 | DirectionalDragArea *edgeDragArea = |
4182 | m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4183 | Q_ASSERT(edgeDragArea != 0); |
4184 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4185 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4186 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4187 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4188 | |
4189 | // Make touches evenly spaced along the edgeDragArea |
4190 | QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f); |
4191 | @@ -708,26 +488,26 @@ |
4192 | |
4193 | QTest::touchEvent(m_view, m_device).press(0, touch0Pos); |
4194 | |
4195 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided); |
4196 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided); |
4197 | |
4198 | // leave it lying around for some time |
4199 | - passTime(qMax(edgeDragArea->maxSilenceTime(), edgeDragArea->compositionTime()) * 10); |
4200 | - |
4201 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4202 | - |
4203 | - qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f; |
4204 | + passTime(edgeDragArea->d->maxTime * 10); |
4205 | + |
4206 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4207 | + |
4208 | + qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f; |
4209 | QPointF dragDirectionVector(1.0f, 0.0f); |
4210 | |
4211 | - qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f; |
4212 | + qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f; |
4213 | QPointF touchMovement = dragDirectionVector * movementStepDistance; |
4214 | int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance); |
4215 | - int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps; |
4216 | + int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps; |
4217 | |
4218 | QTest::touchEvent(m_view, m_device) |
4219 | .move(0, touch0Pos) |
4220 | .press(1, touch1Pos); |
4221 | |
4222 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided); |
4223 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided); |
4224 | |
4225 | for (int i = 0; i < totalMovementSteps; ++i) { |
4226 | touch1Pos += touchMovement.toPoint(); |
4227 | @@ -737,13 +517,13 @@ |
4228 | .move(1, touch1Pos); |
4229 | } |
4230 | |
4231 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); |
4232 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized); |
4233 | |
4234 | QTest::touchEvent(m_view, m_device) |
4235 | .move(0, touch0Pos) |
4236 | .release(1, touch1Pos); |
4237 | |
4238 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4239 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4240 | } |
4241 | |
4242 | /* |
4243 | @@ -762,19 +542,19 @@ |
4244 | DirectionalDragArea *edgeDragArea = |
4245 | rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea"); |
4246 | Q_ASSERT(edgeDragArea != 0); |
4247 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4248 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4249 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4250 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4251 | |
4252 | QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea); |
4253 | QPointF touchPoint = initialTouchPos; |
4254 | |
4255 | - qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f; |
4256 | + qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f; |
4257 | QPointF dragDirectionVector(0.0f, 1.0f); |
4258 | |
4259 | - qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f; |
4260 | + qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f; |
4261 | QPointF touchMovement = dragDirectionVector * movementStepDistance; |
4262 | int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance); |
4263 | - int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps; |
4264 | + int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps; |
4265 | |
4266 | QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint()); |
4267 | |
4268 | @@ -784,7 +564,7 @@ |
4269 | QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint()); |
4270 | } |
4271 | |
4272 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); |
4273 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized); |
4274 | |
4275 | QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint()); |
4276 | } |
4277 | @@ -802,31 +582,30 @@ |
4278 | DirectionalDragArea *edgeDragArea = |
4279 | rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea"); |
4280 | Q_ASSERT(edgeDragArea != 0); |
4281 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4282 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4283 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4284 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4285 | + |
4286 | + // to disable the position smoothing so that we can more easily check sceneDistance values |
4287 | + edgeDragArea->setImmediateRecognition(true); |
4288 | |
4289 | QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea); |
4290 | QPointF touchPoint = initialTouchPos; |
4291 | |
4292 | - qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f; |
4293 | + qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f; |
4294 | |
4295 | - qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f; |
4296 | + qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f; |
4297 | QPointF touchMovement = dragDirectionVector * movementStepDistance; |
4298 | int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance); |
4299 | - int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps; |
4300 | - |
4301 | - QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint()); |
4302 | - |
4303 | -#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) |
4304 | - QQuickWindowPrivate *wp = QQuickWindowPrivate::get(m_view); |
4305 | -#endif |
4306 | + int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps; |
4307 | + |
4308 | + qint64 timestamp = 0; |
4309 | + |
4310 | + sendTouchPress(timestamp, 0, touchPoint); |
4311 | + |
4312 | for (int i = 0; i < totalMovementSteps; ++i) { |
4313 | touchPoint += touchMovement; |
4314 | - passTime(movementTimeStepMs); |
4315 | - QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint()); |
4316 | -#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) |
4317 | - wp->flushDelayedTouchEvent(); |
4318 | -#endif |
4319 | + timestamp += movementTimeStepMs; |
4320 | + sendTouchUpdate(timestamp, 0, touchPoint); |
4321 | } |
4322 | |
4323 | qreal actualDragDistance = ((qreal)totalMovementSteps) * movementStepDistance; |
4324 | @@ -836,7 +615,8 @@ |
4325 | // NB: qFuzzyCompare(), used internally by QCOMPARE(), is broken. |
4326 | QVERIFY(qAbs(edgeDragArea->sceneDistance() - actualDragDistance) < 0.001); |
4327 | |
4328 | - QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint()); |
4329 | + timestamp += movementTimeStepMs; |
4330 | + sendTouchRelease(timestamp, 0, touchPoint); |
4331 | } |
4332 | |
4333 | void tst_DirectionalDragArea::sceneDistance_data() |
4334 | @@ -860,18 +640,18 @@ |
4335 | DirectionalDragArea *edgeDragArea = |
4336 | m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4337 | Q_ASSERT(edgeDragArea != 0); |
4338 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4339 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4340 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4341 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4342 | |
4343 | QPointF touchPoint = calculateInitialTouchPos(edgeDragArea); |
4344 | |
4345 | - qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f; |
4346 | + qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f; |
4347 | QPointF dragDirectionVector(1., 0.); // horizontal positive |
4348 | |
4349 | - qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f; |
4350 | + qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f; |
4351 | QPointF touchMovement = dragDirectionVector * movementStepDistance; |
4352 | int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance); |
4353 | - int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps; |
4354 | + int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps; |
4355 | |
4356 | QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint()); |
4357 | |
4358 | @@ -881,13 +661,13 @@ |
4359 | QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint()); |
4360 | } |
4361 | |
4362 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); |
4363 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized); |
4364 | QCOMPARE(edgeDragArea->dragging(), true); |
4365 | |
4366 | // disable the dragArea while it's being dragged. |
4367 | edgeDragArea->setEnabled(false); |
4368 | |
4369 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4370 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4371 | QCOMPARE(edgeDragArea->dragging(), false); |
4372 | |
4373 | QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint()); |
4374 | @@ -898,15 +678,14 @@ |
4375 | DirectionalDragArea *edgeDragArea = |
4376 | m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4377 | Q_ASSERT(edgeDragArea != 0); |
4378 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4379 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4380 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4381 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4382 | |
4383 | // Disable some constraints we're not interested in |
4384 | - edgeDragArea->setMaxSilenceTime(60 * 1000); |
4385 | - edgeDragArea->setMinSpeed(0); |
4386 | + edgeDragArea->d->setMaxTime(60 * 1000); |
4387 | |
4388 | // And ensure others have the values we want |
4389 | - edgeDragArea->setCompositionTime(60); |
4390 | + edgeDragArea->d->compositionTime = 60; |
4391 | |
4392 | // Put an item right behind edgeDragArea to receive the touches ignored by it |
4393 | DummyItem *dummyItem = new DummyItem; |
4394 | @@ -923,10 +702,10 @@ |
4395 | |
4396 | QTest::touchEvent(m_view, m_device).press(0, touch0Pos); |
4397 | |
4398 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided); |
4399 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided); |
4400 | |
4401 | // We are now going to be way beyond compositionTime |
4402 | - passTime(edgeDragArea->compositionTime()*3); |
4403 | + passTime(edgeDragArea->d->compositionTime*3); |
4404 | |
4405 | QTest::touchEvent(m_view, m_device) |
4406 | .move(0, touch0Pos) |
4407 | @@ -948,7 +727,7 @@ |
4408 | .move(0, touch0Pos) |
4409 | .move(1, touch1Pos); |
4410 | |
4411 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided); |
4412 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided); |
4413 | |
4414 | passTime(5); |
4415 | |
4416 | @@ -956,7 +735,7 @@ |
4417 | .release(0, touch0Pos) |
4418 | .move(1, touch1Pos); |
4419 | |
4420 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4421 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4422 | |
4423 | passTime(5); |
4424 | |
4425 | @@ -964,7 +743,7 @@ |
4426 | .release(1, touch1Pos); |
4427 | |
4428 | // Shouldn't be keepping info about touches that no longer exist or interest us |
4429 | - QVERIFY(edgeDragArea->m_activeTouches.isEmpty()); |
4430 | + QVERIFY(edgeDragArea->d->activeTouches.isEmpty()); |
4431 | |
4432 | delete dummyItem; |
4433 | } |
4434 | @@ -974,12 +753,11 @@ |
4435 | DirectionalDragArea *edgeDragArea = |
4436 | m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4437 | Q_ASSERT(edgeDragArea != 0); |
4438 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4439 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4440 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4441 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4442 | |
4443 | // Disable some constraints we're not interested in |
4444 | - edgeDragArea->setMaxSilenceTime(60 * 1000); |
4445 | - edgeDragArea->setMinSpeed(0); |
4446 | + edgeDragArea->d->setMaxTime(60 * 1000); |
4447 | |
4448 | // Put an item right in front of edgeDragArea |
4449 | DummyItem *dummyItem = new DummyItem(edgeDragArea->parentItem()); |
4450 | @@ -998,11 +776,11 @@ |
4451 | |
4452 | QTest::touchEvent(m_view, m_device).press(0, touchPos); |
4453 | |
4454 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided); |
4455 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided); |
4456 | |
4457 | m_touchRegistry->requestTouchOwnership(0, dummyItem); |
4458 | |
4459 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4460 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4461 | |
4462 | dummyItem->grabTouchPoints({0}); |
4463 | dummyItem->touchEventHandler = [&](QTouchEvent *event) { event->accept(); }; |
4464 | @@ -1010,9 +788,9 @@ |
4465 | passTime(5); |
4466 | QTest::touchEvent(m_view, m_device).release(0, touchPos); |
4467 | |
4468 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4469 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4470 | |
4471 | - QVERIFY(edgeDragArea->m_activeTouches.isEmpty()); |
4472 | + QVERIFY(edgeDragArea->d->activeTouches.isEmpty()); |
4473 | } |
4474 | |
4475 | void tst_DirectionalDragArea::threeFingerDrag() |
4476 | @@ -1020,15 +798,14 @@ |
4477 | DirectionalDragArea *edgeDragArea = |
4478 | m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4479 | Q_ASSERT(edgeDragArea != 0); |
4480 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4481 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4482 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4483 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4484 | |
4485 | // Disable some constraints we're not interested in |
4486 | - edgeDragArea->setMaxSilenceTime(60 * 1000); |
4487 | - edgeDragArea->setMinSpeed(0); |
4488 | + edgeDragArea->d->setMaxTime(60 * 1000); |
4489 | |
4490 | // And ensure others have the values we want |
4491 | - edgeDragArea->setCompositionTime(60); |
4492 | + edgeDragArea->d->compositionTime = 60; |
4493 | |
4494 | // Make touches evenly spaced along the edgeDragArea |
4495 | QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.25f); |
4496 | @@ -1038,14 +815,14 @@ |
4497 | QTest::touchEvent(m_view, m_device) |
4498 | .press(0, touch0Pos); |
4499 | |
4500 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided); |
4501 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided); |
4502 | |
4503 | passTime(5); |
4504 | QTest::touchEvent(m_view, m_device) |
4505 | .move(0, touch0Pos) |
4506 | .press(1, touch1Pos); |
4507 | |
4508 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4509 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4510 | |
4511 | passTime(5); |
4512 | QTest::touchEvent(m_view, m_device) |
4513 | @@ -1053,7 +830,7 @@ |
4514 | .move(1, touch1Pos) |
4515 | .press(2, touch2Pos); |
4516 | |
4517 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4518 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4519 | |
4520 | passTime(10); |
4521 | QTest::touchEvent(m_view, m_device) |
4522 | @@ -1077,7 +854,7 @@ |
4523 | .release(0, touch0Pos); |
4524 | |
4525 | // Shouldn't be keepping info about touches that no longer exist or interest us |
4526 | - QVERIFY(edgeDragArea->m_activeTouches.isEmpty()); |
4527 | + QVERIFY(edgeDragArea->d->activeTouches.isEmpty()); |
4528 | } |
4529 | |
4530 | /* |
4531 | @@ -1090,12 +867,12 @@ |
4532 | DirectionalDragArea *edgeDragArea = |
4533 | m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4534 | Q_ASSERT(edgeDragArea != 0); |
4535 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4536 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4537 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4538 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4539 | |
4540 | // Disable the minimum amount of constraints to ensure immediate recognition |
4541 | - edgeDragArea->setDistanceThreshold(0); |
4542 | - edgeDragArea->setCompositionTime(0); |
4543 | + edgeDragArea->d->setDistanceThreshold(0); |
4544 | + edgeDragArea->d->compositionTime = 0; |
4545 | |
4546 | // Put an item right behind edgeDragArea to receive the touches ignored by it |
4547 | DummyItem *dummyItem = new DummyItem; |
4548 | @@ -1111,7 +888,7 @@ |
4549 | QTest::touchEvent(m_view, m_device).press(0, touch0Pos); |
4550 | |
4551 | // check for immediate recognition |
4552 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); |
4553 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized); |
4554 | |
4555 | // and therefore it should have immediately grabbed the touch point, |
4556 | // not letting it leak to items behind him. |
4557 | @@ -1123,19 +900,19 @@ |
4558 | DirectionalDragArea *edgeDragArea = |
4559 | m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4560 | Q_ASSERT(edgeDragArea != 0); |
4561 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4562 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4563 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4564 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4565 | |
4566 | QPointF touchPoint = calculateInitialTouchPos(edgeDragArea); |
4567 | |
4568 | // Move less than the minimum needed for the drag gesture recognition |
4569 | - qreal desiredDragDistance = edgeDragArea->distanceThreshold()*0.5f; |
4570 | + qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 0.5f; |
4571 | QPointF dragDirectionVector(1., 0.); // horizontal positive |
4572 | |
4573 | - qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f; |
4574 | + qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f; |
4575 | QPointF touchMovement = dragDirectionVector * movementStepDistance; |
4576 | int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance); |
4577 | - int movementTimeStepMs = (edgeDragArea->compositionTime() * 0.8f) / totalMovementSteps; |
4578 | + int movementTimeStepMs = (edgeDragArea->d->compositionTime * 0.8f) / totalMovementSteps; |
4579 | |
4580 | QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint()); |
4581 | |
4582 | @@ -1145,14 +922,14 @@ |
4583 | QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint()); |
4584 | } |
4585 | |
4586 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided); |
4587 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided); |
4588 | |
4589 | // edgeDragArea should be an undecided candidate |
4590 | { |
4591 | auto touchInfo = m_touchRegistry->findTouchInfo(0); |
4592 | QCOMPARE(touchInfo->candidates.size(), 1); |
4593 | QCOMPARE(touchInfo->candidates.at(0).item.data(), edgeDragArea); |
4594 | - QCOMPARE(touchInfo->candidates.at(0).undecided, true); |
4595 | + QCOMPARE(touchInfo->candidates.at(0).state, TouchRegistry::CandidateInfo::Undecided); |
4596 | } |
4597 | |
4598 | // disable the dragArea while it's still recognizing a possible drag gesture. |
4599 | @@ -1169,7 +946,7 @@ |
4600 | QCOMPARE(touchInfo->candidates.size(), 0); |
4601 | } |
4602 | |
4603 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch); |
4604 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4605 | |
4606 | QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint()); |
4607 | } |
4608 | @@ -1182,47 +959,13 @@ |
4609 | QTest::newRow("invisible") << false; |
4610 | } |
4611 | |
4612 | -void tst_DirectionalDragArea::tappedSignal() |
4613 | -{ |
4614 | - DirectionalDragArea *edgeDragArea = |
4615 | - m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4616 | - QVERIFY(edgeDragArea != 0); |
4617 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4618 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4619 | - |
4620 | - QFETCH(bool, immediateGestureRecognition); |
4621 | - if (immediateGestureRecognition) { |
4622 | - // Disable the minimum amount of constraints to ensure immediate recognition |
4623 | - edgeDragArea->setDistanceThreshold(0); |
4624 | - edgeDragArea->setCompositionTime(0); |
4625 | - } |
4626 | - |
4627 | - QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()/2.0f); |
4628 | - |
4629 | - QSignalSpy tappedSpy(edgeDragArea, SIGNAL(tapped())); |
4630 | - |
4631 | - QTest::touchEvent(m_view, m_device).press(0, touch0Pos); |
4632 | - passTime(edgeDragArea->maxTapDuration() / 2); |
4633 | - QTest::touchEvent(m_view, m_device).release(0, touch0Pos); |
4634 | - |
4635 | - QCOMPARE(tappedSpy.count(), 1); |
4636 | -} |
4637 | - |
4638 | -void tst_DirectionalDragArea::tappedSignal_data() |
4639 | -{ |
4640 | - QTest::addColumn<bool>("immediateGestureRecognition"); |
4641 | - |
4642 | - QTest::newRow("immediate gesture recognition") << true; |
4643 | - QTest::newRow("default gesture recognition") << false; |
4644 | -} |
4645 | - |
4646 | void tst_DirectionalDragArea::gettingTouchOwnershipMakesMouseAreaBehindGetCanceled() |
4647 | { |
4648 | DirectionalDragArea *edgeDragArea = |
4649 | m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4650 | QVERIFY(edgeDragArea != nullptr); |
4651 | - edgeDragArea->setRecognitionTimer(fakeTimer); |
4652 | - edgeDragArea->setTimeSource(fakeTimeSource); |
4653 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4654 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4655 | |
4656 | QQuickMouseArea *mouseArea = |
4657 | m_view->rootObject()->findChild<QQuickMouseArea*>("mouseArea"); |
4658 | @@ -1233,12 +976,12 @@ |
4659 | QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea); |
4660 | QPointF touchPoint = initialTouchPos; |
4661 | |
4662 | - qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2; |
4663 | + qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2; |
4664 | QPointF dragDirectionVector(1.0f, 0.0f); // rightwards |
4665 | - qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f; |
4666 | + qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f; |
4667 | QPointF touchMovement = dragDirectionVector * movementStepDistance; |
4668 | int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance); |
4669 | - int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps; |
4670 | + int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps; |
4671 | |
4672 | QCOMPARE(mouseArea->pressed(), false); |
4673 | |
4674 | @@ -1259,13 +1002,305 @@ |
4675 | // As the DirectionalDragArea recognizes the gesture, it grabs the touch from the MouseArea, |
4676 | // which should make the MouseArea get a cancelation event, which will then cause it to |
4677 | // reset its state (going back to "unpressed"/"released"). |
4678 | - QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); |
4679 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized); |
4680 | QCOMPARE(mouseArea->pressed(), false); |
4681 | QCOMPARE(mouseAreaSpy.canceledCount, 1); |
4682 | |
4683 | QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint()); |
4684 | } |
4685 | |
4686 | +void tst_DirectionalDragArea::interleavedTouches() |
4687 | +{ |
4688 | + DirectionalDragArea *edgeDragArea = |
4689 | + m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4690 | + QVERIFY(edgeDragArea != 0); |
4691 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4692 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4693 | + |
4694 | + QPointF touch0 = edgeDragArea->mapToScene( |
4695 | + QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.3)); |
4696 | + |
4697 | + qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2; |
4698 | + QPointF dragDirectionVector(1.0f, 0.0f); // rightwards |
4699 | + qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f; |
4700 | + QPointF touchMovement = dragDirectionVector * movementStepDistance; |
4701 | + int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance); |
4702 | + int movementTimeStepMs = (edgeDragArea->d->maxTime * 0.4f) / totalMovementSteps; |
4703 | + |
4704 | + QTest::touchEvent(m_view, m_device).press(0, touch0.toPoint()); |
4705 | + for (int i = 0; i < totalMovementSteps; ++i) { |
4706 | + touch0 += touchMovement; |
4707 | + passTime(movementTimeStepMs); |
4708 | + QTest::touchEvent(m_view, m_device).move(0, touch0.toPoint()); |
4709 | + } |
4710 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized); |
4711 | + |
4712 | + QPointF touch1 = edgeDragArea->mapToScene( |
4713 | + QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.6)); |
4714 | + |
4715 | + QTest::touchEvent(m_view, m_device) |
4716 | + .move(0, touch0.toPoint()) |
4717 | + .press(1, touch1.toPoint()); |
4718 | + |
4719 | + touch1 += touchMovement; |
4720 | + passTime(movementTimeStepMs); |
4721 | + QTest::touchEvent(m_view, m_device) |
4722 | + .move(0, touch0.toPoint()) |
4723 | + .move(1, touch1.toPoint()); |
4724 | + |
4725 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized); |
4726 | + |
4727 | + QTest::touchEvent(m_view, m_device) |
4728 | + .release(0, touch0.toPoint()) |
4729 | + .move(1, touch1.toPoint()); |
4730 | + |
4731 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4732 | + |
4733 | + touch1 += touchMovement; |
4734 | + passTime(movementTimeStepMs); |
4735 | + QTest::touchEvent(m_view, m_device) |
4736 | + .move(1, touch1.toPoint()); |
4737 | + |
4738 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4739 | + |
4740 | + QPointF touch2 = edgeDragArea->mapToScene( |
4741 | + QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.9)); |
4742 | + |
4743 | + passTime(edgeDragArea->d->compositionTime + movementTimeStepMs); |
4744 | + QTest::touchEvent(m_view, m_device) |
4745 | + .move(1, touch1.toPoint()) |
4746 | + .press(2, touch2.toPoint()); |
4747 | + |
4748 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided); |
4749 | + QCOMPARE(edgeDragArea->d->touchId, 2); |
4750 | + |
4751 | + touch2 += touchMovement; |
4752 | + passTime(movementTimeStepMs); |
4753 | + QTest::touchEvent(m_view, m_device) |
4754 | + .move(1, touch1.toPoint()) |
4755 | + .move(2, touch2.toPoint()); |
4756 | + |
4757 | + touch1 += touchMovement; |
4758 | + passTime(movementTimeStepMs); |
4759 | + QTest::touchEvent(m_view, m_device) |
4760 | + .move(1, touch1.toPoint()) |
4761 | + .move(2, touch2.toPoint()); |
4762 | + |
4763 | + passTime(movementTimeStepMs); |
4764 | + QTest::touchEvent(m_view, m_device) |
4765 | + .release(1, touch1.toPoint()) |
4766 | + .move(2, touch2.toPoint()); |
4767 | + |
4768 | + passTime(movementTimeStepMs); |
4769 | + QTest::touchEvent(m_view, m_device) |
4770 | + .release(2, touch2.toPoint()); |
4771 | + |
4772 | + QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch); |
4773 | +} |
4774 | + |
4775 | +/* |
4776 | + A valid right-edge drag performed on mako |
4777 | + */ |
4778 | +void tst_DirectionalDragArea::makoRightEdgeDrag() |
4779 | +{ |
4780 | + m_view->resize(768, 1280); |
4781 | + QTest::qWait(300); |
4782 | + |
4783 | + DirectionalDragArea *edgeDragArea = |
4784 | + m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea"); |
4785 | + QVERIFY(edgeDragArea != nullptr); |
4786 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4787 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4788 | + |
4789 | + StatusSpy *statusSpy = new StatusSpy(edgeDragArea); |
4790 | + |
4791 | + edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/); |
4792 | + |
4793 | + sendTouchPress(319744, 0, QPointF(767.001, 719.719)); |
4794 | + sendTouchUpdate(319765, 0, QPointF(765.744,729.973)); |
4795 | + sendTouchUpdate(319784, 0, QPointF(740.879,752.182)); |
4796 | + sendTouchUpdate(319803, 0, QPointF(689.698,795.795)); |
4797 | + sendTouchUpdate(319826, 0, QPointF(616.978,856.212)); |
4798 | + sendTouchUpdate(319845, 0, QPointF(558.769,906.157)); |
4799 | + sendTouchUpdate(319859, 0, QPointF(513.219,945.266)); |
4800 | + sendTouchUpdate(319878, 0, QPointF(481.31,975.496)); |
4801 | + sendTouchUpdate(319902, 0, QPointF(460.016,997.439)); |
4802 | + sendTouchUpdate(319920, 0, QPointF(449.761,1008.6)); |
4803 | + sendTouchUpdate(319929, 0, QPointF(445.891,1012.42)); |
4804 | + sendTouchUpdate(319947, 0, QPointF(444.884,1013.93)); |
4805 | + sendTouchUpdate(319965, 0, QPointF(444.461,1014.35)); |
4806 | + sendTouchUpdate(320057, 0, QPointF(444.71,1013.56)); |
4807 | + sendTouchUpdate(320138, 0, QPointF(445.434,1013.6)); |
4808 | + sendTouchUpdate(320154, 0, QPointF(446.338,1012.98)); |
4809 | + sendTouchUpdate(320171, 0, QPointF(447.232,1012.08)); |
4810 | + sendTouchRelease(320171, 0, QPointF(447.232,1012.08)); |
4811 | + |
4812 | + QCOMPARE(statusSpy->recognized(), true); |
4813 | + |
4814 | + delete statusSpy; |
4815 | +} |
4816 | + |
4817 | +/* |
4818 | + A vertical, downwards swipe performed on mako near its right edge. |
4819 | + |
4820 | + The DirectionalDragArea on the right edge must not recognize this |
4821 | + gesture. |
4822 | + */ |
4823 | +void tst_DirectionalDragArea::makoRightEdgeDrag_verticalDownwards() |
4824 | +{ |
4825 | + m_view->resize(768, 1280); |
4826 | + QTest::qWait(300); |
4827 | + |
4828 | + DirectionalDragArea *edgeDragArea = |
4829 | + m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea"); |
4830 | + QVERIFY(edgeDragArea != nullptr); |
4831 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4832 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4833 | + |
4834 | + edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/); |
4835 | + |
4836 | + StatusSpy *statusSpy = new StatusSpy(edgeDragArea); |
4837 | + |
4838 | + sendTouchPress(12012445, 26, QPointF(767.001,461.82)); |
4839 | + sendTouchUpdate(12012472, 26, QPointF(767.001,462.569)); |
4840 | + sendTouchUpdate(12012528, 26, QPointF(767.001,463.334)); |
4841 | + sendTouchUpdate(12012546, 26, QPointF(767.001,466.856)); |
4842 | + sendTouchUpdate(12012571, 26, QPointF(767.001,473.291)); |
4843 | + sendTouchUpdate(12012587, 26, QPointF(767.001,487.31)); |
4844 | + sendTouchUpdate(12012604, 26, QPointF(765.364,507.521)); |
4845 | + sendTouchUpdate(12012618, 26, QPointF(765.364,507.521)); |
4846 | + sendTouchUpdate(12012627, 26, QPointF(762.642,534.317)); |
4847 | + sendTouchUpdate(12012655, 26, QPointF(760.846,573.406)); |
4848 | + sendTouchUpdate(12012667, 26, QPointF(759.838,625.295)); |
4849 | + sendTouchUpdate(12012675, 26, QPointF(758.875,703.207)); |
4850 | + sendTouchUpdate(12012696, 26, QPointF(761.52,777.015)); |
4851 | + sendTouchUpdate(12012713, 26, QPointF(765.659,835.591)); |
4852 | + sendTouchUpdate(12012731, 26, QPointF(766.778,883.206)); |
4853 | + sendTouchUpdate(12012748, 26, QPointF(767.001,922.937)); |
4854 | + sendTouchUpdate(12012779, 26, QPointF(767.001,967.558)); |
4855 | + sendTouchUpdate(12012798, 26, QPointF(767.001,1006.12)); |
4856 | + sendTouchUpdate(12012809, 26, QPointF(767.001,1033.1)); |
4857 | + sendTouchRelease(12012810, 26, QPointF(767.001,1033.1)); |
4858 | + |
4859 | + QCOMPARE(statusSpy->recognized(), false); |
4860 | + |
4861 | + delete statusSpy; |
4862 | +} |
4863 | + |
4864 | +/* |
4865 | + A valid left-edge drag performed on mako. This one starts a bit slow than speeds up |
4866 | + */ |
4867 | +void tst_DirectionalDragArea::makoLeftEdgeDrag_slowStart() |
4868 | +{ |
4869 | + m_view->resize(768, 1280); |
4870 | + QTest::qWait(300); |
4871 | + |
4872 | + DirectionalDragArea *edgeDragArea = |
4873 | + m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4874 | + QVERIFY(edgeDragArea != nullptr); |
4875 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4876 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4877 | + |
4878 | + edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/); |
4879 | + |
4880 | + StatusSpy *statusSpy = new StatusSpy(edgeDragArea); |
4881 | + |
4882 | + sendTouchPress(4002267, 77, QPointF(0,885.154)); |
4883 | + sendTouchUpdate(4002275, 77, QPointF(0,886.214)); |
4884 | + sendTouchUpdate(4002311, 77, QPointF(1.09568,887.75)); |
4885 | + sendTouchUpdate(4002329, 77, QPointF(3.53647,890.191)); |
4886 | + sendTouchUpdate(4002347, 77, QPointF(7.87434,892.879)); |
4887 | + sendTouchUpdate(4002366, 77, QPointF(12.3036,895.075)); |
4888 | + sendTouchUpdate(4002384, 77, QPointF(15.8885,896.849)); |
4889 | + sendTouchUpdate(4002406, 77, QPointF(18.4504,897.88)); |
4890 | + sendTouchUpdate(4002420, 77, QPointF(20.2429,898.149)); |
4891 | + sendTouchUpdate(4002439, 77, QPointF(20.9945,898.149)); |
4892 | + sendTouchUpdate(4002457, 77, QPointF(21.8819,898.149)); |
4893 | + sendTouchUpdate(4002480, 77, QPointF(22.7454,897.389)); |
4894 | + sendTouchUpdate(4002493, 77, QPointF(23.5456,896.589)); |
4895 | + sendTouchUpdate(4002511, 77, QPointF(24.5435,895.031)); |
4896 | + sendTouchUpdate(4002529, 77, QPointF(25.4271,892.32)); |
4897 | + sendTouchUpdate(4002548, 77, QPointF(26.3145,889.658)); |
4898 | + sendTouchUpdate(4002566, 77, QPointF(27.2004,886.999)); |
4899 | + sendTouchUpdate(4002584, 77, QPointF(28.035,885.048)); |
4900 | + sendTouchUpdate(4002603, 77, QPointF(29.9684,883.167)); |
4901 | + sendTouchUpdate(4002620, 77, QPointF(33.3591,881.403)); |
4902 | + sendTouchUpdate(4002639, 77, QPointF(44.1017,879.642)); |
4903 | + sendTouchUpdate(4002657, 77, QPointF(64.828,878.502)); |
4904 | + sendTouchUpdate(4002675, 77, QPointF(87.9486,878.157)); |
4905 | + sendTouchUpdate(4002693, 77, QPointF(112.96,877.742)); |
4906 | + sendTouchUpdate(4002711, 77, QPointF(138.903,877.157)); |
4907 | + sendTouchUpdate(4002729, 77, QPointF(163.204,877.157)); |
4908 | + sendTouchUpdate(4002747, 77, QPointF(182.127,877.157)); |
4909 | + sendTouchUpdate(4002765, 77, QPointF(194.478,877.657)); |
4910 | + sendTouchUpdate(4002785, 77, QPointF(201.474,878.508)); |
4911 | + sendTouchUpdate(4002803, 77, QPointF(204.855,879.401)); |
4912 | + sendTouchUpdate(4002822, 77, QPointF(206.616,880.281)); |
4913 | + sendTouchUpdate(4002839, 77, QPointF(207.115,880.906)); |
4914 | + sendTouchUpdate(4002894, 77, QPointF(206.865,881.184)); |
4915 | + sendTouchUpdate(4002912, 77, QPointF(206.865,882.143)); |
4916 | + sendTouchUpdate(4002930, 77, QPointF(206.865,883.106)); |
4917 | + sendTouchUpdate(4002949, 77, QPointF(206.526,883.994)); |
4918 | + sendTouchUpdate(4002967, 77, QPointF(205.866,884.88)); |
4919 | + sendTouchUpdate(4002985, 77, QPointF(205.866,885.766)); |
4920 | + sendTouchUpdate(4003005, 77, QPointF(205.866,886.654)); |
4921 | + sendTouchUpdate(4003021, 77, QPointF(205.366,887.537)); |
4922 | + sendTouchUpdate(4003039, 77, QPointF(204.592,888.428)); |
4923 | + sendTouchUpdate(4003050, 77, QPointF(204.367,888.653)); |
4924 | + sendTouchRelease(4003050, 77, QPointF(204.367,888.653)); |
4925 | + |
4926 | + QCOMPARE(statusSpy->recognized(), true); |
4927 | + |
4928 | + delete statusSpy; |
4929 | +} |
4930 | + |
4931 | +void tst_DirectionalDragArea::makoLeftEdgeDrag_movesSlightlyBackwardsOnStart() |
4932 | +{ |
4933 | + m_view->resize(768, 1280); |
4934 | + QTest::qWait(300); |
4935 | + |
4936 | + DirectionalDragArea *edgeDragArea = |
4937 | + m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); |
4938 | + QVERIFY(edgeDragArea != nullptr); |
4939 | + edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer()); |
4940 | + edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource()); |
4941 | + |
4942 | + edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/); |
4943 | + |
4944 | + StatusSpy *statusSpy = new StatusSpy(edgeDragArea); |
4945 | + |
4946 | + sendTouchPress(41097, 24, QPointF(13.9909,827.177)); |
4947 | + sendTouchUpdate(41120, 24, QPointF(19.2375,825.677)); |
4948 | + sendTouchUpdate(41138, 24, QPointF(18.4057,826.177)); |
4949 | + sendTouchUpdate(41161, 24, QPointF(20.1067,825.867)); |
4950 | + sendTouchUpdate(41177, 24, QPointF(21.8869,824.977)); |
4951 | + sendTouchUpdate(41193, 24, QPointF(24.7603,823.494)); |
4952 | + sendTouchUpdate(41211, 24, QPointF(28.3889,821.725)); |
4953 | + sendTouchUpdate(41229, 24, QPointF(32.2909,819.955)); |
4954 | + sendTouchUpdate(41247, 24, QPointF(38.2251,817.431)); |
4955 | + sendTouchUpdate(41266, 24, QPointF(52.4182,814.223)); |
4956 | + sendTouchUpdate(41284, 24, QPointF(85.8465,809.483)); |
4957 | + sendTouchUpdate(41302, 24, QPointF(126.091,802.741)); |
4958 | + sendTouchUpdate(41320, 24, QPointF(153.171,797.977)); |
4959 | + sendTouchUpdate(41338, 24, QPointF(170.565,795.077)); |
4960 | + sendTouchUpdate(41356, 24, QPointF(178.685,794.101)); |
4961 | + sendTouchUpdate(41375, 24, QPointF(183.706,793.225)); |
4962 | + sendTouchUpdate(41393, 24, QPointF(186.112,793.19)); |
4963 | + sendTouchUpdate(41411, 24, QPointF(187.634,793.19)); |
4964 | + sendTouchUpdate(41429, 24, QPointF(188.505,793.19)); |
4965 | + sendTouchUpdate(41532, 24, QPointF(187.816,793.19)); |
4966 | + sendTouchUpdate(41538, 24, QPointF(186.902,793.19)); |
4967 | + sendTouchUpdate(41557, 24, QPointF(186.01,793.19)); |
4968 | + sendTouchUpdate(41575, 24, QPointF(185.125,793.444)); |
4969 | + sendTouchUpdate(41593, 24, QPointF(184.229,793.69)); |
4970 | + sendTouchUpdate(41605, 24, QPointF(183.88,793.69)); |
4971 | + sendTouchRelease(41607, 24, QPointF(183.88,793.69)); |
4972 | + |
4973 | + QCOMPARE(statusSpy->recognized(), true); |
4974 | + |
4975 | + delete statusSpy; |
4976 | +} |
4977 | + |
4978 | QTEST_MAIN(tst_DirectionalDragArea) |
4979 | |
4980 | #include "tst_DirectionalDragArea.moc" |
4981 | |
4982 | === modified file 'tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml' |
4983 | --- tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml 2014-10-07 13:02:29 +0000 |
4984 | +++ tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml 2015-04-10 21:17:56 +0000 |
4985 | @@ -1,5 +1,5 @@ |
4986 | /* |
4987 | - * Copyright (C) 2013 Canonical, Ltd. |
4988 | + * Copyright (C) 2013,2015 Canonical, Ltd. |
4989 | * |
4990 | * This program is free software; you can redistribute it and/or modify |
4991 | * it under the terms of the GNU General Public License as published by |
4992 | @@ -16,12 +16,19 @@ |
4993 | |
4994 | import QtQuick 2.0 |
4995 | import Ubuntu.Components 0.1 |
4996 | +import Unity.Test 0.1 |
4997 | |
4998 | Rectangle { |
4999 | width: units.gu(60) |
5000 | height: units.gu(60) |
FAILED: Continuous integration, rev:1705 jenkins. qa.ubuntu. com/job/ unity8- ci/5511/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 2090/console jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- vivid/674/ console jenkins. qa.ubuntu. com/job/ unity8- vivid-amd64- ci/676/ console jenkins. qa.ubuntu. com/job/ unity8- vivid-i386- ci/676/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 2088/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/5511/ rebuild
http://