source: trunk/src/gui/kernel/qstandardgestures.cpp@ 1006

Last change on this file since 1006 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 20.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qstandardgestures_p.h"
43#include "qgesture.h"
44#include "qgesture_p.h"
45#include "qevent.h"
46#include "qwidget.h"
47#include "qabstractscrollarea.h"
48#include <qgraphicssceneevent.h>
49#include "qdebug.h"
50
51#ifndef QT_NO_GESTURES
52
53QT_BEGIN_NAMESPACE
54
55QPanGestureRecognizer::QPanGestureRecognizer()
56{
57}
58
59QGesture *QPanGestureRecognizer::create(QObject *target)
60{
61 if (target && target->isWidgetType()) {
62#if defined(Q_OS_WIN) && !defined(QT_NO_NATIVE_GESTURES)
63 // for scroll areas on Windows we want to use native gestures instead
64 if (!qobject_cast<QAbstractScrollArea *>(target->parent()))
65 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
66#else
67 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
68#endif
69 }
70 return new QPanGesture;
71}
72
73QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state,
74 QObject *,
75 QEvent *event)
76{
77 QPanGesture *q = static_cast<QPanGesture *>(state);
78 QPanGesturePrivate *d = q->d_func();
79
80 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
81
82 QGestureRecognizer::Result result;
83 switch (event->type()) {
84 case QEvent::TouchBegin: {
85 result = QGestureRecognizer::MayBeGesture;
86 QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
87 d->lastOffset = d->offset = QPointF();
88 break;
89 }
90 case QEvent::TouchEnd: {
91 if (q->state() != Qt::NoGesture) {
92 if (ev->touchPoints().size() == 2) {
93 QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
94 QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
95 d->lastOffset = d->offset;
96 d->offset =
97 QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(),
98 p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2;
99 }
100 result = QGestureRecognizer::FinishGesture;
101 } else {
102 result = QGestureRecognizer::CancelGesture;
103 }
104 break;
105 }
106 case QEvent::TouchUpdate: {
107 if (ev->touchPoints().size() >= 2) {
108 QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
109 QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
110 d->lastOffset = d->offset;
111 d->offset =
112 QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(),
113 p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2;
114 if (d->offset.x() > 10 || d->offset.y() > 10 ||
115 d->offset.x() < -10 || d->offset.y() < -10) {
116 q->setHotSpot(p1.startScreenPos());
117 result = QGestureRecognizer::TriggerGesture;
118 } else {
119 result = QGestureRecognizer::MayBeGesture;
120 }
121 }
122 break;
123 }
124 case QEvent::MouseButtonPress:
125 case QEvent::MouseMove:
126 case QEvent::MouseButtonRelease:
127 result = QGestureRecognizer::Ignore;
128 break;
129 default:
130 result = QGestureRecognizer::Ignore;
131 break;
132 }
133 return result;
134}
135
136void QPanGestureRecognizer::reset(QGesture *state)
137{
138 QPanGesture *pan = static_cast<QPanGesture*>(state);
139 QPanGesturePrivate *d = pan->d_func();
140
141 d->lastOffset = d->offset = QPointF();
142 d->acceleration = 0;
143
144 QGestureRecognizer::reset(state);
145}
146
147
148//
149// QPinchGestureRecognizer
150//
151
152QPinchGestureRecognizer::QPinchGestureRecognizer()
153{
154}
155
156QGesture *QPinchGestureRecognizer::create(QObject *target)
157{
158 if (target && target->isWidgetType()) {
159 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
160 }
161 return new QPinchGesture;
162}
163
164QGestureRecognizer::Result QPinchGestureRecognizer::recognize(QGesture *state,
165 QObject *,
166 QEvent *event)
167{
168 QPinchGesture *q = static_cast<QPinchGesture *>(state);
169 QPinchGesturePrivate *d = q->d_func();
170
171 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
172
173 QGestureRecognizer::Result result;
174
175 switch (event->type()) {
176 case QEvent::TouchBegin: {
177 result = QGestureRecognizer::MayBeGesture;
178 break;
179 }
180 case QEvent::TouchEnd: {
181 if (q->state() != Qt::NoGesture) {
182 result = QGestureRecognizer::FinishGesture;
183 } else {
184 result = QGestureRecognizer::CancelGesture;
185 }
186 break;
187 }
188 case QEvent::TouchUpdate: {
189 d->changeFlags = 0;
190 if (ev->touchPoints().size() == 2) {
191 QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
192 QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
193
194 d->hotSpot = p1.screenPos();
195 d->isHotSpotSet = true;
196
197 QPointF centerPoint = (p1.screenPos() + p2.screenPos()) / 2.0;
198 if (d->isNewSequence) {
199 d->startPosition[0] = p1.screenPos();
200 d->startPosition[1] = p2.screenPos();
201 d->lastCenterPoint = centerPoint;
202 } else {
203 d->lastCenterPoint = d->centerPoint;
204 }
205 d->centerPoint = centerPoint;
206
207 d->changeFlags |= QPinchGesture::CenterPointChanged;
208
209 if (d->isNewSequence) {
210 d->scaleFactor = 1.0;
211 d->lastScaleFactor = 1.0;
212 } else {
213 d->lastScaleFactor = d->scaleFactor;
214 QLineF line(p1.screenPos(), p2.screenPos());
215 QLineF lastLine(p1.lastScreenPos(), p2.lastScreenPos());
216 d->scaleFactor = line.length() / lastLine.length();
217 }
218 d->totalScaleFactor = d->totalScaleFactor * d->scaleFactor;
219 d->changeFlags |= QPinchGesture::ScaleFactorChanged;
220
221 qreal angle = QLineF(p1.screenPos(), p2.screenPos()).angle();
222 if (angle > 180)
223 angle -= 360;
224 qreal startAngle = QLineF(p1.startScreenPos(), p2.startScreenPos()).angle();
225 if (startAngle > 180)
226 startAngle -= 360;
227 const qreal rotationAngle = startAngle - angle;
228 if (d->isNewSequence)
229 d->lastRotationAngle = 0.0;
230 else
231 d->lastRotationAngle = d->rotationAngle;
232 d->rotationAngle = rotationAngle;
233 d->totalRotationAngle += d->rotationAngle - d->lastRotationAngle;
234 d->changeFlags |= QPinchGesture::RotationAngleChanged;
235
236 d->totalChangeFlags |= d->changeFlags;
237 d->isNewSequence = false;
238 result = QGestureRecognizer::TriggerGesture;
239 } else {
240 d->isNewSequence = true;
241 if (q->state() == Qt::NoGesture)
242 result = QGestureRecognizer::Ignore;
243 else
244 result = QGestureRecognizer::FinishGesture;
245 }
246 break;
247 }
248 case QEvent::MouseButtonPress:
249 case QEvent::MouseMove:
250 case QEvent::MouseButtonRelease:
251 result = QGestureRecognizer::Ignore;
252 break;
253 default:
254 result = QGestureRecognizer::Ignore;
255 break;
256 }
257 return result;
258}
259
260void QPinchGestureRecognizer::reset(QGesture *state)
261{
262 QPinchGesture *pinch = static_cast<QPinchGesture *>(state);
263 QPinchGesturePrivate *d = pinch->d_func();
264
265 d->totalChangeFlags = d->changeFlags = 0;
266
267 d->startCenterPoint = d->lastCenterPoint = d->centerPoint = QPointF();
268 d->totalScaleFactor = d->lastScaleFactor = d->scaleFactor = 1;
269 d->totalRotationAngle = d->lastRotationAngle = d->rotationAngle = 0;
270
271 d->isNewSequence = true;
272 d->startPosition[0] = d->startPosition[1] = QPointF();
273
274 QGestureRecognizer::reset(state);
275}
276
277//
278// QSwipeGestureRecognizer
279//
280
281QSwipeGestureRecognizer::QSwipeGestureRecognizer()
282{
283}
284
285QGesture *QSwipeGestureRecognizer::create(QObject *target)
286{
287 if (target && target->isWidgetType()) {
288 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
289 }
290 return new QSwipeGesture;
291}
292
293QGestureRecognizer::Result QSwipeGestureRecognizer::recognize(QGesture *state,
294 QObject *,
295 QEvent *event)
296{
297 QSwipeGesture *q = static_cast<QSwipeGesture *>(state);
298 QSwipeGesturePrivate *d = q->d_func();
299
300 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
301
302 QGestureRecognizer::Result result;
303
304 switch (event->type()) {
305 case QEvent::TouchBegin: {
306 d->velocityValue = 1;
307 d->time.start();
308 d->started = true;
309 result = QGestureRecognizer::MayBeGesture;
310 break;
311 }
312 case QEvent::TouchEnd: {
313 if (q->state() != Qt::NoGesture) {
314 result = QGestureRecognizer::FinishGesture;
315 } else {
316 result = QGestureRecognizer::CancelGesture;
317 }
318 break;
319 }
320 case QEvent::TouchUpdate: {
321 if (!d->started)
322 result = QGestureRecognizer::CancelGesture;
323 else if (ev->touchPoints().size() == 3) {
324 QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
325 QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
326 QTouchEvent::TouchPoint p3 = ev->touchPoints().at(2);
327
328 if (d->lastPositions[0].isNull()) {
329 d->lastPositions[0] = p1.startScreenPos().toPoint();
330 d->lastPositions[1] = p2.startScreenPos().toPoint();
331 d->lastPositions[2] = p3.startScreenPos().toPoint();
332 }
333 d->hotSpot = p1.screenPos();
334 d->isHotSpotSet = true;
335
336 int xDistance = (p1.screenPos().x() - d->lastPositions[0].x() +
337 p2.screenPos().x() - d->lastPositions[1].x() +
338 p3.screenPos().x() - d->lastPositions[2].x()) / 3;
339 int yDistance = (p1.screenPos().y() - d->lastPositions[0].y() +
340 p2.screenPos().y() - d->lastPositions[1].y() +
341 p3.screenPos().y() - d->lastPositions[2].y()) / 3;
342
343 const int distance = xDistance >= yDistance ? xDistance : yDistance;
344 int elapsedTime = d->time.restart();
345 if (!elapsedTime)
346 elapsedTime = 1;
347 d->velocityValue = 0.9 * d->velocityValue + distance / elapsedTime;
348 d->swipeAngle = QLineF(p1.startScreenPos(), p1.screenPos()).angle();
349
350 static const int MoveThreshold = 50;
351 if (xDistance > MoveThreshold || yDistance > MoveThreshold) {
352 // measure the distance to check if the direction changed
353 d->lastPositions[0] = p1.screenPos().toPoint();
354 d->lastPositions[1] = p2.screenPos().toPoint();
355 d->lastPositions[2] = p3.screenPos().toPoint();
356 QSwipeGesture::SwipeDirection horizontal =
357 xDistance > 0 ? QSwipeGesture::Right : QSwipeGesture::Left;
358 QSwipeGesture::SwipeDirection vertical =
359 yDistance > 0 ? QSwipeGesture::Down : QSwipeGesture::Up;
360 if (d->verticalDirection == QSwipeGesture::NoDirection)
361 d->verticalDirection = vertical;
362 if (d->horizontalDirection == QSwipeGesture::NoDirection)
363 d->horizontalDirection = horizontal;
364 if (d->verticalDirection != vertical || d->horizontalDirection != horizontal) {
365 // the user has changed the direction!
366 result = QGestureRecognizer::CancelGesture;
367 }
368 result = QGestureRecognizer::TriggerGesture;
369 } else {
370 if (q->state() != Qt::NoGesture)
371 result = QGestureRecognizer::TriggerGesture;
372 else
373 result = QGestureRecognizer::MayBeGesture;
374 }
375 } else if (ev->touchPoints().size() > 3) {
376 result = QGestureRecognizer::CancelGesture;
377 } else { // less than 3 touch points
378 if (d->started && (ev->touchPointStates() & Qt::TouchPointPressed))
379 result = QGestureRecognizer::CancelGesture;
380 else if (d->started)
381 result = QGestureRecognizer::Ignore;
382 else
383 result = QGestureRecognizer::MayBeGesture;
384 }
385 break;
386 }
387 case QEvent::MouseButtonPress:
388 case QEvent::MouseMove:
389 case QEvent::MouseButtonRelease:
390 result = QGestureRecognizer::Ignore;
391 break;
392 default:
393 result = QGestureRecognizer::Ignore;
394 break;
395 }
396 return result;
397}
398
399void QSwipeGestureRecognizer::reset(QGesture *state)
400{
401 QSwipeGesture *q = static_cast<QSwipeGesture *>(state);
402 QSwipeGesturePrivate *d = q->d_func();
403
404 d->verticalDirection = d->horizontalDirection = QSwipeGesture::NoDirection;
405 d->swipeAngle = 0;
406
407 d->lastPositions[0] = d->lastPositions[1] = d->lastPositions[2] = QPoint();
408 d->started = false;
409 d->velocityValue = 0;
410 d->time.invalidate();
411
412 QGestureRecognizer::reset(state);
413}
414
415//
416// QTapGestureRecognizer
417//
418
419QTapGestureRecognizer::QTapGestureRecognizer()
420{
421}
422
423QGesture *QTapGestureRecognizer::create(QObject *target)
424{
425 if (target && target->isWidgetType()) {
426 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
427 }
428 return new QTapGesture;
429}
430
431QGestureRecognizer::Result QTapGestureRecognizer::recognize(QGesture *state,
432 QObject *,
433 QEvent *event)
434{
435 QTapGesture *q = static_cast<QTapGesture *>(state);
436 QTapGesturePrivate *d = q->d_func();
437
438 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
439
440 QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture;
441
442 switch (event->type()) {
443 case QEvent::TouchBegin: {
444 d->position = ev->touchPoints().at(0).pos();
445 q->setHotSpot(ev->touchPoints().at(0).screenPos());
446 result = QGestureRecognizer::TriggerGesture;
447 break;
448 }
449 case QEvent::TouchUpdate:
450 case QEvent::TouchEnd: {
451 if (q->state() != Qt::NoGesture && ev->touchPoints().size() == 1) {
452 QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
453 QPoint delta = p.pos().toPoint() - p.startPos().toPoint();
454 enum { TapRadius = 40 };
455 if (delta.manhattanLength() <= TapRadius) {
456 if (event->type() == QEvent::TouchEnd)
457 result = QGestureRecognizer::FinishGesture;
458 else
459 result = QGestureRecognizer::TriggerGesture;
460 }
461 }
462 break;
463 }
464 case QEvent::MouseButtonPress:
465 case QEvent::MouseMove:
466 case QEvent::MouseButtonRelease:
467 result = QGestureRecognizer::Ignore;
468 break;
469 default:
470 result = QGestureRecognizer::Ignore;
471 break;
472 }
473 return result;
474}
475
476void QTapGestureRecognizer::reset(QGesture *state)
477{
478 QTapGesture *q = static_cast<QTapGesture *>(state);
479 QTapGesturePrivate *d = q->d_func();
480
481 d->position = QPointF();
482
483 QGestureRecognizer::reset(state);
484}
485
486//
487// QTapAndHoldGestureRecognizer
488//
489
490QTapAndHoldGestureRecognizer::QTapAndHoldGestureRecognizer()
491{
492}
493
494QGesture *QTapAndHoldGestureRecognizer::create(QObject *target)
495{
496 if (target && target->isWidgetType()) {
497 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
498 }
499 return new QTapAndHoldGesture;
500}
501
502QGestureRecognizer::Result
503QTapAndHoldGestureRecognizer::recognize(QGesture *state, QObject *object,
504 QEvent *event)
505{
506 QTapAndHoldGesture *q = static_cast<QTapAndHoldGesture *>(state);
507 QTapAndHoldGesturePrivate *d = q->d_func();
508
509 if (object == state && event->type() == QEvent::Timer) {
510 q->killTimer(d->timerId);
511 d->timerId = 0;
512 return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint;
513 }
514
515 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
516 const QMouseEvent *me = static_cast<const QMouseEvent *>(event);
517#ifndef QT_NO_GRAPHICSVIEW
518 const QGraphicsSceneMouseEvent *gsme = static_cast<const QGraphicsSceneMouseEvent *>(event);
519#endif
520
521 enum { TapRadius = 40 };
522
523 switch (event->type()) {
524#ifndef QT_NO_GRAPHICSVIEW
525 case QEvent::GraphicsSceneMousePress:
526 d->position = gsme->screenPos();
527 q->setHotSpot(d->position);
528 if (d->timerId)
529 q->killTimer(d->timerId);
530 d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout);
531 return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
532#endif
533 case QEvent::MouseButtonPress:
534 d->position = me->globalPos();
535 q->setHotSpot(d->position);
536 if (d->timerId)
537 q->killTimer(d->timerId);
538 d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout);
539 return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
540 case QEvent::TouchBegin:
541 d->position = ev->touchPoints().at(0).startScreenPos();
542 q->setHotSpot(d->position);
543 if (d->timerId)
544 q->killTimer(d->timerId);
545 d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout);
546 return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
547#ifndef QT_NO_GRAPHICSVIEW
548 case QEvent::GraphicsSceneMouseRelease:
549#endif
550 case QEvent::MouseButtonRelease:
551 case QEvent::TouchEnd:
552 return QGestureRecognizer::CancelGesture; // get out of the MayBeGesture state
553 case QEvent::TouchUpdate:
554 if (d->timerId && ev->touchPoints().size() == 1) {
555 QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
556 QPoint delta = p.pos().toPoint() - p.startPos().toPoint();
557 if (delta.manhattanLength() <= TapRadius)
558 return QGestureRecognizer::MayBeGesture;
559 }
560 return QGestureRecognizer::CancelGesture;
561 case QEvent::MouseMove: {
562 QPoint delta = me->globalPos() - d->position.toPoint();
563 if (d->timerId && delta.manhattanLength() <= TapRadius)
564 return QGestureRecognizer::MayBeGesture;
565 return QGestureRecognizer::CancelGesture;
566 }
567#ifndef QT_NO_GRAPHICSVIEW
568 case QEvent::GraphicsSceneMouseMove: {
569 QPoint delta = gsme->screenPos() - d->position.toPoint();
570 if (d->timerId && delta.manhattanLength() <= TapRadius)
571 return QGestureRecognizer::MayBeGesture;
572 return QGestureRecognizer::CancelGesture;
573 }
574#endif
575 default:
576 return QGestureRecognizer::Ignore;
577 }
578}
579
580void QTapAndHoldGestureRecognizer::reset(QGesture *state)
581{
582 QTapAndHoldGesture *q = static_cast<QTapAndHoldGesture *>(state);
583 QTapAndHoldGesturePrivate *d = q->d_func();
584
585 d->position = QPointF();
586 if (d->timerId)
587 q->killTimer(d->timerId);
588 d->timerId = 0;
589
590 QGestureRecognizer::reset(state);
591}
592
593QT_END_NAMESPACE
594
595#endif // QT_NO_GESTURES
Note: See TracBrowser for help on using the repository browser.