Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qstandardgestures.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "qgesture.h"
6#include "qgesture_p.h"
7#include "qevent.h"
8#include "qwidget.h"
10#if QT_CONFIG(graphicsview)
11#include <qgraphicssceneevent.h>
12#endif
13#include "qdebug.h"
14
15#ifndef QT_NO_GESTURES
16
18
19// If the change in scale for a single touch event is out of this range,
20// we consider it to be spurious.
21static const qreal kSingleStepScaleMax = 2.0;
22static const qreal kSingleStepScaleMin = 0.1;
23
25{
26 if (target && target->isWidgetType()) {
27#if (defined(Q_OS_MACOS) || defined(Q_OS_WIN)) && !defined(QT_NO_NATIVE_GESTURES)
28 // for scroll areas on Windows and OS X we want to use native gestures instead
29 if (!qobject_cast<QAbstractScrollArea *>(target->parent()))
31#else
33#endif
34 }
35 return new QPanGesture;
36}
37
38static QPointF panOffset(const QList<QEventPoint> &touchPoints, int maxCount)
39{
41 const int count = qMin(touchPoints.size(), maxCount);
42 for (int p = 0; p < count; ++p)
43 result += touchPoints.at(p).position() - touchPoints.at(p).pressPosition();
44 return result / qreal(count);
45}
46
48 QObject *,
50{
51 QPanGesture *q = static_cast<QPanGesture *>(state);
52 QPanGesturePrivate *d = q->d_func();
53
54 QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
55 switch (event->type()) {
56 case QEvent::TouchBegin: {
58 d->lastOffset = d->offset = QPointF();
59 d->pointCount = m_pointCount;
60 break;
61 }
62 case QEvent::TouchEnd: {
63 if (q->state() != Qt::NoGesture) {
64 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
65 if (ev->points().size() == d->pointCount) {
66 d->lastOffset = d->offset;
67 d->offset = panOffset(ev->points(), d->pointCount);
68 }
70 } else {
72 }
73 break;
74 }
76 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
77 if (ev->points().size() >= d->pointCount) {
78 d->lastOffset = d->offset;
79 d->offset = panOffset(ev->points(), d->pointCount);
80 if (d->offset.x() > 10 || d->offset.y() > 10 ||
81 d->offset.x() < -10 || d->offset.y() < -10) {
82 q->setHotSpot(ev->points().first().globalPressPosition());
84 } else {
86 }
87 }
88 break;
89 }
90 default:
91 break;
92 }
93 return result;
94}
95
97{
98 QPanGesture *pan = static_cast<QPanGesture*>(state);
99 QPanGesturePrivate *d = pan->d_func();
100
101 d->lastOffset = d->offset = QPointF();
102 d->acceleration = 0;
103
105}
106
107
108//
109// QPinchGestureRecognizer
110//
111
113{
114}
115
117{
118 if (target && target->isWidgetType()) {
120 }
121 return new QPinchGesture;
122}
123
125 QObject *,
126 QEvent *event)
127{
128 QPinchGesture *q = static_cast<QPinchGesture *>(state);
129 QPinchGesturePrivate *d = q->d_func();
130
131 QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
132
133 switch (event->type()) {
134 case QEvent::TouchBegin: {
136 break;
137 }
138 case QEvent::TouchEnd: {
139 if (q->state() != Qt::NoGesture) {
141 } else {
143 }
144 break;
145 }
146 case QEvent::TouchUpdate: {
147 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
148 d->changeFlags = { };
149 if (ev->points().size() == 2) {
150 const QEventPoint &p1 = ev->points().at(0);
151 const QEventPoint &p2 = ev->points().at(1);
152
153 d->hotSpot = p1.globalPosition();
154 d->isHotSpotSet = true;
155
156 QPointF centerPoint = (p1.globalPosition() + p2.globalPosition()) / 2.0;
157 if (d->isNewSequence) {
158 d->startPosition[0] = p1.globalPosition();
159 d->startPosition[1] = p2.globalPosition();
160 d->lastCenterPoint = centerPoint;
161 } else {
162 d->lastCenterPoint = d->centerPoint;
163 }
164 d->centerPoint = centerPoint;
165
166 d->changeFlags |= QPinchGesture::CenterPointChanged;
167
168 if (d->isNewSequence) {
169 d->scaleFactor = 1.0;
170 d->lastScaleFactor = 1.0;
171 } else {
172 d->lastScaleFactor = d->scaleFactor;
173 QLineF line(p1.globalPosition(), p2.globalPosition());
174 QLineF lastLine(p1.globalLastPosition(), p2.globalLastPosition());
175 qreal newScaleFactor = line.length() / lastLine.length();
176 if (newScaleFactor > kSingleStepScaleMax || newScaleFactor < kSingleStepScaleMin)
178 d->scaleFactor = newScaleFactor;
179 }
180 d->totalScaleFactor = d->totalScaleFactor * d->scaleFactor;
181 d->changeFlags |= QPinchGesture::ScaleFactorChanged;
182
183 qreal angle = QLineF(p1.globalPosition(), p2.globalPosition()).angle();
184 if (angle > 180)
185 angle -= 360;
186 qreal startAngle = QLineF(p1.globalPressPosition(), p2.globalPressPosition()).angle();
187 if (startAngle > 180)
188 startAngle -= 360;
189 const qreal rotationAngle = startAngle - angle;
190 if (d->isNewSequence)
191 d->lastRotationAngle = 0.0;
192 else
193 d->lastRotationAngle = d->rotationAngle;
194 d->rotationAngle = rotationAngle;
195 d->totalRotationAngle += d->rotationAngle - d->lastRotationAngle;
197
198 d->totalChangeFlags |= d->changeFlags;
199 d->isNewSequence = false;
201 } else {
202 d->isNewSequence = true;
203 if (q->state() == Qt::NoGesture)
205 else
207 }
208 break;
209 }
210 default:
211 break;
212 }
213 return result;
214}
215
217{
218 QPinchGesture *pinch = static_cast<QPinchGesture *>(state);
219 QPinchGesturePrivate *d = pinch->d_func();
220
221 d->totalChangeFlags = d->changeFlags = { };
222
223 d->startCenterPoint = d->lastCenterPoint = d->centerPoint = QPointF();
224 d->totalScaleFactor = d->lastScaleFactor = d->scaleFactor = 1;
225 d->totalRotationAngle = d->lastRotationAngle = d->rotationAngle = 0;
226
227 d->isNewSequence = true;
228 d->startPosition[0] = d->startPosition[1] = QPointF();
229
231}
232
233//
234// QSwipeGestureRecognizer
235//
236
238{
239}
240
242{
243 if (target && target->isWidgetType()) {
245 }
246 return new QSwipeGesture;
247}
248
250 QObject *,
251 QEvent *event)
252{
253 QSwipeGesture *q = static_cast<QSwipeGesture *>(state);
254 QSwipeGesturePrivate *d = q->d_func();
255
256 QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
257
258 switch (event->type()) {
259 case QEvent::TouchBegin: {
260 d->velocityValue = 1;
261 d->time.start();
264 break;
265 }
266 case QEvent::TouchEnd: {
267 if (q->state() != Qt::NoGesture) {
269 } else {
271 }
272 break;
273 }
274 case QEvent::TouchUpdate: {
275 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
278 else if (ev->points().size() == 3) {
280 const QEventPoint &p1 = ev->points().at(0);
281 const QEventPoint &p2 = ev->points().at(1);
282 const QEventPoint &p3 = ev->points().at(2);
283
284 if (d->lastPositions[0].isNull()) {
285 d->lastPositions[0] = p1.globalPressPosition().toPoint();
286 d->lastPositions[1] = p2.globalPressPosition().toPoint();
287 d->lastPositions[2] = p3.globalPressPosition().toPoint();
288 }
289 d->hotSpot = p1.globalPosition();
290 d->isHotSpotSet = true;
291
292 int xDistance = (p1.globalPosition().x() - d->lastPositions[0].x() +
293 p2.globalPosition().x() - d->lastPositions[1].x() +
294 p3.globalPosition().x() - d->lastPositions[2].x()) / 3;
295 int yDistance = (p1.globalPosition().y() - d->lastPositions[0].y() +
296 p2.globalPosition().y() - d->lastPositions[1].y() +
297 p3.globalPosition().y() - d->lastPositions[2].y()) / 3;
298
299 const int distance = xDistance >= yDistance ? xDistance : yDistance;
300 int elapsedTime = d->time.restart();
301 if (!elapsedTime)
302 elapsedTime = 1;
303 d->velocityValue = 0.9 * d->velocityValue + (qreal) distance / elapsedTime;
304 d->swipeAngle = QLineF(p1.globalPressPosition(), p1.globalPosition()).angle();
305
306 static const int MoveThreshold = 50;
307 static const int directionChangeThreshold = MoveThreshold / 8;
308 if (qAbs(xDistance) > MoveThreshold || qAbs(yDistance) > MoveThreshold) {
309 // measure the distance to check if the direction changed
310 d->lastPositions[0] = p1.globalPosition().toPoint();
311 d->lastPositions[1] = p2.globalPosition().toPoint();
312 d->lastPositions[2] = p3.globalPosition().toPoint();
314 // QTBUG-46195, small changes in direction should not cause the gesture to be canceled.
315 if (d->verticalDirection == QSwipeGesture::NoDirection || qAbs(yDistance) > directionChangeThreshold) {
316 const QSwipeGesture::SwipeDirection vertical = yDistance > 0
318 if (d->verticalDirection != QSwipeGesture::NoDirection && d->verticalDirection != vertical)
320 d->verticalDirection = vertical;
321 }
322 if (d->horizontalDirection == QSwipeGesture::NoDirection || qAbs(xDistance) > directionChangeThreshold) {
323 const QSwipeGesture::SwipeDirection horizontal = xDistance > 0
325 if (d->horizontalDirection != QSwipeGesture::NoDirection && d->horizontalDirection != horizontal)
327 d->horizontalDirection = horizontal;
328 }
329 } else {
330 if (q->state() != Qt::NoGesture)
332 else
334 }
335 } else if (ev->points().size() > 3) {
337 } else { // less than 3 touch points
338 switch (d->state) {
341 break;
344 break;
348 break;
349 }
350 }
351 break;
352 }
353 default:
354 break;
355 }
356 return result;
357}
358
360{
361 QSwipeGesture *q = static_cast<QSwipeGesture *>(state);
362 QSwipeGesturePrivate *d = q->d_func();
363
364 d->verticalDirection = d->horizontalDirection = QSwipeGesture::NoDirection;
365 d->swipeAngle = 0;
366
367 d->lastPositions[0] = d->lastPositions[1] = d->lastPositions[2] = QPoint();
369 d->velocityValue = 0;
370 d->time.invalidate();
371
373}
374
375//
376// QTapGestureRecognizer
377//
378
380{
381}
382
384{
385 if (target && target->isWidgetType()) {
387 }
388 return new QTapGesture;
389}
390
392 QObject *,
393 QEvent *event)
394{
395 QTapGesture *q = static_cast<QTapGesture *>(state);
396 QTapGesturePrivate *d = q->d_func();
397
398 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
399
400 QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture;
401
402 switch (event->type()) {
403 case QEvent::TouchBegin: {
404 d->position = ev->points().at(0).position();
405 q->setHotSpot(ev->points().at(0).globalPosition());
407 break;
408 }
410 case QEvent::TouchEnd: {
411 if (q->state() != Qt::NoGesture && ev->points().size() == 1) {
412 const QEventPoint &p = ev->points().at(0);
413 QPoint delta = p.position().toPoint() - p.pressPosition().toPoint();
414 enum { TapRadius = 40 };
415 if (delta.manhattanLength() <= TapRadius) {
416 if (event->type() == QEvent::TouchEnd)
418 else
420 }
421 }
422 break;
423 }
428 break;
429 default:
431 break;
432 }
433 return result;
434}
435
437{
438 QTapGesture *q = static_cast<QTapGesture *>(state);
439 QTapGesturePrivate *d = q->d_func();
440
441 d->position = QPointF();
442
444}
445
446//
447// QTapAndHoldGestureRecognizer
448//
449
451{
452}
453
455{
456 if (target && target->isWidgetType()) {
458 }
459 return new QTapAndHoldGesture;
460}
461
462QGestureRecognizer::Result
464 QEvent *event)
465{
466 QTapAndHoldGesture *q = static_cast<QTapAndHoldGesture *>(state);
467 QTapAndHoldGesturePrivate *d = q->d_func();
468
469 if (object == state && event->type() == QEvent::Timer) {
470 q->killTimer(d->timerId);
471 d->timerId = 0;
473 }
474
475 enum { TapRadius = 40 };
476
477 switch (event->type()) {
478#if QT_CONFIG(graphicsview)
480 const QGraphicsSceneMouseEvent *gsme = static_cast<const QGraphicsSceneMouseEvent *>(event);
481 d->position = gsme->screenPos();
482 q->setHotSpot(d->position);
483 if (d->timerId)
484 q->killTimer(d->timerId);
485 d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout);
486 return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
487 }
488#endif
490 const QMouseEvent *me = static_cast<const QMouseEvent *>(event);
491 d->position = me->globalPosition().toPoint();
492 q->setHotSpot(d->position);
493 if (d->timerId)
494 q->killTimer(d->timerId);
495 d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout);
496 return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
497 }
498 case QEvent::TouchBegin: {
499 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
500 d->position = ev->points().at(0).globalPressPosition();
501 q->setHotSpot(d->position);
502 if (d->timerId)
503 q->killTimer(d->timerId);
504 d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout);
505 return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
506 }
507#if QT_CONFIG(graphicsview)
509#endif
511 case QEvent::TouchEnd:
512 return QGestureRecognizer::CancelGesture; // get out of the MayBeGesture state
513 case QEvent::TouchUpdate: {
514 const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
515 if (d->timerId && ev->points().size() == 1) {
516 const QEventPoint &p = ev->points().at(0);
517 QPoint delta = p.position().toPoint() - p.pressPosition().toPoint();
518 if (delta.manhattanLength() <= TapRadius)
520 }
522 }
523 case QEvent::MouseMove: {
524 const QMouseEvent *me = static_cast<const QMouseEvent *>(event);
525 QPoint delta = me->globalPosition().toPoint() - d->position.toPoint();
526 if (d->timerId && delta.manhattanLength() <= TapRadius)
529 }
530#if QT_CONFIG(graphicsview)
532 const QGraphicsSceneMouseEvent *gsme = static_cast<const QGraphicsSceneMouseEvent *>(event);
533 QPoint delta = gsme->screenPos() - d->position.toPoint();
534 if (d->timerId && delta.manhattanLength() <= TapRadius)
537 }
538#endif
539 default:
541 }
542}
543
545{
546 QTapAndHoldGesture *q = static_cast<QTapAndHoldGesture *>(state);
547 QTapAndHoldGesturePrivate *d = q->d_func();
548
549 d->position = QPointF();
550 if (d->timerId)
551 q->killTimer(d->timerId);
552 d->timerId = 0;
553
555}
556
558
559#endif // QT_NO_GESTURES
The QEventPoint class provides information about a point in a QPointerEvent.
Definition qeventpoint.h:20
QPointF globalPosition
the global position of this point.
Definition qeventpoint.h:44
QPointF globalPressPosition
the global position at which this point was pressed.
Definition qeventpoint.h:45
QPointF position
the position of this point.
Definition qeventpoint.h:36
\inmodule QtCore
Definition qcoreevent.h:45
@ GraphicsSceneMouseMove
Definition qcoreevent.h:189
@ GraphicsSceneMouseRelease
Definition qcoreevent.h:191
@ GraphicsSceneMousePress
Definition qcoreevent.h:190
@ MouseMove
Definition qcoreevent.h:63
@ MouseButtonPress
Definition qcoreevent.h:60
@ TouchUpdate
Definition qcoreevent.h:242
@ TouchBegin
Definition qcoreevent.h:241
@ MouseButtonRelease
Definition qcoreevent.h:61
virtual void reset(QGesture *state)
This function is called by the framework to reset a given gesture.
The QGesture class represents a gesture, containing properties that describe the corresponding user i...
Definition qgesture.h:29
The QGraphicsSceneMouseEvent class provides mouse events in the graphics view framework.
QPoint screenPos() const
Returns the mouse cursor position in screen coordinates.
\inmodule QtCore
Definition qline.h:182
qreal angle() const
Definition qline.cpp:558
qreal length() const
Returns the length of the line.
Definition qline.cpp:542
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
T & first()
Definition qlist.h:628
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
\inmodule QtGui
Definition qevent.h:195
\inmodule QtCore
Definition qobject.h:90
QGesture * create(QObject *target) override
This function is called by Qt to create a new QGesture object for the given target (QWidget or QGraph...
void reset(QGesture *state) override
This function is called by the framework to reset a given gesture.
QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event) override
Handles the given event for the watched object, updating the state of the gesture object as required,...
The QPanGesture class describes a panning gesture made by the user.\inmodule QtWidgets.
Definition qgesture.h:73
QGesture * create(QObject *target) override
This function is called by Qt to create a new QGesture object for the given target (QWidget or QGraph...
QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event) override
Handles the given event for the watched object, updating the state of the gesture object as required,...
void reset(QGesture *state) override
This function is called by the framework to reset a given gesture.
The QPinchGesture class describes a pinch gesture made by the user.\inmodule QtWidgets.
Definition qgesture.h:103
@ RotationAngleChanged
Definition qgesture.h:110
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:338
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition qpoint.h:394
\inmodule QtCore\reentrant
Definition qpoint.h:23
constexpr int manhattanLength() const
Returns the sum of the absolute values of x() and y(), traditionally known as the "Manhattan length" ...
Definition qpoint.h:147
const QList< QEventPoint > & points() const
Returns a list of points in this pointer event.
Definition qevent.h:86
QPointF globalPosition() const
Returns the position of the point in this event on the screen or virtual desktop.
Definition qevent.h:122
qsizetype length() const
Returns the number of characters in this string.
Definition qstring.h:187
QGesture * create(QObject *target) override
This function is called by Qt to create a new QGesture object for the given target (QWidget or QGraph...
QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event) override
Handles the given event for the watched object, updating the state of the gesture object as required,...
void reset(QGesture *state) override
This function is called by the framework to reset a given gesture.
The QSwipeGesture class describes a swipe gesture made by the user.\inmodule QtWidgets.
Definition qgesture.h:177
SwipeDirection
This enum describes the possible directions for the gesture's motion along the horizontal and vertica...
Definition qgesture.h:187
void reset(QGesture *state) override
This function is called by the framework to reset a given gesture.
QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event) override
Handles the given event for the watched object, updating the state of the gesture object as required,...
QGesture * create(QObject *target) override
This function is called by Qt to create a new QGesture object for the given target (QWidget or QGraph...
The QTapAndHoldGesture class describes a tap-and-hold (aka LongTap) gesture made by the user....
Definition qgesture.h:222
void reset(QGesture *state) override
This function is called by the framework to reset a given gesture.
QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event) override
Handles the given event for the watched object, updating the state of the gesture object as required,...
QGesture * create(QObject *target) override
This function is called by Qt to create a new QGesture object for the given target (QWidget or QGraph...
The QTapGesture class describes a tap gesture made by the user.\inmodule QtWidgets.
Definition qgesture.h:204
The QTouchEvent class contains parameters that describe a touch event.
Definition qevent.h:916
QEventPoint::States touchPointStates() const
Returns a bitwise OR of all the touch point states for this event.
Definition qevent.h:935
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
QPixmap p2
QPixmap p1
[0]
else opt state
[0]
Combined button and popup list for selecting options.
@ WA_AcceptTouchEvents
Definition qnamespace.h:403
@ NoGesture
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLenum GLenum GLsizei count
GLsizei GLsizei GLfloat distance
GLfloat angle
GLenum target
struct _cl_event * event
GLsizei maxCount
Definition qopenglext.h:677
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
static QPointF panOffset(const QList< QEventPoint > &touchPoints, int maxCount)
static QT_BEGIN_NAMESPACE const qreal kSingleStepScaleMax
static const qreal kSingleStepScaleMin
double qreal
Definition qtypes.h:92
app setAttribute(Qt::AA_DontShowIconsInMenus)