~osomon/webbrowser-app/maxCacheSizeHint

« back to all changes in this revision

Viewing changes to src/app/unity8/plugins/Ubuntu/Gestures/DirectionalDragArea.h

  • Committer: Olivier Tilloy
  • Date: 2015-04-08 15:29:44 UTC
  • mfrom: (930.1.25 webbrowser-app)
  • Revision ID: olivier.tilloy@canonical.com-20150408152944-zg7hpedldixspgf7
Merge the latest changes from trunk and resolve a conflict.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2013,2014 Canonical, Ltd.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; version 3.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 */
 
16
 
 
17
#ifndef DIRECTIONAL_DRAG_AREA_H
 
18
#define DIRECTIONAL_DRAG_AREA_H
 
19
 
 
20
#include <QtQuick/QQuickItem>
 
21
#include "AxisVelocityCalculator.h"
 
22
#include "UbuntuGesturesQmlGlobal.h"
 
23
#include "Damper.h"
 
24
#include "Direction.h"
 
25
 
 
26
// lib UbuntuGestures
 
27
#include <Pool.h>
 
28
#include <Timer.h>
 
29
 
 
30
class TouchOwnershipEvent;
 
31
class UnownedTouchEvent;
 
32
 
 
33
/*
 
34
 An area that detects axis-aligned single-finger drag gestures
 
35
 
 
36
 If a drag deviates too much from the components' direction recognition will
 
37
 fail. It will also fail if the drag or flick is too short. E.g. a noisy or
 
38
 fidgety click
 
39
 
 
40
 See doc/DirectionalDragArea.svg
 
41
 */
 
42
class UBUNTUGESTURESQML_EXPORT DirectionalDragArea : public QQuickItem {
 
43
    Q_OBJECT
 
44
 
 
45
    // The direction in which the gesture should move in order to be recognized.
 
46
    Q_PROPERTY(Direction::Type direction READ direction WRITE setDirection NOTIFY directionChanged)
 
47
 
 
48
    // The distance travelled by the finger along the axis specified by
 
49
    // DirectionalDragArea's direction.
 
50
    Q_PROPERTY(qreal distance READ distance NOTIFY distanceChanged)
 
51
 
 
52
    // The distance travelled by the finger along the axis specified by
 
53
    // DirectionalDragArea's direction in scene coordinates
 
54
    Q_PROPERTY(qreal sceneDistance READ sceneDistance NOTIFY sceneDistanceChanged)
 
55
 
 
56
    // Position of the touch point performing the drag relative to this item.
 
57
    Q_PROPERTY(qreal touchX READ touchX NOTIFY touchXChanged)
 
58
    Q_PROPERTY(qreal touchY READ touchY NOTIFY touchYChanged)
 
59
 
 
60
    // Position of the touch point performing the drag, in scene's coordinate system
 
61
    Q_PROPERTY(qreal touchSceneX READ touchSceneX NOTIFY touchSceneXChanged)
 
62
    Q_PROPERTY(qreal touchSceneY READ touchSceneY NOTIFY touchSceneYChanged)
 
63
 
 
64
    // The current status of the directional drag gesture area.
 
65
    Q_PROPERTY(Status status READ status NOTIFY statusChanged)
 
66
 
 
67
    // Whether a drag gesture is taking place
 
68
    // This will be true as long as status is Undecided or Recognized
 
69
    // When a gesture gets rejected, dragging turns to false.
 
70
    Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
 
71
 
 
72
    /////
 
73
    // stuff that will be set in stone at some point
 
74
 
 
75
    // How far the touch point can move away from its expected position before
 
76
    // it causes a rejection in the gesture recognition. This is to compensate
 
77
    // for both noise in the touch input signal and for the natural irregularities
 
78
    // in the finger movement.
 
79
    // Proper value is likely device-specific.
 
80
    Q_PROPERTY(qreal maxDeviation READ maxDeviation WRITE setMaxDeviation NOTIFY maxDeviationChanged)
 
81
 
 
82
    // Widening angle, in degrees
 
83
    // It's roughly the maximum angle a touch point can make relative to the
 
84
    // axis defined by the compoment's direction for it to be recognized as a
 
85
    // directional drag.
 
86
    Q_PROPERTY(qreal wideningAngle READ wideningAngle WRITE setWideningAngle
 
87
               NOTIFY wideningAngleChanged)
 
88
 
 
89
    // How far a touch point has to move from its initial position in order for
 
90
    // it to be recognized as a directional drag.
 
91
    Q_PROPERTY(qreal distanceThreshold READ distanceThreshold WRITE setDistanceThreshold
 
92
               NOTIFY distanceThresholdChanged)
 
93
 
 
94
    // Minimum speed a gesture needs to have in order to be recognized as a
 
95
    // directional drag.
 
96
    // In pixels per second
 
97
    Q_PROPERTY(qreal minSpeed READ minSpeed WRITE setMinSpeed NOTIFY minSpeedChanged)
 
98
 
 
99
    // A gesture will be rejected if more than maxSilenceTime milliseconds has
 
100
    // passed since we last got an input event from it (during Undecided state).
 
101
    //
 
102
    // Silence (i.e., lack of new input events) doesn't necessarily mean that the user's
 
103
    // finger is still (zero drag speed). In some cases the finger might be moving but
 
104
    // the driver's high noise filtering might cause those silence periods, specially
 
105
    // in the moments succeeding a press (talking about Galaxy Nexus here).
 
106
    Q_PROPERTY(int maxSilenceTime READ maxSilenceTime
 
107
                                  WRITE setMaxSilenceTime
 
108
                                  NOTIFY maxSilenceTimeChanged)
 
109
 
 
110
    //
 
111
    /////
 
112
 
 
113
    // Maximum time (in milliseconds) after the start of a given touch point where
 
114
    // subsequent touch starts are grouped with the first one into an N-touches gesture
 
115
    // (e.g. a two-fingers tap or drag).
 
116
    Q_PROPERTY(int compositionTime READ compositionTime
 
117
                                   WRITE setCompositionTime
 
118
                                   NOTIFY compositionTimeChanged)
 
119
 
 
120
    Q_ENUMS(Direction)
 
121
    Q_ENUMS(Status)
 
122
public:
 
123
    DirectionalDragArea(QQuickItem *parent = 0);
 
124
 
 
125
    Direction::Type direction() const;
 
126
    void setDirection(Direction::Type);
 
127
 
 
128
    // Describes the state of the directional drag gesture.
 
129
    enum Status {
 
130
        // Waiting for a new touch point to land on this area. No gesture is being processed
 
131
        // or tracked.
 
132
        WaitingForTouch,
 
133
 
 
134
        // A touch point has landed on this area but it's not know yet whether it is
 
135
        // performing a drag in the correct direction.
 
136
        // If it's decided that the touch point is not performing a directional drag gesture,
 
137
        // it will be rejected/ignored and status will return to WaitingForTouch.
 
138
        Undecided, //Recognizing,
 
139
 
 
140
        // There's a touch point in this area and it performed a drag in the correct
 
141
        // direction.
 
142
        //
 
143
        // Once recognized, the gesture state will move back to WaitingForTouch only once
 
144
        // that touch point ends. The gesture will remain in the Recognized state even if
 
145
        // the touch point starts moving in other directions or halts.
 
146
        Recognized,
 
147
    };
 
148
    Status status() const { return m_status; }
 
149
 
 
150
    qreal distance() const;
 
151
    qreal sceneDistance() const;
 
152
    void updateSceneDistance();
 
153
 
 
154
    qreal touchX() const;
 
155
    qreal touchY() const;
 
156
 
 
157
    qreal touchSceneX() const;
 
158
    qreal touchSceneY() const;
 
159
 
 
160
    bool dragging() const { return (m_status == Undecided) || (m_status == Recognized); }
 
161
 
 
162
    qreal maxDeviation() const { return m_dampedScenePos.maxDelta(); }
 
163
    void setMaxDeviation(qreal value);
 
164
 
 
165
    qreal wideningAngle() const;
 
166
    void setWideningAngle(qreal value);
 
167
 
 
168
    qreal distanceThreshold() const { return m_distanceThreshold; }
 
169
    void setDistanceThreshold(qreal value);
 
170
 
 
171
    qreal minSpeed() const { return m_minSpeed; }
 
172
    void setMinSpeed(qreal value);
 
173
 
 
174
    int maxSilenceTime() const { return m_maxSilenceTime; }
 
175
    void setMaxSilenceTime(int value);
 
176
 
 
177
    int compositionTime() const { return m_compositionTime; }
 
178
    void setCompositionTime(int value);
 
179
 
 
180
    // Replaces the existing Timer with the given one.
 
181
    //
 
182
    // Useful for providing a fake timer when testing.
 
183
    void setRecognitionTimer(UbuntuGestures::AbstractTimer *timer);
 
184
 
 
185
    // Useful for testing, where a fake time source can be supplied
 
186
    void setTimeSource(const UbuntuGestures::SharedTimeSource &timeSource);
 
187
 
 
188
    bool event(QEvent *e) override;
 
189
 
 
190
    // Maximum time, in milliseconds, between a press and a release, for a touch
 
191
    // sequence to be considered a tap.
 
192
    int maxTapDuration() const { return 300; }
 
193
 
 
194
Q_SIGNALS:
 
195
    void directionChanged(Direction::Type direction);
 
196
    void statusChanged(Status value);
 
197
    void draggingChanged(bool value);
 
198
    void distanceChanged(qreal value);
 
199
    void sceneDistanceChanged(qreal value);
 
200
    void maxDeviationChanged(qreal value);
 
201
    void wideningAngleChanged(qreal value);
 
202
    void distanceThresholdChanged(qreal value);
 
203
    void minSpeedChanged(qreal value);
 
204
    void maxSilenceTimeChanged(int value);
 
205
    void compositionTimeChanged(int value);
 
206
    void touchXChanged(qreal value);
 
207
    void touchYChanged(qreal value);
 
208
    void touchSceneXChanged(qreal value);
 
209
    void touchSceneYChanged(qreal value);
 
210
 
 
211
    // TODO: I would rather not have such signal as it has nothing to do with drag gestures.
 
212
    // Remove when no longer used or move its implementation to the QML code that uses it
 
213
    // See maxTapDuration()
 
214
    void tapped();
 
215
 
 
216
protected:
 
217
    virtual void touchEvent(QTouchEvent *event);
 
218
 
 
219
private Q_SLOTS:
 
220
    void checkSpeed();
 
221
    void giveUpIfDisabledOrInvisible();
 
222
 
 
223
private:
 
224
    void touchEvent_absent(QTouchEvent *event);
 
225
    void touchEvent_undecided(QTouchEvent *event);
 
226
    void touchEvent_recognized(QTouchEvent *event);
 
227
    bool pointInsideAllowedArea() const;
 
228
    bool movingInRightDirection() const;
 
229
    bool movedFarEnough(const QPointF &point) const;
 
230
    const QTouchEvent::TouchPoint *fetchTargetTouchPoint(QTouchEvent *event);
 
231
    void setStatus(Status newStatus);
 
232
    void setPreviousPos(const QPointF &point);
 
233
    void setPreviousScenePos(const QPointF &point);
 
234
    void updateVelocityCalculator(const QPointF &point);
 
235
    bool isWithinTouchCompositionWindow();
 
236
    void updateSceneDirectionVector();
 
237
    // returns the scalar projection between the given vector (in scene coordinates)
 
238
    // and m_sceneDirectionVector
 
239
    qreal projectOntoDirectionVector(const QPointF &sceneVector) const;
 
240
    void touchOwnershipEvent(TouchOwnershipEvent *event);
 
241
    void unownedTouchEvent(UnownedTouchEvent *event);
 
242
    void unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent);
 
243
    void watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints);
 
244
    bool recognitionIsDisabled() const;
 
245
    void emitSignalIfTapped();
 
246
 
 
247
    Status m_status;
 
248
 
 
249
    QPointF m_startPos;
 
250
    QPointF m_startScenePos;
 
251
    QPointF m_previousPos;
 
252
    QPointF m_previousScenePos;
 
253
    qreal m_sceneDistance;
 
254
    int m_touchId;
 
255
 
 
256
    // A movement damper is used in some of the gesture recognition calculations
 
257
    // to get rid of noise or small oscillations in the touch position.
 
258
    DampedPointF m_dampedScenePos;
 
259
    QPointF m_previousDampedScenePos;
 
260
 
 
261
    // Unit vector in scene coordinates describing the direction of the gesture recognition
 
262
    QPointF m_sceneDirectionVector;
 
263
 
 
264
    Direction::Type m_direction;
 
265
    qreal m_wideningAngle; // in degrees
 
266
    qreal m_wideningFactor; // it's pow(cosine(m_wideningAngle), 2)
 
267
    qreal m_distanceThreshold;
 
268
    qreal m_distanceThresholdSquared; // it's pow(m_distanceThreshold, 2)
 
269
    qreal m_minSpeed;
 
270
    int m_maxSilenceTime; // in milliseconds
 
271
    int m_silenceTime; // in milliseconds
 
272
    int m_compositionTime; // in milliseconds
 
273
    int m_numSamplesOnLastSpeedCheck;
 
274
    UbuntuGestures::AbstractTimer *m_recognitionTimer;
 
275
    AxisVelocityCalculator *m_velocityCalculator;
 
276
 
 
277
    UbuntuGestures::SharedTimeSource m_timeSource;
 
278
 
 
279
    // Information about an active touch point
 
280
    struct ActiveTouchInfo {
 
281
        ActiveTouchInfo() : id(-1), startTime(-1) {}
 
282
        bool isValid() const { return id != -1; }
 
283
        void reset() { id = -1; }
 
284
        int id;
 
285
        qint64 startTime;
 
286
    };
 
287
    class ActiveTouchesInfo {
 
288
    public:
 
289
        ActiveTouchesInfo(const UbuntuGestures::SharedTimeSource &timeSource);
 
290
        void update(QTouchEvent *event);
 
291
        qint64 touchStartTime(int id);
 
292
        bool isEmpty() const { return m_touchInfoPool.isEmpty(); }
 
293
        qint64 mostRecentStartTime();
 
294
        UbuntuGestures::SharedTimeSource m_timeSource;
 
295
    private:
 
296
        void addTouchPoint(int touchId);
 
297
        void removeTouchPoint(int touchId);
 
298
        #if ACTIVETOUCHESINFO_DEBUG
 
299
        QString toString();
 
300
        #endif
 
301
 
 
302
        Pool<ActiveTouchInfo> m_touchInfoPool;
 
303
    } m_activeTouches;
 
304
 
 
305
    friend class tst_DirectionalDragArea;
 
306
};
 
307
 
 
308
#endif // DIRECTIONAL_DRAG_AREA_H