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 // lib UbuntuGestures
25 #include <Timer.h>
26 
27 class TouchOwnershipEvent;
28 class UnownedTouchEvent;
29 
30 class 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)
38 public:
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 
91 Q_SIGNALS:
92  void idChanged();
93  void pressedChanged();
94  void xChanged();
95  void yChanged();
96  void draggingChanged();
97 
98 private:
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 contstrained by a minimim and/or maximum number of touch points.
110  This components 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  */
114 class UBUNTUGESTURESQML_EXPORT TouchGestureArea : public QQuickItem
115 {
116  Q_OBJECT
117  Q_ENUMS(Status)
118 
119  Q_PROPERTY(int status READ status NOTIFY statusChanged)
120  Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
121  Q_PROPERTY(QQmlListProperty<GestureTouchPoint> touchPoints READ touchPoints NOTIFY touchPointsUpdated)
122 
123  Q_PROPERTY(int minimumTouchPoints READ minimumTouchPoints WRITE setMinimumTouchPoints NOTIFY minimumTouchPointsChanged)
124  Q_PROPERTY(int maximumTouchPoints READ maximumTouchPoints WRITE setMaximumTouchPoints NOTIFY maximumTouchPointsChanged)
125 
126  // Time(ms) the component will wait for after receiving an initial touch to recognise a gesutre before rejecting it.
127  Q_PROPERTY(int recognitionPeriod READ recognitionPeriod WRITE setRecognitionPeriod NOTIFY recognitionPeriodChanged)
128  // Time(ms) the component will allow a recognised gesture to intermitently release a touch point before rejecting the gesture.
129  // This is so we will not immediately reject a gesture if there are fleeting touch point releases while dragging.
130  Q_PROPERTY(int releaseRejectPeriod READ releaseRejectPeriod WRITE setReleaseRejectPeriod NOTIFY releaseRejectPeriodChanged)
131 
132 public:
133  // Describes the state of the touch gesture area.
134  enum Status {
135  WaitingForTouch,
136  Undecided,
137  Recognized,
138  Rejected
139  };
140  TouchGestureArea(QQuickItem* parent = NULL);
141  ~TouchGestureArea();
142 
143  bool event(QEvent *e) override;
144 
145  void setRecognitionTimer(UbuntuGestures::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 
163 Q_SIGNALS:
164  void statusChanged(int status);
165 
166  void touchPointsUpdated();
167  void draggingChanged(bool dragging);
168  void minimumTouchPointsChanged(bool value);
169  void maximumTouchPointsChanged(bool value);
170  void recognitionPeriodChanged(bool value);
171  void releaseRejectPeriodChanged(bool 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 
178 protected:
179  void itemChange(ItemChange change, const ItemChangeData &value);
180 
181 private Q_SLOTS:
182  void rejectGesture();
183 
184 private:
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(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  UbuntuGestures::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 
227 QML_DECLARE_TYPE(GestureTouchPoint)
228 
229 #endif // TOUCHGESTUREAREA_H