diff options
-rw-r--r-- | src/quick/handlers/qquickhandlerpoint.cpp | 83 | ||||
-rw-r--r-- | src/quick/handlers/qquickhandlerpoint_p.h | 5 | ||||
-rw-r--r-- | src/quick/handlers/qquickmultipointhandler.cpp | 35 | ||||
-rw-r--r-- | src/quick/handlers/qquickmultipointhandler_p.h | 10 | ||||
-rw-r--r-- | src/quick/handlers/qquickpinchhandler.cpp | 37 | ||||
-rw-r--r-- | src/quick/handlers/qquickpinchhandler_p.h | 8 | ||||
-rw-r--r-- | src/quick/handlers/qquicksinglepointhandler.cpp | 31 | ||||
-rw-r--r-- | tests/manual/pointer/pinchDragFlingMPTA.qml | 2 | ||||
-rw-r--r-- | tests/manual/pointer/pinchHandler.qml | 6 |
9 files changed, 126 insertions, 91 deletions
diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp index 45c85f88fc..6c7bf2fc8a 100644 --- a/src/quick/handlers/qquickhandlerpoint.cpp +++ b/src/quick/handlers/qquickhandlerpoint.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qquickhandlerpoint_p.h" +#include "private/qquickevents_p_p.h" QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH_TARGET) @@ -93,6 +94,88 @@ void QQuickHandlerPoint::reset() m_pressedButtons = Qt::NoButton; } +void QQuickHandlerPoint::reset(const QQuickEventPoint *point) +{ + m_id = point->pointId(); + const QQuickPointerEvent *event = point->pointerEvent(); + switch (point->state()) { + case QQuickEventPoint::Pressed: + m_pressPosition = point->position(); + m_scenePressPosition = point->scenePosition(); + m_pressedButtons = event->buttons(); + break; + case QQuickEventPoint::Released: + reset(); + return; + default: + m_pressedButtons = event->buttons(); + break; + } + if (event->asPointerTouchEvent()) { + const QQuickEventTouchPoint *tp = static_cast<const QQuickEventTouchPoint *>(point); + m_uniqueId = tp->uniqueId(); + m_rotation = tp->rotation(); + m_pressure = tp->pressure(); + m_ellipseDiameters = tp->ellipseDiameters(); + } else if (event->asPointerTabletEvent()) { + // TODO + } else { + m_uniqueId = event->device()->uniqueId(); + m_rotation = 0; + m_pressure = event->buttons() ? 1 : 0; + m_ellipseDiameters = QSizeF(); + } + m_position = point->position(); + m_scenePosition = point->scenePosition(); + if (point->state() == QQuickEventPoint::Updated) + m_velocity = point->velocity(); +} + +void QQuickHandlerPoint::reset(const QVector<QQuickEventPoint *> &points) +{ + if (points.isEmpty()) { + qWarning("reset: no points"); + return; + } + if (points.count() == 1) { + reset(points.first()); + return; + } + // all points are required to be from the same event + const QQuickPointerEvent *event = points.first()->pointerEvent(); + QPointF posSum; + QPointF scenePosSum; + QVector2D velocitySum; + qreal pressureSum = 0; + QSizeF ellipseDiameterSum; + bool press = false; + const QQuickPointerTouchEvent *touchEvent = event->asPointerTouchEvent(); + for (const QQuickEventPoint *point : qAsConst(points)) { + posSum += point->position(); + scenePosSum += point->scenePosition(); + velocitySum += point->velocity(); + if (touchEvent) { + pressureSum += static_cast<const QQuickEventTouchPoint *>(point)->pressure(); + ellipseDiameterSum += static_cast<const QQuickEventTouchPoint *>(point)->ellipseDiameters(); + } + if (point->state() == QQuickEventPoint::Pressed) + press = true; + } + m_id = 0; + m_uniqueId = QPointingDeviceUniqueId(); + m_pressedButtons = event->buttons(); + m_position = posSum / points.size(); + m_scenePosition = scenePosSum / points.size(); + if (press) { + m_pressPosition = m_position; + m_scenePressPosition = m_scenePosition; + } + m_velocity = velocitySum / points.size(); + m_rotation = 0; // averaging the rotations of all the points isn't very sensible + m_pressure = pressureSum / points.size(); + m_ellipseDiameters = ellipseDiameterSum / points.size(); +} + /*! \readonly \qmlproperty int QtQuick::HandlerPoint::id diff --git a/src/quick/handlers/qquickhandlerpoint_p.h b/src/quick/handlers/qquickhandlerpoint_p.h index b390b9b6f7..bdf7ae0d9d 100644 --- a/src/quick/handlers/qquickhandlerpoint_p.h +++ b/src/quick/handlers/qquickhandlerpoint_p.h @@ -89,8 +89,11 @@ public: QSizeF ellipseDiameters() const { return m_ellipseDiameters; } QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; } -private: void reset(); + void reset(const QQuickEventPoint *point); + void reset(const QVector<QQuickEventPoint *> &points); + +private: int m_id; QPointingDeviceUniqueId m_uniqueId; Qt::MouseButtons m_pressedButtons; diff --git a/src/quick/handlers/qquickmultipointhandler.cpp b/src/quick/handlers/qquickmultipointhandler.cpp index d595b4c9b4..89733a4260 100644 --- a/src/quick/handlers/qquickmultipointhandler.cpp +++ b/src/quick/handlers/qquickmultipointhandler.cpp @@ -91,6 +91,20 @@ bool QQuickMultiPointHandler::wantsPointerEvent(QQuickPointerEvent *event) return ret; } +void QQuickMultiPointHandler::handlePointerEventImpl(QQuickPointerEvent *event) +{ + QQuickPointerHandler::handlePointerEventImpl(event); + m_centroid.reset(m_currentPoints); + emit centroidChanged(); +} + +void QQuickMultiPointHandler::onActiveChanged() +{ + if (active()) { + m_centroid.m_sceneGrabPosition = m_centroid.m_scenePosition; + } +} + QVector<QQuickEventPoint *> QQuickMultiPointHandler::eligiblePoints(QQuickPointerEvent *event) { QVector<QQuickEventPoint *> ret; @@ -207,27 +221,6 @@ bool QQuickMultiPointHandler::sameAsCurrentPoints(QQuickPointerEvent *event) return ret; } -// TODO make templates for these functions somehow? -QPointF QQuickMultiPointHandler::touchPointCentroid() -{ - QPointF ret; - if (Q_UNLIKELY(m_currentPoints.size() == 0)) - return ret; - for (QQuickEventPoint *point : qAsConst(m_currentPoints)) - ret += point->scenePosition(); - return ret / m_currentPoints.size(); -} - -QVector2D QQuickMultiPointHandler::touchPointCentroidVelocity() -{ - QVector2D ret; - if (Q_UNLIKELY(m_currentPoints.size() == 0)) - return ret; - for (QQuickEventPoint *point : qAsConst(m_currentPoints)) - ret += point->velocity(); - return ret / m_currentPoints.size(); -} - qreal QQuickMultiPointHandler::averageTouchPointDistance(const QPointF &ref) { qreal ret = 0; diff --git a/src/quick/handlers/qquickmultipointhandler_p.h b/src/quick/handlers/qquickmultipointhandler_p.h index 67e550d387..5a44866e67 100644 --- a/src/quick/handlers/qquickmultipointhandler_p.h +++ b/src/quick/handlers/qquickmultipointhandler_p.h @@ -53,6 +53,7 @@ #include "qquickitem.h" #include "qevent.h" +#include "qquickhandlerpoint_p.h" #include "qquickpointerdevicehandler_p.h" QT_BEGIN_NAMESPACE @@ -63,6 +64,7 @@ class Q_AUTOTEST_EXPORT QQuickMultiPointHandler : public QQuickPointerDeviceHand Q_PROPERTY(int minimumPointCount READ minimumPointCount WRITE setMinimumPointCount NOTIFY minimumPointCountChanged) Q_PROPERTY(int maximumPointCount READ maximumPointCount WRITE setMaximumPointCount NOTIFY maximumPointCountChanged) Q_PROPERTY(qreal pointDistanceThreshold READ pointDistanceThreshold WRITE setPointDistanceThreshold NOTIFY pointDistanceThresholdChanged) + Q_PROPERTY(QQuickHandlerPoint centroid READ centroid NOTIFY centroidChanged) public: explicit QQuickMultiPointHandler(QObject *parent = nullptr, int minimumPointCount = 2); @@ -77,10 +79,13 @@ public: qreal pointDistanceThreshold() const { return m_pointDistanceThreshold; } void setPointDistanceThreshold(qreal pointDistanceThreshold); + QQuickHandlerPoint centroid() const { return m_centroid; } + signals: void minimumPointCountChanged(); void maximumPointCountChanged(); void pointDistanceThresholdChanged(); + void centroidChanged(); protected: struct PointData { @@ -91,10 +96,10 @@ protected: }; bool wantsPointerEvent(QQuickPointerEvent *event) override; + void handlePointerEventImpl(QQuickPointerEvent *event) override; + void onActiveChanged() override; bool sameAsCurrentPoints(QQuickPointerEvent *event); QVector<QQuickEventPoint *> eligiblePoints(QQuickPointerEvent *event); - QPointF touchPointCentroid(); - QVector2D touchPointCentroidVelocity(); qreal averageTouchPointDistance(const QPointF &ref); qreal averageStartingDistance(const QPointF &ref); qreal averageTouchPointAngle(const QPointF &ref); @@ -106,6 +111,7 @@ protected: protected: QVector<QQuickEventPoint *> m_currentPoints; + QQuickHandlerPoint m_centroid; int m_minimumPointCount; int m_maximumPointCount; qreal m_pointDistanceThreshold; diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp index fc69accffc..7dafb16d3f 100644 --- a/src/quick/handlers/qquickpinchhandler.cpp +++ b/src/quick/handlers/qquickpinchhandler.cpp @@ -287,11 +287,11 @@ bool QQuickPinchHandler::wantsPointerEvent(QQuickPointerEvent *event) void QQuickPinchHandler::onActiveChanged() { + QQuickMultiPointHandler::onActiveChanged(); if (active()) { m_startMatrix = QMatrix4x4(); - m_startCentroid = touchPointCentroid(); - m_startAngles = angles(m_startCentroid); - m_startDistance = averageTouchPointDistance(m_startCentroid); + m_startAngles = angles(m_centroid.sceneGrabPosition()); + m_startDistance = averageTouchPointDistance(m_centroid.sceneGrabPosition()); m_activeRotation = 0; m_activeTranslation = QVector2D(); if (const QQuickItem *t = target()) { @@ -319,6 +319,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) for (QQuickEventPoint *point : qAsConst(m_currentPoints)) qCDebug(lcPinchHandler) << point->state() << point->sceneGrabPosition() << "->" << point->scenePosition(); } + QQuickMultiPointHandler::handlePointerEventImpl(event); qreal dist = 0; #if QT_CONFIG(gestures) @@ -328,8 +329,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) m_activeScale = 1; m_activeRotation = 0; m_activeTranslation = QVector2D(); - m_centroid = QPointF(); - m_centroidVelocity = QVector2D(); + m_centroid.reset(); setActive(false); emit updated(); return; @@ -344,12 +344,9 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) 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 @@ -374,17 +371,15 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) 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); + dist = averageTouchPointDistance(m_centroid.scenePosition()); 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); + QVector<PointData> newAngles = angles(m_centroid.scenePosition()); const qreal angleDelta = averageAngleDelta(m_startAngles, newAngles); m_activeRotation += angleDelta; m_startAngles = std::move(newAngles); @@ -396,7 +391,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) 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 = target()->parentItem()->mapFromScene(m_centroid.scenePosition()); centroidParentPos = QPointF(qBound(bounds.left(), centroidParentPos.x(), bounds.right()), qBound(bounds.top(), centroidParentPos.y(), bounds.bottom())); } @@ -407,9 +402,8 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) if (target() && target()->parentItem()) { // 3. Drag/translate - const QPointF centroidStartParentPos = target()->parentItem()->mapFromScene(m_startCentroid); + const QPointF centroidStartParentPos = target()->parentItem()->mapFromScene(m_centroid.sceneGrabPosition()); m_activeTranslation = QVector2D(centroidParentPos - centroidStartParentPos); - // apply rotation + scaling around the centroid - then apply translation. QMatrix4x4 mat; @@ -432,10 +426,10 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) // TODO some translation inadvertently happens; try to hold the chosen pinch origin in place } else { - m_activeTranslation = QVector2D(m_centroid - m_startCentroid); + m_activeTranslation = QVector2D(m_centroid.scenePosition() - m_centroid.scenePressPosition()); } - qCDebug(lcPinchHandler) << "centroid" << m_startCentroid << "->" << m_centroid + qCDebug(lcPinchHandler) << "centroid" << m_centroid.scenePressPosition() << "->" << m_centroid.scenePosition() << ", distance" << m_startDistance << "->" << dist << ", startScale" << m_startScale << "->" << scale << ", activeRotation" << m_activeRotation @@ -456,15 +450,6 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) /*! \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 diff --git a/src/quick/handlers/qquickpinchhandler_p.h b/src/quick/handlers/qquickpinchhandler_p.h index 9a17971416..c2eedeb9e0 100644 --- a/src/quick/handlers/qquickpinchhandler_p.h +++ b/src/quick/handlers/qquickpinchhandler_p.h @@ -66,8 +66,6 @@ class Q_AUTOTEST_EXPORT QQuickPinchHandler : public QQuickMultiPointHandler Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged) Q_PROPERTY(qreal maximumRotation READ maximumRotation WRITE setMaximumRotation NOTIFY maximumRotationChanged) Q_PROPERTY(PinchOrigin pinchOrigin READ pinchOrigin WRITE setPinchOrigin NOTIFY pinchOriginChanged) - Q_PROPERTY(QPointF centroid READ centroid NOTIFY updated) - Q_PROPERTY(QVector2D centroidVelocity READ centroidVelocity NOTIFY updated) Q_PROPERTY(qreal scale READ scale NOTIFY updated) Q_PROPERTY(qreal rotation READ rotation NOTIFY updated) Q_PROPERTY(QVector2D translation READ translation NOTIFY updated) @@ -103,9 +101,6 @@ public: QVector2D translation() const { return m_activeTranslation; } qreal scale() const { return m_activeScale; } qreal rotation() const { return m_activeRotation; } - QPointF centroid() const { return m_centroid; } - QVector2D centroidVelocity() const { return m_centroidVelocity; } - qreal minimumX() const { return m_minimumX; } void setMinimumX(qreal minX); qreal maximumX() const { return m_maximumX; } @@ -137,8 +132,6 @@ private: qreal m_activeScale; qreal m_activeRotation; QVector2D m_activeTranslation; - QPointF m_centroid; - QVector2D m_centroidVelocity; qreal m_minimumScale; qreal m_maximumScale; @@ -156,7 +149,6 @@ private: // internal qreal m_startScale; qreal m_startRotation; - QPointF m_startCentroid; qreal m_startDistance; QPointF m_startPos; diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp index 5510813cce..2147359df4 100644 --- a/src/quick/handlers/qquicksinglepointhandler.cpp +++ b/src/quick/handlers/qquicksinglepointhandler.cpp @@ -130,38 +130,11 @@ void QQuickSinglePointHandler::handlePointerEventImpl(QQuickPointerEvent *event) if (!m_pointInfo.m_id || !currentPoint->isAccepted()) { reset(); } else { - if (event->asPointerTouchEvent()) { - QQuickEventTouchPoint *tp = static_cast<QQuickEventTouchPoint *>(currentPoint); - m_pointInfo.m_uniqueId = tp->uniqueId(); - m_pointInfo.m_rotation = tp->rotation(); - m_pointInfo.m_pressure = tp->pressure(); - m_pointInfo.m_ellipseDiameters = tp->ellipseDiameters(); - } else if (event->asPointerTabletEvent()) { - // TODO - } else { - m_pointInfo.m_uniqueId = event->device()->uniqueId(); - m_pointInfo.m_rotation = 0; - m_pointInfo.m_pressure = event->buttons() ? 1 : 0; - m_pointInfo.m_ellipseDiameters = QSizeF(); - } - m_pointInfo.m_position = currentPoint->position(); - m_pointInfo.m_scenePosition = currentPoint->scenePosition(); - if (currentPoint->state() == QQuickEventPoint::Updated) - m_pointInfo.m_velocity = currentPoint->velocity(); + m_pointInfo.reset(currentPoint); handleEventPoint(currentPoint); - switch (currentPoint->state()) { - case QQuickEventPoint::Pressed: - m_pointInfo.m_pressPosition = currentPoint->position(); - m_pointInfo.m_scenePressPosition = currentPoint->scenePosition(); - m_pointInfo.m_pressedButtons = event->buttons(); - break; - case QQuickEventPoint::Released: + if (currentPoint->state() == QQuickEventPoint::Released) { setExclusiveGrab(currentPoint, false); reset(); - break; - default: - m_pointInfo.m_pressedButtons = event->buttons(); - break; } emit pointChanged(); } diff --git a/tests/manual/pointer/pinchDragFlingMPTA.qml b/tests/manual/pointer/pinchDragFlingMPTA.qml index 2578d62466..0362832662 100644 --- a/tests/manual/pointer/pinchDragFlingMPTA.qml +++ b/tests/manual/pointer/pinchDragFlingMPTA.qml @@ -66,7 +66,7 @@ Rectangle { minimumPointCount: 3 minimumScale: 0.1 maximumScale: 10 - onActiveChanged: if (!active) fling.restart(centroidVelocity) + onActiveChanged: if (!active) fling.restart(centroid.velocity) } DragHandler { id: dragHandler diff --git a/tests/manual/pointer/pinchHandler.qml b/tests/manual/pointer/pinchHandler.qml index 409b852b55..36af1f53bd 100644 --- a/tests/manual/pointer/pinchHandler.qml +++ b/tests/manual/pointer/pinchHandler.qml @@ -153,7 +153,7 @@ Rectangle { maximumScale: 10 onActiveChanged: { if (!active) - anim.restart(centroidVelocity) + anim.restart(centroid.velocity) } } TapHandler { gesturePolicy: TapHandler.DragThreshold; onTapped: rect3.z = rect2.z + 1 } @@ -164,8 +164,8 @@ Rectangle { Rectangle { id: centroidIndicator property QtObject pincher: activePincher() - x: pincher.centroid.x - radius - y: pincher.centroid.y - radius + x: pincher.centroid.scenePosition.x - radius + y: pincher.centroid.scenePosition.y - radius z: 1 visible: pincher.active radius: width / 2 |