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