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

Last change on this file since 642 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 19.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
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 [email protected].
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 "qdebug.h"
49
50QT_BEGIN_NAMESPACE
51
52QPanGestureRecognizer::QPanGestureRecognizer()
53{
54}
55
56QGesture *QPanGestureRecognizer::create(QObject *target)
57{
58 if (target && target->isWidgetType()) {
59#if defined(Q_OS_WIN) && !defined(QT_NO_NATIVE_GESTURES)
60 // for scroll areas on Windows we want to use native gestures instead
61 if (!qobject_cast<QAbstractScrollArea *>(target->parent()))
62 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
63#else
64 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
65#endif
66 }
67 return new QPanGesture;
68}
69
70QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state,
71 QObject *,
72 QEvent *event)
73{
74 QPanGesture *q = static_cast<QPanGesture *>(state);
75 QPanGesturePrivate *d = q->d_func();
76
77 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
78
79 QGestureRecognizer::Result result;
80 switch (event->type()) {
81 case QEvent::TouchBegin: {
82 result = QGestureRecognizer::MayBeGesture;
83 QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
84 d->lastOffset = d->offset = QPointF();
85 break;
86 }
87 case QEvent::TouchEnd: {
88 if (q->state() != Qt::NoGesture) {
89 if (ev->touchPoints().size() == 2) {
90 QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
91 QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
92 d->lastOffset = d->offset;
93 d->offset =
94 QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(),
95 p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2;
96 }
97 result = QGestureRecognizer::FinishGesture;
98 } else {
99 result = QGestureRecognizer::CancelGesture;
100 }
101 break;
102 }
103 case QEvent::TouchUpdate: {
104 if (ev->touchPoints().size() >= 2) {
105 QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
106 QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
107 d->lastOffset = d->offset;
108 d->offset =
109 QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(),
110 p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2;
111 if (d->offset.x() > 10 || d->offset.y() > 10 ||
112 d->offset.x() < -10 || d->offset.y() < -10) {
113 result = QGestureRecognizer::TriggerGesture;
114 } else {
115 result = QGestureRecognizer::MayBeGesture;
116 }
117 }
118 break;
119 }
120 case QEvent::MouseButtonPress:
121 case QEvent::MouseMove:
122 case QEvent::MouseButtonRelease:
123 result = QGestureRecognizer::Ignore;
124 break;
125 default:
126 result = QGestureRecognizer::Ignore;
127 break;
128 }
129 return result;
130}
131
132void QPanGestureRecognizer::reset(QGesture *state)
133{
134 QPanGesture *pan = static_cast<QPanGesture*>(state);
135 QPanGesturePrivate *d = pan->d_func();
136
137 d->lastOffset = d->offset = QPointF();
138 d->acceleration = 0;
139
140 QGestureRecognizer::reset(state);
141}
142
143
144//
145// QPinchGestureRecognizer
146//
147
148QPinchGestureRecognizer::QPinchGestureRecognizer()
149{
150}
151
152QGesture *QPinchGestureRecognizer::create(QObject *target)
153{
154 if (target && target->isWidgetType()) {
155 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
156 }
157 return new QPinchGesture;
158}
159
160QGestureRecognizer::Result QPinchGestureRecognizer::recognize(QGesture *state,
161 QObject *,
162 QEvent *event)
163{
164 QPinchGesture *q = static_cast<QPinchGesture *>(state);
165 QPinchGesturePrivate *d = q->d_func();
166
167 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
168
169 QGestureRecognizer::Result result;
170
171 switch (event->type()) {
172 case QEvent::TouchBegin: {
173 result = QGestureRecognizer::MayBeGesture;
174 break;
175 }
176 case QEvent::TouchEnd: {
177 if (q->state() != Qt::NoGesture) {
178 result = QGestureRecognizer::FinishGesture;
179 } else {
180 result = QGestureRecognizer::CancelGesture;
181 }
182 break;
183 }
184 case QEvent::TouchUpdate: {
185 d->changeFlags = 0;
186 if (ev->touchPoints().size() == 2) {
187 QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
188 QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
189
190 d->hotSpot = p1.screenPos();
191 d->isHotSpotSet = true;
192
193 if (d->isNewSequence) {
194 d->startPosition[0] = p1.screenPos();
195 d->startPosition[1] = p2.screenPos();
196 }
197 QLineF line(p1.screenPos(), p2.screenPos());
198 QLineF tmp(line);
199 tmp.setLength(line.length() / 2.);
200 QPointF centerPoint = tmp.p2();
201
202 d->lastCenterPoint = d->centerPoint;
203 d->centerPoint = centerPoint;
204 d->changeFlags |= QPinchGesture::CenterPointChanged;
205
206 const qreal scaleFactor =
207 QLineF(p1.screenPos(), p2.screenPos()).length()
208 / QLineF(d->startPosition[0], d->startPosition[1]).length();
209 if (d->isNewSequence) {
210 d->lastScaleFactor = scaleFactor;
211 } else {
212 d->lastScaleFactor = d->scaleFactor;
213 }
214 d->scaleFactor = scaleFactor;
215 d->totalScaleFactor += d->scaleFactor - d->lastScaleFactor;
216 d->changeFlags |= QPinchGesture::ScaleFactorChanged;
217
218 qreal angle = QLineF(p1.screenPos(), p2.screenPos()).angle();
219 if (angle > 180)
220 angle -= 360;
221 qreal startAngle = QLineF(p1.startScreenPos(), p2.startScreenPos()).angle();
222 if (startAngle > 180)
223 startAngle -= 360;
224 const qreal rotationAngle = startAngle - angle;
225 if (d->isNewSequence)
226 d->lastRotationAngle = rotationAngle;
227 else
228 d->lastRotationAngle = d->rotationAngle;
229 d->rotationAngle = rotationAngle;
230 d->totalRotationAngle += d->rotationAngle - d->lastRotationAngle;
231 d->changeFlags |= QPinchGesture::RotationAngleChanged;
232
233 d->totalChangeFlags |= d->changeFlags;
234 d->isNewSequence = false;
235 result = QGestureRecognizer::TriggerGesture;
236 } else {
237 d->isNewSequence = true;
238 if (q->state() == Qt::NoGesture)
239 result = QGestureRecognizer::Ignore;
240 else
241 result = QGestureRecognizer::FinishGesture;
242 }
243 break;
244 }
245 case QEvent::MouseButtonPress:
246 case QEvent::MouseMove:
247 case QEvent::MouseButtonRelease:
248 result = QGestureRecognizer::Ignore;
249 break;
250 default:
251 result = QGestureRecognizer::Ignore;
252 break;
253 }
254 return result;
255}
256
257void QPinchGestureRecognizer::reset(QGesture *state)
258{
259 QPinchGesture *pinch = static_cast<QPinchGesture *>(state);
260 QPinchGesturePrivate *d = pinch->d_func();
261
262 d->totalChangeFlags = d->changeFlags = 0;
263
264 d->startCenterPoint = d->lastCenterPoint = d->centerPoint = QPointF();
265 d->totalScaleFactor = d->lastScaleFactor = d->scaleFactor = 0;
266 d->totalRotationAngle = d->lastRotationAngle = d->rotationAngle = 0;
267
268 d->isNewSequence = true;
269 d->startPosition[0] = d->startPosition[1] = QPointF();
270
271 QGestureRecognizer::reset(state);
272}
273
274//
275// QSwipeGestureRecognizer
276//
277
278QSwipeGestureRecognizer::QSwipeGestureRecognizer()
279{
280}
281
282QGesture *QSwipeGestureRecognizer::create(QObject *target)
283{
284 if (target && target->isWidgetType()) {
285 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
286 }
287 return new QSwipeGesture;
288}
289
290QGestureRecognizer::Result QSwipeGestureRecognizer::recognize(QGesture *state,
291 QObject *,
292 QEvent *event)
293{
294 QSwipeGesture *q = static_cast<QSwipeGesture *>(state);
295 QSwipeGesturePrivate *d = q->d_func();
296
297 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
298
299 QGestureRecognizer::Result result;
300
301 switch (event->type()) {
302 case QEvent::TouchBegin: {
303 d->speed = 1;
304 d->time = QTime::currentTime();
305 d->started = true;
306 result = QGestureRecognizer::MayBeGesture;
307 break;
308 }
309 case QEvent::TouchEnd: {
310 if (q->state() != Qt::NoGesture) {
311 result = QGestureRecognizer::FinishGesture;
312 } else {
313 result = QGestureRecognizer::CancelGesture;
314 }
315 break;
316 }
317 case QEvent::TouchUpdate: {
318 if (!d->started)
319 result = QGestureRecognizer::CancelGesture;
320 else if (ev->touchPoints().size() == 3) {
321 QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
322 QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
323 QTouchEvent::TouchPoint p3 = ev->touchPoints().at(2);
324
325 if (d->lastPositions[0].isNull()) {
326 d->lastPositions[0] = p1.startScreenPos().toPoint();
327 d->lastPositions[1] = p2.startScreenPos().toPoint();
328 d->lastPositions[2] = p3.startScreenPos().toPoint();
329 }
330 d->hotSpot = p1.screenPos();
331 d->isHotSpotSet = true;
332
333 int xDistance = (p1.screenPos().x() - d->lastPositions[0].x() +
334 p2.screenPos().x() - d->lastPositions[1].x() +
335 p3.screenPos().x() - d->lastPositions[2].x()) / 3;
336 int yDistance = (p1.screenPos().y() - d->lastPositions[0].y() +
337 p2.screenPos().y() - d->lastPositions[1].y() +
338 p3.screenPos().y() - d->lastPositions[2].y()) / 3;
339
340 const int distance = xDistance >= yDistance ? xDistance : yDistance;
341 int elapsedTime = d->time.msecsTo(QTime::currentTime());
342 if (!elapsedTime)
343 elapsedTime = 1;
344 d->speed = 0.9 * d->speed + distance / elapsedTime;
345 d->time = QTime::currentTime();
346 d->swipeAngle = QLineF(p1.startScreenPos(), p1.screenPos()).angle();
347
348 static const int MoveThreshold = 50;
349 if (xDistance > MoveThreshold || yDistance > MoveThreshold) {
350 // measure the distance to check if the direction changed
351 d->lastPositions[0] = p1.screenPos().toPoint();
352 d->lastPositions[1] = p2.screenPos().toPoint();
353 d->lastPositions[2] = p3.screenPos().toPoint();
354 QSwipeGesture::SwipeDirection horizontal =
355 xDistance > 0 ? QSwipeGesture::Right : QSwipeGesture::Left;
356 QSwipeGesture::SwipeDirection vertical =
357 yDistance > 0 ? QSwipeGesture::Down : QSwipeGesture::Up;
358 if (d->verticalDirection == QSwipeGesture::NoDirection)
359 d->verticalDirection = vertical;
360 if (d->horizontalDirection == QSwipeGesture::NoDirection)
361 d->horizontalDirection = horizontal;
362 if (d->verticalDirection != vertical || d->horizontalDirection != horizontal) {
363 // the user has changed the direction!
364 result = QGestureRecognizer::CancelGesture;
365 }
366 result = QGestureRecognizer::TriggerGesture;
367 } else {
368 if (q->state() != Qt::NoGesture)
369 result = QGestureRecognizer::TriggerGesture;
370 else
371 result = QGestureRecognizer::MayBeGesture;
372 }
373 } else if (ev->touchPoints().size() > 3) {
374 result = QGestureRecognizer::CancelGesture;
375 } else { // less than 3 touch points
376 if (d->started && (ev->touchPointStates() & Qt::TouchPointPressed))
377 result = QGestureRecognizer::CancelGesture;
378 else if (d->started)
379 result = QGestureRecognizer::Ignore;
380 else
381 result = QGestureRecognizer::MayBeGesture;
382 }
383 break;
384 }
385 case QEvent::MouseButtonPress:
386 case QEvent::MouseMove:
387 case QEvent::MouseButtonRelease:
388 result = QGestureRecognizer::Ignore;
389 break;
390 default:
391 result = QGestureRecognizer::Ignore;
392 break;
393 }
394 return result;
395}
396
397void QSwipeGestureRecognizer::reset(QGesture *state)
398{
399 QSwipeGesture *q = static_cast<QSwipeGesture *>(state);
400 QSwipeGesturePrivate *d = q->d_func();
401
402 d->verticalDirection = d->horizontalDirection = QSwipeGesture::NoDirection;
403 d->swipeAngle = 0;
404
405 d->lastPositions[0] = d->lastPositions[1] = d->lastPositions[2] = QPoint();
406 d->started = false;
407 d->speed = 0;
408 d->time = QTime();
409
410 QGestureRecognizer::reset(state);
411}
412
413//
414// QTapGestureRecognizer
415//
416
417QTapGestureRecognizer::QTapGestureRecognizer()
418{
419}
420
421QGesture *QTapGestureRecognizer::create(QObject *target)
422{
423 if (target && target->isWidgetType()) {
424 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
425 }
426 return new QTapGesture;
427}
428
429QGestureRecognizer::Result QTapGestureRecognizer::recognize(QGesture *state,
430 QObject *,
431 QEvent *event)
432{
433 QTapGesture *q = static_cast<QTapGesture *>(state);
434 QTapGesturePrivate *d = q->d_func();
435
436 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
437
438 QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture;
439
440 switch (event->type()) {
441 case QEvent::TouchBegin: {
442 d->position = ev->touchPoints().at(0).pos();
443 result = QGestureRecognizer::TriggerGesture;
444 break;
445 }
446 case QEvent::TouchUpdate:
447 case QEvent::TouchEnd: {
448 if (q->state() != Qt::NoGesture && ev->touchPoints().size() == 1) {
449 QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
450 QPoint delta = p.pos().toPoint() - p.startPos().toPoint();
451 enum { TapRadius = 40 };
452 if (delta.manhattanLength() <= TapRadius) {
453 if (event->type() == QEvent::TouchEnd)
454 result = QGestureRecognizer::FinishGesture;
455 else
456 result = QGestureRecognizer::TriggerGesture;
457 }
458 }
459 break;
460 }
461 case QEvent::MouseButtonPress:
462 case QEvent::MouseMove:
463 case QEvent::MouseButtonRelease:
464 result = QGestureRecognizer::Ignore;
465 break;
466 default:
467 result = QGestureRecognizer::Ignore;
468 break;
469 }
470 return result;
471}
472
473void QTapGestureRecognizer::reset(QGesture *state)
474{
475 QTapGesture *q = static_cast<QTapGesture *>(state);
476 QTapGesturePrivate *d = q->d_func();
477
478 d->position = QPointF();
479
480 QGestureRecognizer::reset(state);
481}
482
483//
484// QTapAndHoldGestureRecognizer
485//
486
487QTapAndHoldGestureRecognizer::QTapAndHoldGestureRecognizer()
488{
489}
490
491QGesture *QTapAndHoldGestureRecognizer::create(QObject *target)
492{
493 if (target && target->isWidgetType()) {
494 static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
495 }
496 return new QTapAndHoldGesture;
497}
498
499QGestureRecognizer::Result
500QTapAndHoldGestureRecognizer::recognize(QGesture *state, QObject *object,
501 QEvent *event)
502{
503 QTapAndHoldGesture *q = static_cast<QTapAndHoldGesture *>(state);
504 QTapAndHoldGesturePrivate *d = q->d_func();
505
506 if (object == state && event->type() == QEvent::Timer) {
507 q->killTimer(d->timerId);
508 d->timerId = 0;
509 return QGestureRecognizer::Ignore | QGestureRecognizer::ConsumeEventHint;
510 }
511
512 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
513
514 QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture;
515
516 enum { TimerInterval = 2000 };
517 enum { TapRadius = 40 };
518
519 switch (event->type()) {
520 case QEvent::TouchBegin:
521 d->position = ev->touchPoints().at(0).pos();
522 if (d->timerId)
523 q->killTimer(d->timerId);
524 d->timerId = q->startTimer(TimerInterval);
525 result = QGestureRecognizer::TriggerGesture;
526 break;
527 case QEvent::TouchEnd:
528 if (d->timerId)
529 result = QGestureRecognizer::CancelGesture;
530 else
531 result = QGestureRecognizer::FinishGesture;
532 break;
533 case QEvent::TouchUpdate:
534 if (q->state() != Qt::NoGesture && ev->touchPoints().size() == 1) {
535 QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
536 QPoint delta = p.pos().toPoint() - p.startPos().toPoint();
537 if (delta.manhattanLength() <= TapRadius)
538 result = QGestureRecognizer::TriggerGesture;
539 }
540 break;
541 case QEvent::MouseButtonPress:
542 case QEvent::MouseMove:
543 case QEvent::MouseButtonRelease:
544 result = QGestureRecognizer::Ignore;
545 break;
546 default:
547 result = QGestureRecognizer::Ignore;
548 break;
549 }
550 return result;
551}
552
553void QTapAndHoldGestureRecognizer::reset(QGesture *state)
554{
555 QTapAndHoldGesture *q = static_cast<QTapAndHoldGesture *>(state);
556 QTapAndHoldGesturePrivate *d = q->d_func();
557
558 d->position = QPointF();
559 if (d->timerId)
560 q->killTimer(d->timerId);
561 d->timerId = 0;
562
563 QGestureRecognizer::reset(state);
564}
565
566QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.