|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * |
|
5 * This program is free software: you can redistribute it and/or modify |
|
6 * it under the terms of the GNU Lesser General Public License as published by |
|
7 * the Free Software Foundation, version 2.1 of the License. |
|
8 * |
|
9 * This program is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 * GNU Lesser General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU Lesser General Public License |
|
15 * along with this program. If not, |
|
16 * see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/". |
|
17 * |
|
18 * Description: |
|
19 * |
|
20 */ |
|
21 |
|
22 /* |
|
23 W A R N I N G |
|
24 ------------- |
|
25 THIS IS A TEMPORARY GESTURE CODE. WOULD BE REPLACED WHEN BROWSER HAS ITS OWN GESTURE FRAMEWORK |
|
26 */ |
|
27 |
|
28 #include "GestureRecognizer.h" |
|
29 |
|
30 #include "GestureListener.h" |
|
31 #include "GestureRecognizer_p.h" |
|
32 |
|
33 #include <QtGui> |
|
34 |
|
35 static const int DoubleClickFilterDuration = 300; |
|
36 static const int LongClickFilterDuration = 1000; |
|
37 static const int MinTimeHoldForClick = 50; |
|
38 static const int ThresholdForMove = 30; |
|
39 |
|
40 namespace GVA { |
|
41 |
|
42 GestureRecognizer::GestureRecognizer(GestureListener* gestureListener) |
|
43 : d_ptr(new GestureRecognizerPrivate(gestureListener)) |
|
44 { |
|
45 Q_D(GestureRecognizer); |
|
46 d->q_ptr = this; |
|
47 } |
|
48 |
|
49 GestureRecognizer::~GestureRecognizer() |
|
50 { } |
|
51 |
|
52 bool GestureRecognizer::mouseEventFilter(QGraphicsSceneMouseEvent* event) |
|
53 { |
|
54 Q_D(GestureRecognizer); |
|
55 bool handled = false; |
|
56 |
|
57 switch(event->type()) { |
|
58 case QEvent::GraphicsSceneMouseDoubleClick: |
|
59 handled = d->mouseDoubleClickEvent(event); |
|
60 break; |
|
61 case QEvent::GraphicsSceneMouseMove: |
|
62 handled = d->mouseMoveEvent(event); |
|
63 break; |
|
64 case QEvent::GraphicsSceneMousePress: |
|
65 handled = d->mousePressEvent(event); |
|
66 break; |
|
67 case QEvent::GraphicsSceneMouseRelease: |
|
68 handled = d->mouseReleaseEvent(event); |
|
69 break; |
|
70 case QEvent::GraphicsSceneContextMenu: |
|
71 //Swallow context menu event. |
|
72 //Since we have own way of handling it |
|
73 handled = true; |
|
74 default: |
|
75 break; |
|
76 } |
|
77 return handled; |
|
78 } |
|
79 |
|
80 qreal GestureRecognizer::dragInertia() const |
|
81 { |
|
82 Q_D(const GestureRecognizer); |
|
83 return d->m_dragInertia; |
|
84 } |
|
85 |
|
86 void GestureRecognizer::setDragInertia(qreal inertia) |
|
87 { |
|
88 Q_D(GestureRecognizer); |
|
89 d->m_dragInertia = inertia; |
|
90 } |
|
91 |
|
92 int GestureRecognizer::directionErrorMargin() const |
|
93 { |
|
94 Q_D(const GestureRecognizer); |
|
95 return d->m_directionErrorMargin; |
|
96 } |
|
97 |
|
98 void GestureRecognizer::setDirectionErrorMargin(int errorMargin) |
|
99 { |
|
100 Q_D(GestureRecognizer); |
|
101 d->m_directionErrorMargin = errorMargin; |
|
102 } |
|
103 |
|
104 qreal GestureRecognizer::axisLockThreshold() const |
|
105 { |
|
106 Q_D(const GestureRecognizer); |
|
107 return d->m_axisLockThreshold; |
|
108 } |
|
109 |
|
110 void GestureRecognizer::setAxisLockThreshold(qreal threshold) |
|
111 { |
|
112 Q_D(GestureRecognizer); |
|
113 d->m_axisLockThreshold = threshold; |
|
114 } |
|
115 |
|
116 qreal GestureRecognizer::maximumVelocity() const |
|
117 { |
|
118 Q_D(const GestureRecognizer); |
|
119 return d->m_maxVelocity; |
|
120 } |
|
121 |
|
122 void GestureRecognizer::setMaximumVelocity(qreal v) |
|
123 { |
|
124 Q_D(GestureRecognizer); |
|
125 d->m_maxVelocity = v; |
|
126 } |
|
127 |
|
128 qreal GestureRecognizer::minimumVelocity() const |
|
129 { |
|
130 Q_D(const GestureRecognizer); |
|
131 return d->m_minVelocity; |
|
132 } |
|
133 |
|
134 void GestureRecognizer::setMinimumVelocity(qreal v) |
|
135 { |
|
136 Q_D(GestureRecognizer); |
|
137 d->m_minVelocity = v; |
|
138 } |
|
139 |
|
140 int GestureRecognizer::panningThreshold() const |
|
141 { |
|
142 Q_D(const GestureRecognizer); |
|
143 return d->m_panningThreshold; |
|
144 } |
|
145 |
|
146 void GestureRecognizer::setPanningThreshold(int threshold) |
|
147 { |
|
148 Q_D(GestureRecognizer); |
|
149 d->m_panningThreshold = threshold; |
|
150 } |
|
151 |
|
152 qreal GestureRecognizer::fastVelocityFactor() const |
|
153 { |
|
154 Q_D(const GestureRecognizer); |
|
155 return d->m_fastVelocityFactor; |
|
156 } |
|
157 |
|
158 void GestureRecognizer::setFastVelocityFactor(qreal v) |
|
159 { |
|
160 Q_D(GestureRecognizer); |
|
161 d->m_fastVelocityFactor = v; |
|
162 } |
|
163 |
|
164 int GestureRecognizer::scrollsPerSecond() const |
|
165 { |
|
166 Q_D(const GestureRecognizer); |
|
167 return d->m_fastVelocityFactor; |
|
168 } |
|
169 |
|
170 void GestureRecognizer::setScrollsPerSecond(int sps) |
|
171 { |
|
172 Q_D(GestureRecognizer); |
|
173 d->m_scrollsPerSecond = sps; |
|
174 } |
|
175 |
|
176 // |
|
177 //GestureRecognizerPrivate DIFINITION |
|
178 // |
|
179 GestureRecognizerPrivate::GestureRecognizerPrivate(GestureListener* gestureListener) |
|
180 : m_gestureListener(gestureListener) |
|
181 , m_state(GestureRecognizerPrivate::Inactive) |
|
182 , m_dragInertia(0.85) |
|
183 , m_directionErrorMargin(10) |
|
184 , m_axisLockThreshold(0) |
|
185 , m_maxVelocity(3500) |
|
186 , m_minVelocity(10) |
|
187 , m_panningThreshold(25) |
|
188 , m_fastVelocityFactor(0.01) |
|
189 , m_scrollsPerSecond(20) |
|
190 , m_velocity(QPointF(0, 0)) |
|
191 , m_position(QPointF(-1, -1)) |
|
192 , m_initialPos(QPointF(-1, -1)) |
|
193 |
|
194 { } |
|
195 |
|
196 GestureRecognizerPrivate::~GestureRecognizerPrivate() |
|
197 { } |
|
198 |
|
199 bool GestureRecognizerPrivate::mousePressEvent(QGraphicsSceneMouseEvent* event) |
|
200 { |
|
201 if (event->button() != Qt::LeftButton) |
|
202 return false; |
|
203 |
|
204 if (m_state == GestureRecognizerPrivate::Inactive) { |
|
205 //First mouse press. |
|
206 m_position = event->scenePos(); |
|
207 m_initialPos = m_position; |
|
208 |
|
209 changeState(GestureRecognizerPrivate::Press); |
|
210 |
|
211 GestureEvent gesture = gestureEvent(m_initialPos, GestureEvent::Touch); |
|
212 m_gestureListener->handleGesture(&gesture); |
|
213 |
|
214 m_lastTime.start(); |
|
215 m_delayedPressMoment.start(); |
|
216 m_timer.start(LongClickFilterDuration, this); |
|
217 } else if(m_state == GestureRecognizerPrivate::Release) { |
|
218 //This press is for double tap. |
|
219 changeState(GestureRecognizerPrivate::DoublePress); |
|
220 } |
|
221 event->setAccepted(true); |
|
222 return true; |
|
223 } |
|
224 |
|
225 bool GestureRecognizerPrivate::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) |
|
226 { |
|
227 if (event->button() != Qt::LeftButton) |
|
228 return true; |
|
229 |
|
230 if (m_state == GestureRecognizerPrivate::Inactive) { |
|
231 //Release event cannot be generated in gesture recognizer is in active! |
|
232 event->setAccepted(true); |
|
233 resetTouchPositions(); |
|
234 return true; |
|
235 } |
|
236 |
|
237 if (m_state == GestureRecognizerPrivate::Press) { |
|
238 if (m_delayedPressMoment.elapsed() > MinTimeHoldForClick) { |
|
239 //Waiting for MinTimeHoldForClick to make sure use has actually pressed. |
|
240 //Removes accidentall press |
|
241 changeState(GestureRecognizerPrivate::Release); |
|
242 m_timer.start(DoubleClickFilterDuration, this); |
|
243 } else |
|
244 resetTouchPositions(); |
|
245 } else if (m_state == GestureRecognizerPrivate::Move) { |
|
246 if (qAbs(m_velocity.x()) > m_minVelocity |
|
247 || qAbs(m_velocity.y()) > m_minVelocity) { |
|
248 GestureEvent gesture = gestureEvent(m_position, GestureEvent::Flick); |
|
249 gesture.setVelocity(m_velocity); |
|
250 m_gestureListener->handleGesture(&gesture); |
|
251 } |
|
252 m_velocity = QPointF(0,0); |
|
253 resetTouchPositions(); |
|
254 } else if (m_state == GestureRecognizerPrivate::DoublePress) { |
|
255 //Stop double tap timer |
|
256 m_timer.stop(); |
|
257 GestureEvent gesture = gestureEvent(m_initialPos, GestureEvent::DoubleTap); |
|
258 m_gestureListener->handleGesture(&gesture); |
|
259 resetTouchPositions(); |
|
260 } |
|
261 event->setAccepted(true); |
|
262 return true; |
|
263 } |
|
264 |
|
265 bool GestureRecognizerPrivate::mouseMoveEvent(QGraphicsSceneMouseEvent* event) |
|
266 { |
|
267 QPoint delta; |
|
268 if (m_state == GestureRecognizerPrivate::Press) { |
|
269 delta = (event->scenePos() - m_initialPos).toPoint(); |
|
270 QPoint absDelta; |
|
271 absDelta.setX(qAbs(delta.x())); |
|
272 absDelta.setY(qAbs(delta.y())); |
|
273 |
|
274 if ((absDelta.x() > ThresholdForMove) || (absDelta.y() > ThresholdForMove)) { |
|
275 //Stop long tap timer |
|
276 m_timer.stop(); |
|
277 |
|
278 changeState(GestureRecognizerPrivate::Move); |
|
279 m_position = event->scenePos(); |
|
280 } else { |
|
281 //Ignore until user has actually moved |
|
282 return true; |
|
283 } |
|
284 } else if (m_state == GestureRecognizerPrivate::Move) { |
|
285 delta = (event->scenePos() - m_position).toPoint(); |
|
286 m_position = event->scenePos(); |
|
287 } else { |
|
288 resetTouchPositions(); |
|
289 return true; |
|
290 } |
|
291 |
|
292 //Aplly if axis stickiness is specified. |
|
293 if (m_axisLockThreshold) { |
|
294 int dx = qAbs(delta.x()); |
|
295 int dy = qAbs(delta.y()); |
|
296 |
|
297 if (dx || dy) { |
|
298 bool vertical = (dy > dx); |
|
299 qreal alpha = qreal(vertical ? dx : dy) / qreal(vertical ? dy : dx); |
|
300 if (alpha <= m_axisLockThreshold) { |
|
301 if (vertical) |
|
302 delta.setX(0); |
|
303 else |
|
304 delta.setY(0); |
|
305 } |
|
306 } |
|
307 } |
|
308 |
|
309 m_velocity = calculateVelocity(delta, m_lastTime.elapsed()); |
|
310 |
|
311 //Send pan gesture |
|
312 GestureEvent gesture = gestureEvent(m_position, GestureEvent::Pan); |
|
313 gesture.setDelta(delta); |
|
314 m_gestureListener->handleGesture(&gesture); |
|
315 m_lastTime.restart(); |
|
316 |
|
317 event->setAccepted(true); |
|
318 return true; |
|
319 } |
|
320 |
|
321 bool GestureRecognizerPrivate::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) |
|
322 { |
|
323 if (m_state == GestureRecognizerPrivate::Release) { |
|
324 m_timer.stop(); |
|
325 GestureEvent gesture = gestureEvent(m_initialPos, GestureEvent::DoubleTap); |
|
326 m_gestureListener->handleGesture(&gesture); |
|
327 } |
|
328 resetTouchPositions(); |
|
329 event->setAccepted(true); |
|
330 return true; |
|
331 } |
|
332 |
|
333 void GestureRecognizerPrivate::changeState(GestureRecognizerPrivate::State state) |
|
334 { |
|
335 m_state = state; |
|
336 } |
|
337 |
|
338 GestureEvent GestureRecognizerPrivate::gestureEvent(const QPointF& pos, GestureEvent::Type type) |
|
339 { |
|
340 GestureEvent gestureEvent; |
|
341 gestureEvent.setType(type); |
|
342 gestureEvent.setPosition(pos); |
|
343 return gestureEvent; |
|
344 } |
|
345 |
|
346 void GestureRecognizerPrivate::timerEvent(QTimerEvent* event) |
|
347 { |
|
348 if (event->timerId() != m_timer.timerId()) |
|
349 return; |
|
350 |
|
351 m_timer.stop(); |
|
352 |
|
353 QPointF position; |
|
354 GestureEvent::Type gestureType; |
|
355 |
|
356 if (m_state == GestureRecognizerPrivate::Press) { |
|
357 //Long press |
|
358 position = m_position; |
|
359 gestureType = GestureEvent::LongTap; |
|
360 } else if (m_state == GestureRecognizerPrivate::Release) { |
|
361 //Actual release event |
|
362 position = m_initialPos; |
|
363 gestureType = GestureEvent::Release; |
|
364 } else { |
|
365 resetTouchPositions(); |
|
366 changeState(GestureRecognizerPrivate::Inactive); |
|
367 return; |
|
368 } |
|
369 |
|
370 resetTouchPositions(); |
|
371 GestureEvent gesture = gestureEvent(position, gestureType); |
|
372 m_gestureListener->handleGesture(&gesture); |
|
373 return; |
|
374 } |
|
375 |
|
376 void GestureRecognizerPrivate::resetTouchPositions() |
|
377 { |
|
378 m_position = QPointF(-1, -1); |
|
379 m_initialPos = m_position; |
|
380 changeState(GestureRecognizerPrivate::Inactive); |
|
381 } |
|
382 |
|
383 QPointF GestureRecognizerPrivate::calculateVelocity(const QPointF& delta, int time) |
|
384 { |
|
385 QPointF newVelocity = m_velocity; |
|
386 |
|
387 if ((delta / qreal(time)).manhattanLength() < 25) { |
|
388 QPointF rawVelocity = delta / qreal(time) * qreal(1000) / qreal(m_scrollsPerSecond); |
|
389 newVelocity = newVelocity * (qreal(1) - m_dragInertia) + rawVelocity * m_dragInertia; |
|
390 } |
|
391 |
|
392 newVelocity.setX(delta.x() ? qBound(-m_maxVelocity, newVelocity.x(), m_maxVelocity) : m_velocity.x()); |
|
393 newVelocity.setY(delta.y() ? qBound(-m_maxVelocity, newVelocity.y(), m_maxVelocity) : m_velocity.y()); |
|
394 return newVelocity; |
|
395 } |
|
396 |
|
397 } // namespace GVA |
|
398 |