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