Lomiri
Loading...
Searching...
No Matches
TouchGestureArea.h
1/*
2 * Copyright (C) 2016 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 TOUCHGESTUREAREA_H
18#define TOUCHGESTUREAREA_H
19
20#include "LomiriGesturesQmlGlobal.h"
21
22#include <QQuickItem>
23
24#include <LomiriGestures/lomirigesturesglobal.h>
25#include <LomiriGestures/private/timer_p.h>
26
27UG_FORWARD_DECLARE_CLASS(TouchOwnershipEvent)
28UG_FORWARD_DECLARE_CLASS(UnownedTouchEvent)
29
30class GestureTouchPoint : public QObject
31{
32 Q_OBJECT
33 Q_PROPERTY(int id READ id NOTIFY idChanged)
34 Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
35 Q_PROPERTY(qreal x READ x NOTIFY xChanged)
36 Q_PROPERTY(qreal y READ y NOTIFY yChanged)
37 Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
38public:
39 GestureTouchPoint()
40 : m_id(-1)
41 , m_pressed(false)
42 , m_x(0)
43 , m_y(0)
44 , m_dragging(false)
45 {
46 }
47
48 GestureTouchPoint(const GestureTouchPoint& other)
49 : QObject(nullptr)
50 {
51 operator=(other);
52 }
53
54 int id() const { return m_id; }
55 void setId(int id);
56
57 bool pressed() const { return m_pressed; }
58 void setPressed(bool pressed);
59
60 qreal x() const { return m_x; }
61 void setX(qreal x);
62
63 qreal y() const { return m_y; }
64 void setY(qreal y);
65
66 bool dragging() const { return m_dragging; }
67 void setDragging(bool dragging);
68
69 GestureTouchPoint& operator=(const GestureTouchPoint& rhs) {
70 if (&rhs == this) return *this;
71 m_id = rhs.m_id;
72 m_pressed = rhs.m_pressed;
73 m_x = rhs.m_x;
74 m_y = rhs.m_y;
75 m_dragging = rhs.m_dragging;
76 return *this;
77 }
78
79 bool operator==(const GestureTouchPoint& rhs) const {
80 if (&rhs == this) return true;
81 return m_id == rhs.m_id &&
82 m_pressed == rhs.m_pressed &&
83 m_x == rhs.m_x &&
84 m_y == rhs.m_y &&
85 m_dragging == rhs.m_dragging;
86 }
87 bool operator!=(const GestureTouchPoint& rhs) const { return !operator==(rhs); }
88
89 void setPos(const QPointF &pos);
90
91Q_SIGNALS:
92 void idChanged();
93 void pressedChanged();
94 void xChanged();
95 void yChanged();
96 void draggingChanged();
97
98private:
99 int m_id;
100 bool m_pressed;
101 qreal m_x;
102 qreal m_y;
103 bool m_dragging;
104};
105
106/*
107 An area that detects multi-finger gestures.
108
109 We can use this to detect gestures constrained by a minimum and/or maximum number of touch points.
110 This component uses the touch registry to apply for ownership of touch points.
111 This way we can use the component in conjuntion with the directional drag area to compete for ownwership
112 or gestures; unlike the MultiPointTouchArea.
113 */
114class LOMIRIGESTURESQML_EXPORT TouchGestureArea : public QQuickItem
115{
116 Q_OBJECT
117
118 Q_PROPERTY(int status READ status NOTIFY statusChanged)
119 Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
120 Q_PROPERTY(QQmlListProperty<GestureTouchPoint> touchPoints READ touchPoints NOTIFY touchPointsUpdated)
121
122 Q_PROPERTY(int minimumTouchPoints READ minimumTouchPoints WRITE setMinimumTouchPoints NOTIFY minimumTouchPointsChanged)
123 Q_PROPERTY(int maximumTouchPoints READ maximumTouchPoints WRITE setMaximumTouchPoints NOTIFY maximumTouchPointsChanged)
124
125 // Time(ms) the component will wait for after receiving an initial touch to recognise a gesutre before rejecting it.
126 Q_PROPERTY(int recognitionPeriod READ recognitionPeriod WRITE setRecognitionPeriod NOTIFY recognitionPeriodChanged)
127 // Time(ms) the component will allow a recognised gesture to intermitently release a touch point before rejecting the gesture.
128 // This is so we will not immediately reject a gesture if there are fleeting touch point releases while dragging.
129 Q_PROPERTY(int releaseRejectPeriod READ releaseRejectPeriod WRITE setReleaseRejectPeriod NOTIFY releaseRejectPeriodChanged)
130
131public:
132 // Describes the state of the touch gesture area.
133 enum Status {
134 WaitingForTouch,
135 Undecided,
136 Recognized,
137 Rejected
138 };
139 Q_ENUM(Status)
140 TouchGestureArea(QQuickItem* parent = nullptr);
141 ~TouchGestureArea();
142
143 bool event(QEvent *e) override;
144
145 void setRecognitionTimer(UG_PREPEND_NAMESPACE(AbstractTimer) *timer);
146
147 int status() const;
148 bool dragging() const;
149 QQmlListProperty<GestureTouchPoint> touchPoints();
150
151 int minimumTouchPoints() const;
152 void setMinimumTouchPoints(int value);
153
154 int maximumTouchPoints() const;
155 void setMaximumTouchPoints(int value);
156
157 int recognitionPeriod() const;
158 void setRecognitionPeriod(int value);
159
160 int releaseRejectPeriod() const;
161 void setReleaseRejectPeriod(int value);
162
163Q_SIGNALS:
164 void statusChanged(int status);
165
166 void touchPointsUpdated();
167 void draggingChanged(bool dragging);
168 void minimumTouchPointsChanged(int value);
169 void maximumTouchPointsChanged(int value);
170 void recognitionPeriodChanged(int value);
171 void releaseRejectPeriodChanged(int value);
172
173 void pressed(const QList<QObject*>& points);
174 void released(const QList<QObject*>& points);
175 void updated(const QList<QObject*>& points);
176 void clicked();
177
178protected:
179 void itemChange(ItemChange change, const ItemChangeData &value) override;
180
181private Q_SLOTS:
182 void rejectGesture();
183
184private:
185 void touchEvent(QTouchEvent *event) override;
186 void touchEvent_waitingForTouch(QTouchEvent *event);
187 void touchEvent_waitingForMoreTouches(QTouchEvent *event);
188 void touchEvent_waitingForOwnership(QTouchEvent *event);
189 void touchEvent_recognized(QTouchEvent *event);
190 void touchEvent_rejected(QTouchEvent *event);
191
192 void unownedTouchEvent(QTouchEvent *unownedTouchEvent);
193 void unownedTouchEvent_waitingForMoreTouches(QTouchEvent *unownedTouchEvent);
194 void unownedTouchEvent_waitingForOwnership(QTouchEvent *unownedTouchEvent);
195 void unownedTouchEvent_recognised(QTouchEvent *unownedTouchEvent);
196 void unownedTouchEvent_rejected(QTouchEvent *unownedTouchEvent);
197
198 void touchOwnershipEvent(UG_PREPEND_NAMESPACE(TouchOwnershipEvent) *event);
199 void updateTouchPoints(QTouchEvent *event);
200
201 GestureTouchPoint* addTouchPoint(const QTouchEvent::TouchPoint *tp);
202 void clearTouchLists();
203 void setDragging(bool dragging);
204 void setInternalStatus(uint status);
205 void resyncCachedTouchPoints();
206
207 static int touchPoint_count(QQmlListProperty<GestureTouchPoint> *list);
208 static GestureTouchPoint* touchPoint_at(QQmlListProperty<GestureTouchPoint> *list, int index);
209
210 uint m_status;
211 QSet<int> m_candidateTouches;
212 QSet<int> m_watchedTouches;
213 UG_PREPEND_NAMESPACE(AbstractTimer) *m_recognitionTimer;
214
215 bool m_dragging;
216 QHash<int, GestureTouchPoint*> m_liveTouchPoints;
217 QHash<int, GestureTouchPoint*> m_cachedTouchPoints;
218 QList<QObject*> m_releasedTouchPoints;
219 QList<QObject*> m_pressedTouchPoints;
220 QList<QObject*> m_movedTouchPoints;
221 int m_minimumTouchPoints;
222 int m_maximumTouchPoints;
223 int m_recognitionPeriod;
224 int m_releaseRejectPeriod;
225};
226
227QML_DECLARE_TYPE(GestureTouchPoint)
228
229#endif // TOUCHGESTUREAREA_H