summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/gestures/imageviewer/imagewidget.cpp6
-rw-r--r--src/gui/kernel/qstandardgestures.cpp153
-rw-r--r--src/gui/kernel/qstandardgestures.h14
-rw-r--r--src/gui/kernel/qstandardgestures_p.h16
-rw-r--r--tests/manual/gestures/pinch/pinchwidget.cpp4
5 files changed, 150 insertions, 43 deletions
diff --git a/examples/gestures/imageviewer/imagewidget.cpp b/examples/gestures/imageviewer/imagewidget.cpp
index 7dbd084..a4ea238 100644
--- a/examples/gestures/imageviewer/imagewidget.cpp
+++ b/examples/gestures/imageviewer/imagewidget.cpp
@@ -123,8 +123,10 @@ void ImageWidget::panTriggered()
void ImageWidget::pinchTriggered()
{
QPinchGesture *pg = qobject_cast<QPinchGesture*>(sender());
- rotationAngle += pg->rotationAngle();
- scaleFactor += pg->scaleFactor();
+ if (pg->rotationAngle() != 0.0)
+ rotationAngle += pg->rotationAngle() - pg->lastRotationAngle();
+ if (pg->scaleFactor() != 1.0)
+ scaleFactor += pg->scaleFactor() - pg->lastScaleFactor();
update();
}
diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp
index f6534d1..783c1d3 100644
--- a/src/gui/kernel/qstandardgestures.cpp
+++ b/src/gui/kernel/qstandardgestures.cpp
@@ -47,6 +47,7 @@
#include <private/qapplication_p.h>
#include <private/qevent_p.h>
#include <private/qwidget_p.h>
+#include <qmath.h>
QT_BEGIN_NAMESPACE
@@ -172,11 +173,12 @@ bool QPanGesture::eventFilter(QObject *receiver, QEvent *event)
return false;
}
if (state() == Qt::NoGesture) {
- d->lastOffset = d->totalOffset = QSize();
+ d->lastOffset = d->totalOffset = d->offset = QSize();
} else {
- d->lastOffset = QSize(ev->position.x() - d->lastPosition.x(),
- ev->position.y() - d->lastPosition.y());
- d->totalOffset += d->lastOffset;
+ d->lastOffset = d->offset;
+ d->offset = QSize(ev->position.x() - d->lastPosition.x(),
+ ev->position.y() - d->lastPosition.y());
+ d->totalOffset += d->offset;
}
d->lastPosition = ev->position;
updateState(nextState);
@@ -201,16 +203,17 @@ bool QPanGesture::filterEvent(QEvent *event)
if (event->type() == QEvent::TouchBegin) {
QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
d->lastPosition = p.pos().toPoint();
- d->lastOffset = d->totalOffset = QSize();
+ d->lastOffset = d->totalOffset = d->offset = QSize();
} else if (event->type() == QEvent::TouchEnd) {
if (state() != Qt::NoGesture) {
if (ev->touchPoints().size() == 2) {
QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
- d->lastOffset =
+ d->lastOffset = d->offset;
+ d->offset =
QSize(p1.pos().x() - p1.lastPos().x() + p2.pos().x() - p2.lastPos().x(),
p1.pos().y() - p1.lastPos().y() + p2.pos().y() - p2.lastPos().y()) / 2;
- d->totalOffset += d->lastOffset;
+ d->totalOffset += d->offset;
}
updateState(Qt::GestureFinished);
}
@@ -219,10 +222,11 @@ bool QPanGesture::filterEvent(QEvent *event)
if (ev->touchPoints().size() == 2) {
QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
- d->lastOffset =
+ d->lastOffset = d->offset;
+ d->offset =
QSize(p1.pos().x() - p1.lastPos().x() + p2.pos().x() - p2.lastPos().x(),
p1.pos().y() - p1.lastPos().y() + p2.pos().y() - p2.lastPos().y()) / 2;
- d->totalOffset += d->lastOffset;
+ d->totalOffset += d->offset;
if (d->totalOffset.width() > 10 || d->totalOffset.height() > 10 ||
d->totalOffset.width() < -10 || d->totalOffset.height() < -10) {
updateState(Qt::GestureUpdated);
@@ -264,8 +268,9 @@ bool QPanGesture::filterEvent(QEvent *event)
QPointF mousePos = QCursor::pos();
QPointF dist = mousePos - d->lastPosition;
d->lastPosition = mousePos;
- d->lastOffset = QSizeF(dist.x(), dist.y());
- d->totalOffset += d->lastOffset;
+ d->lastOffset = d->offset;
+ d->offset = QSizeF(dist.x(), dist.y());
+ d->totalOffset += d->offset;
updateState(Qt::GestureUpdated);
}
} else if (state() == Qt::NoGesture) {
@@ -285,7 +290,7 @@ bool QPanGesture::filterEvent(QEvent *event)
void QPanGesture::reset()
{
Q_D(QPanGesture);
- d->lastOffset = d->totalOffset = QSize(0, 0);
+ d->lastOffset = d->totalOffset = d->offset = QSize(0, 0);
d->lastPosition = QPoint(0, 0);
#if defined(QT_MAC_USE_COCOA)
@@ -310,8 +315,7 @@ QSizeF QPanGesture::totalOffset() const
/*!
\property QPanGesture::lastOffset
- Specifies a pan offset since the last time the gesture was
- triggered.
+ Specifies a pan offset the last time the gesture was triggered.
*/
QSizeF QPanGesture::lastOffset() const
{
@@ -319,6 +323,18 @@ QSizeF QPanGesture::lastOffset() const
return d->lastOffset;
}
+/*!
+ \property QPanGesture::offset
+
+ Specifies the current pan offset since the last time the gesture was
+ triggered.
+*/
+QSizeF QPanGesture::offset() const
+{
+ Q_D(const QPanGesture);
+ return d->offset;
+}
+
//////////////////////////////////////////////////////////////////////////////
/*!
@@ -397,37 +413,75 @@ bool QPinchGesture::eventFilter(QObject *receiver, QEvent *event)
// next we might receive the first gesture update event, so we
// prepare for it.
d->state = Qt::NoGesture;
- d->scaleFactor = d->lastScaleFactor = 1;
- d->rotationAngle = d->lastRotationAngle = 0;
+ d->totalScaleFactor = d->scaleFactor = d->lastScaleFactor = 1.;
+ d->totalRotationAngle = d->rotationAngle = d->lastRotationAngle = 0.;
d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPointF();
#if defined(Q_WS_WIN)
d->initialDistance = 0;
+ d->lastSequenceId = ev->sequenceId;
#endif
return false;
- case QNativeGestureEvent::Rotate:
- d->scaleFactor = 0;
+ case QNativeGestureEvent::Rotate: {
+ d->lastScaleFactor = d->scaleFactor;
d->lastRotationAngle = d->rotationAngle;
-#if defined(Q_WS_WIN)
- d->rotationAngle = -1 * GID_ROTATE_ANGLE_FROM_ARGUMENT(ev->argument);
-#elif defined(Q_WS_MAC)
- d->rotationAngle = ev->percentage;
-#endif
+#if defined(Q_WS_MAC)
+ d->rotationAngle += ev->percentage;
nextState = Qt::GestureUpdated;
+#elif defined(Q_WS_WIN)
+ // This is a workaround for an issue with the native rotation
+ // gesture on Windows 7. For some reason the rotation angle in the
+ // first WM_GESTURE message in a sequence contains value that is
+ // off a little bit and causes the rotating item to "jump", so
+ // we just ignore the first WM_GESTURE in every sequence.
+ bool windowsRotateWorkaround = false;
+ if (!d->lastSequenceId) {
+ windowsRotateWorkaround = true;
+ d->lastSequenceId = ev->sequenceId;
+ }
+ if (d->lastSequenceId > 0 && d->lastSequenceId != (ulong)-1 && ev->sequenceId != d->lastSequenceId) {
+ // this is the first WM_GESTURE message in a sequence.
+ d->totalRotationAngle += d->rotationAngle;
+ windowsRotateWorkaround = true;
+ // a magic value to mark that the next WM_GESTURE message is
+ // the second message in a sequence and we should clear the
+ // lastRotationAngle
+ d->lastSequenceId = (ulong)-1;
+ }
+ if (!windowsRotateWorkaround) {
+ d->rotationAngle = -1 * GID_ROTATE_ANGLE_FROM_ARGUMENT(ev->argument) * 180. / M_PI;
+ if (d->lastSequenceId == (ulong)-1) {
+ // a special case since we need to set the lastRotationAngle to
+ // rotationAngle when the first WM_GESTURE is received in each
+ // sequence.
+ d->lastRotationAngle = d->rotationAngle;
+ }
+ d->lastSequenceId = ev->sequenceId;
+ }
+ if (!windowsRotateWorkaround)
+ nextState = Qt::GestureUpdated;
+#endif
event->accept();
break;
+ }
case QNativeGestureEvent::Zoom:
- d->rotationAngle = 0;
+ d->lastRotationAngle = d->rotationAngle;
+ d->lastScaleFactor = d->scaleFactor;
#if defined(Q_WS_WIN)
if (d->initialDistance != 0) {
- d->lastScaleFactor = d->scaleFactor;
int distance = int(qint64(ev->argument));
- d->scaleFactor = (qreal) distance / d->initialDistance;
+ if (d->lastSequenceId && ev->sequenceId != d->lastSequenceId) {
+ d->totalScaleFactor *= d->scaleFactor;
+ d->initialDistance = int(qint64(ev->argument));
+ d->lastScaleFactor = d->scaleFactor = (qreal) distance / d->initialDistance;
+ } else {
+ d->scaleFactor = (qreal) distance / d->initialDistance;
+ }
+ d->lastSequenceId = ev->sequenceId;
} else {
d->initialDistance = int(qint64(ev->argument));
}
#elif defined(Q_WS_MAC)
- d->lastScaleFactor = d->scaleFactor;
- d->scaleFactor = ev->percentage;
+ d->scaleFactor += ev->percentage;
#endif
nextState = Qt::GestureUpdated;
event->accept();
@@ -469,16 +523,33 @@ bool QPinchGesture::filterEvent(QEvent *event)
void QPinchGesture::reset()
{
Q_D(QPinchGesture);
- d->scaleFactor = d->lastScaleFactor = 0;
- d->rotationAngle = d->lastRotationAngle = 0;
+ d->totalScaleFactor = d->scaleFactor = d->lastScaleFactor = 1.;
+ d->totalRotationAngle = d->rotationAngle = d->lastRotationAngle = 0.;
d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPointF();
QGesture::reset();
}
/*!
+ \property QPinchGesture::totalScaleFactor
+
+ Specifies a total scale factor of the pinch gesture since the gesture
+ started.
+*/
+qreal QPinchGesture::totalScaleFactor() const
+{
+ Q_D(const QPinchGesture);
+ return d->totalScaleFactor * d->scaleFactor;
+}
+
+/*!
\property QPinchGesture::scaleFactor
Specifies a scale factor of the pinch gesture.
+
+ If the gesture consists of several pinch sequences (i.e. zoom and rotate
+ sequences), then this property specifies the scale factor in the current
+ sequence. When pinching changes the rotation angle only, the value of this
+ property is 1.
*/
qreal QPinchGesture::scaleFactor() const
{
@@ -496,9 +567,29 @@ qreal QPinchGesture::lastScaleFactor() const
}
/*!
+ \property QPinchGesture::totalRotationAngle
+
+ Specifies a total rotation angle of the gesture since the gesture started.
+
+ The angle is specified in degrees.
+*/
+qreal QPinchGesture::totalRotationAngle() const
+{
+ Q_D(const QPinchGesture);
+ return d->totalRotationAngle + d->rotationAngle;
+}
+
+/*!
\property QPinchGesture::rotationAngle
Specifies a rotation angle of the gesture.
+
+ If the gesture consists of several pinch sequences (i.e. zoom and rotate
+ sequences), then this property specifies the rotation angle in the current
+ sequence. When pinching changes the scale factor only, the value of this
+ property is 0.
+
+ The angle is specified in degrees.
*/
qreal QPinchGesture::rotationAngle() const
{
@@ -509,6 +600,8 @@ qreal QPinchGesture::rotationAngle() const
\property QPinchGesture::lastRotationAngle
Specifies a previous rotation angle of the gesture.
+
+ The angle is specified in degrees.
*/
qreal QPinchGesture::lastRotationAngle() const
{
diff --git a/src/gui/kernel/qstandardgestures.h b/src/gui/kernel/qstandardgestures.h
index 33166fe..c6dfa92 100644
--- a/src/gui/kernel/qstandardgestures.h
+++ b/src/gui/kernel/qstandardgestures.h
@@ -61,6 +61,7 @@ class Q_GUI_EXPORT QPanGesture : public QGesture
Q_PROPERTY(QSizeF totalOffset READ totalOffset)
Q_PROPERTY(QSizeF lastOffset READ lastOffset)
+ Q_PROPERTY(QSizeF offset READ offset)
public:
QPanGesture(QWidget *gestureTarget, QObject *parent = 0);
@@ -69,6 +70,7 @@ public:
QSizeF totalOffset() const;
QSizeF lastOffset() const;
+ QSizeF offset() const;
protected:
void reset();
@@ -87,11 +89,13 @@ class Q_GUI_EXPORT QPinchGesture : public QGesture
Q_OBJECT
Q_DECLARE_PRIVATE(QPinchGesture)
- Q_PROPERTY(qreal scaleFactor READ scaleFactor)
+ Q_PROPERTY(qreal totalScaleFactor READ totalScaleFactor)
Q_PROPERTY(qreal lastScaleFactor READ lastScaleFactor)
+ Q_PROPERTY(qreal scaleFactor READ scaleFactor)
- Q_PROPERTY(qreal rotationAngle READ rotationAngle)
+ Q_PROPERTY(qreal totalRotationAngle READ totalRotationAngle)
Q_PROPERTY(qreal lastRotationAngle READ lastRotationAngle)
+ Q_PROPERTY(qreal rotationAngle READ rotationAngle)
Q_PROPERTY(QPointF startCenterPoint READ startCenterPoint)
Q_PROPERTY(QPointF lastCenterPoint READ lastCenterPoint)
@@ -107,11 +111,13 @@ public:
QPointF lastCenterPoint() const;
QPointF centerPoint() const;
- qreal scaleFactor() const;
+ qreal totalScaleFactor() const;
qreal lastScaleFactor() const;
+ qreal scaleFactor() const;
- qreal rotationAngle() const;
+ qreal totalRotationAngle() const;
qreal lastRotationAngle() const;
+ qreal rotationAngle() const;
private:
bool event(QEvent *event);
diff --git a/src/gui/kernel/qstandardgestures_p.h b/src/gui/kernel/qstandardgestures_p.h
index 270f307..9e23515 100644
--- a/src/gui/kernel/qstandardgestures_p.h
+++ b/src/gui/kernel/qstandardgestures_p.h
@@ -74,6 +74,7 @@ public:
QSizeF totalOffset;
QSizeF lastOffset;
+ QSizeF offset;
QPointF lastPosition;
#if defined(QT_MAC_USE_COCOA)
@@ -88,25 +89,30 @@ class QPinchGesturePrivate : public QGesturePrivate
public:
QPinchGesturePrivate()
- : scaleFactor(0), lastScaleFactor(0),
- rotationAngle(0), lastRotationAngle(0)
+ : totalScaleFactor(0.), lastScaleFactor(0.), scaleFactor(0.),
+ totalRotationAngle(0.), lastRotationAngle(0.), rotationAngle(0.)
#ifdef Q_WS_WIN
- ,initialDistance(0)
+ ,initialDistance(0), lastSequenceId(0)
#endif
{
}
void setupGestureTarget(QObject *o);
- qreal scaleFactor;
+ qreal totalScaleFactor; // total scale factor, excluding the current sequence.
qreal lastScaleFactor;
- qreal rotationAngle;
+ qreal scaleFactor; // scale factor in the current sequence.
+
+ qreal totalRotationAngle; // total rotation angle, excluding the current sequence.
qreal lastRotationAngle;
+ qreal rotationAngle; // rotation angle in the current sequence.
+
QPointF startCenterPoint;
QPointF lastCenterPoint;
QPointF centerPoint;
#ifdef Q_WS_WIN
int initialDistance;
+ ulong lastSequenceId;
#endif
};
diff --git a/tests/manual/gestures/pinch/pinchwidget.cpp b/tests/manual/gestures/pinch/pinchwidget.cpp
index aa11f8d..cc16443 100644
--- a/tests/manual/gestures/pinch/pinchwidget.cpp
+++ b/tests/manual/gestures/pinch/pinchwidget.cpp
@@ -104,8 +104,8 @@ void PinchWidget::onPinchTriggered()
QPoint transformCenter = worldTransform.map(QPoint(width()/2, height()/2));
currentPinchTransform = QTransform()
.translate(transformCenter.x(), transformCenter.y())
- .scale(pinch->scaleFactor(), pinch->scaleFactor())
- .rotateRadians(pinch->rotationAngle())
+ .scale(pinch->totalScaleFactor(), pinch->totalScaleFactor())
+ .rotate(pinch->totalRotationAngle())
.translate(-transformCenter.x(), -transformCenter.y());
update();
}