aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/handlers/qquickpinchhandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/handlers/qquickpinchhandler.cpp')
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp168
1 files changed, 137 insertions, 31 deletions
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index 3cd99fe1a2..84c4e912d1 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -55,6 +55,7 @@ Q_LOGGING_CATEGORY(lcPinchHandler, "qt.quick.handler.pinch")
/*!
\qmltype PinchHandler
\instantiates QQuickPinchHandler
+ \inherits MultiPointHandler
\inqmlmodule Qt.labs.handlers
\ingroup qtquick-handlers
\brief Handler for pinch gestures
@@ -242,6 +243,28 @@ void QQuickPinchHandler::setMaximumY(qreal maxY)
emit maximumYChanged();
}
+bool QQuickPinchHandler::wantsPointerEvent(QQuickPointerEvent *event)
+{
+ if (!QQuickMultiPointHandler::wantsPointerEvent(event))
+ return false;
+
+ if (minimumPointCount() == 2) {
+ if (const auto gesture = event->asPointerNativeGestureEvent()) {
+ switch (gesture->type()) {
+ case Qt::BeginNativeGesture:
+ case Qt::EndNativeGesture:
+ case Qt::ZoomNativeGesture:
+ case Qt::RotateNativeGesture:
+ return parentContains(event->point(0));
+ default:
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
/*!
\qmlproperty int QtQuick::PinchHandler::minimumTouchPoints
@@ -288,51 +311,87 @@ void QQuickPinchHandler::onActiveChanged()
void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
{
- Q_UNUSED(event)
if (Q_UNLIKELY(lcPinchHandler().isDebugEnabled())) {
for (QQuickEventPoint *point : qAsConst(m_currentPoints))
qCDebug(lcPinchHandler) << point->state() << point->sceneGrabPosition() << "->" << point->scenePosition();
}
- bool containsReleasedPoints = event->isReleaseEvent();
- if (!active() && !containsReleasedPoints) {
- // Verify that least one of the points have moved beyond threshold needed to activate the handler
- for (QQuickEventPoint *point : qAsConst(m_currentPoints)) {
- if (QQuickWindowPrivate::dragOverThreshold(point)) {
- if (grabPoints(m_currentPoints))
- setActive(true);
- break;
+ qreal dist = 0;
+ if (const auto gesture = event->asPointerNativeGestureEvent()) {
+ switch (gesture->type()) {
+ case Qt::EndNativeGesture:
+ m_activeScale = 1;
+ m_activeRotation = 0;
+ m_activeTranslation = QVector2D();
+ m_centroid = QPointF();
+ m_centroidVelocity = QVector2D();
+ setActive(false);
+ emit updated();
+ return;
+ case Qt::ZoomNativeGesture:
+ m_activeScale *= 1 + gesture->value();
+ break;
+ case Qt::RotateNativeGesture:
+ m_activeRotation += gesture->value();
+ break;
+ default:
+ // Nothing of interest (which is unexpected, because wantsPointerEvent() should have returned false)
+ return;
+ }
+ if (!active()) {
+ m_centroid = gesture->point(0)->scenePosition();
+ setActive(true);
+ m_startCentroid = m_centroid;
+ // Native gestures for 2-finger pinch do not allow dragging, so
+ // the centroid won't move during the gesture, and translation stays at zero
+ m_centroidVelocity = QVector2D();
+ m_activeTranslation = QVector2D();
+ }
+ } else {
+ bool containsReleasedPoints = event->isReleaseEvent();
+ if (!active() && !containsReleasedPoints) {
+ // Verify that at least one of the points has moved beyond threshold needed to activate the handler
+ for (QQuickEventPoint *point : qAsConst(m_currentPoints)) {
+ if (QQuickWindowPrivate::dragOverThreshold(point)) {
+ if (grabPoints(m_currentPoints))
+ setActive(true);
+ break;
+ }
}
+ if (!active())
+ return;
}
- if (!active())
- return;
+ // TODO check m_pinchOrigin: right now it acts like it's set to PinchCenter
+ m_centroid = touchPointCentroid();
+ m_centroidVelocity = touchPointCentroidVelocity();
+ // avoid mapping the minima and maxima, as they might have unmappable values
+ // such as -inf/+inf. Because of this we perform the bounding to min/max in local coords.
+ // 1. scale
+ dist = averageTouchPointDistance(m_centroid);
+ m_activeScale = dist / m_startDistance;
+ m_activeScale = qBound(m_minimumScale/m_startScale, m_activeScale, m_maximumScale/m_startScale);
+
+ // 2. rotate
+ QVector<PointData> newAngles = angles(m_centroid);
+ const qreal angleDelta = averageAngleDelta(m_startAngles, newAngles);
+ m_activeRotation += angleDelta;
+ m_startAngles = std::move(newAngles);
+
+ if (!containsReleasedPoints)
+ acceptPoints(m_currentPoints);
}
- // TODO check m_pinchOrigin: right now it acts like it's set to PinchCenter
- m_centroid = touchPointCentroid();
- m_centroidVelocity = touchPointCentroidVelocity();
- QRectF bounds(m_minimumX, m_minimumY, m_maximumX - m_minimumX, m_maximumY - m_minimumY);
- // avoid mapping the minima and maxima, as they might have unmappable values
- // such as -inf/+inf. Because of this we perform the bounding to min/max in local coords.
+
QPointF centroidParentPos;
+ QRectF bounds(m_minimumX, m_minimumY, m_maximumX - m_minimumX, m_maximumY - m_minimumY);
if (target() && target()->parentItem()) {
centroidParentPos = target()->parentItem()->mapFromScene(m_centroid);
centroidParentPos = QPointF(qBound(bounds.left(), centroidParentPos.x(), bounds.right()),
qBound(bounds.top(), centroidParentPos.y(), bounds.bottom()));
}
- // 1. scale
- const qreal dist = averageTouchPointDistance(m_centroid);
- m_activeScale = dist / m_startDistance;
- m_activeScale = qBound(m_minimumScale/m_startScale, m_activeScale, m_maximumScale/m_startScale);
- const qreal scale = m_startScale * m_activeScale;
-
- // 2. rotate
- QVector<PointData> newAngles = angles(m_centroid);
- const qreal angleDelta = averageAngleDelta(m_startAngles, newAngles);
- m_activeRotation += angleDelta;
const qreal totalRotation = m_startRotation + m_activeRotation;
const qreal rotation = qBound(m_minimumRotation, totalRotation, m_maximumRotation);
m_activeRotation += (rotation - totalRotation); //adjust for the potential bounding above
- m_startAngles = std::move(newAngles);
+ const qreal scale = m_startScale * m_activeScale;
if (target() && target()->parentItem()) {
// 3. Drag/translate
@@ -363,15 +422,62 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
} else {
m_activeTranslation = QVector2D(m_centroid - m_startCentroid);
}
+
qCDebug(lcPinchHandler) << "centroid" << m_startCentroid << "->" << m_centroid
<< ", distance" << m_startDistance << "->" << dist
<< ", startScale" << m_startScale << "->" << scale
<< ", activeRotation" << m_activeRotation
- << ", rotation" << rotation;
+ << ", rotation" << rotation
+ << " from " << event->device()->type();
- if (!containsReleasedPoints)
- acceptPoints(m_currentPoints);
emit updated();
}
+/*!
+ \readonly
+ \qmlproperty QPointF QtQuick::PinchHandler::centroid
+
+ A point exactly in the middle of the currently-pressed touch points.
+ If \l pinchOrigin is set to \c PinchCenter, the \l target will be rotated
+ around this point.
+*/
+
+/*!
+ \readonly
+ \qmlproperty QVector2D QtQuick::PinchHandler::centroidVelocity
+
+ The average velocity of the \l centroid: a vector representing the speed
+ and direction of movement of the whole group of touchpoints, in logical
+ pixels per second.
+*/
+
+/*!
+ \readonly
+ \qmlproperty real QtQuick::PinchHandler::scale
+
+ The scale factor. It is 1.0 when the gesture begins, increases as the
+ touchpoints are spread apart, and decreases as the touchpoints are brought
+ together. If \l target is not null, this will be automatically applied to its
+ \l {Item::scale}{scale}. Otherwise, bindings can be used to do arbitrary
+ things with this value.
+*/
+
+/*!
+ \readonly
+ \qmlproperty real QtQuick::PinchHandler::rotation
+
+ The rotation of the pinch gesture in degrees, with positive values clockwise.
+ It is 0 when the gesture begins. If \l target is not null, this will be
+ automatically applied to its \l {Item::rotation}{rotation}. Otherwise,
+ bindings can be used to do arbitrary things with this value.
+*/
+
+/*!
+ \readonly
+ \qmlproperty QVector2D QtQuick::PinchHandler::translation
+
+ The translation of the gesture \l centroid. It is \c (0, 0) when the
+ gesture begins.
+*/
+
QT_END_NAMESPACE