aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/handlers
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2022-11-16 18:20:19 +0100
committerShawn Rutledge <shawn.rutledge@qt.io>2022-12-10 03:13:57 +0100
commit7867a683fcb938939fb2837a26ac8e1941e3fe08 (patch)
tree271faa101a68abdd55c5c88146ee8bc223a413a8 /src/quick/handlers
parentf064497bd5021e5d28266cabbb703d548f6961b0 (diff)
Add PinchHandler.scaleAxis, rotationAxis; hold values in axes
Pointer Handlers that manipulate target item properties should now use QQuickDragAxis consistently to: - enforce minimum and maximum values - hold the persistent and active values - make those available via properties - emit a new activeValueChanged(delta) signal when the value changes, so that it's possible to incrementally update a target item property in JS (onValueDelta: target.property += delta) In the pinchHandler.qml example, you can use the PinchHandler to adjust 4 properties of one Rectangle independently (it requires coordination). m_boundedActiveValue controls whether m_activeValue will be kept between minimum and maximum. For rotation, tst_QQuickPinchHandler::scaleNativeGesture() expects it to be, although that seems questionable now, and may be addressed later. [ChangeLog][QtQuick][Event Handlers] PinchHandler now has scaleAxis and rotationAxis grouped properties, alongside the existing xAxis and yAxis; and all of these now have activeValue and persistentValue properties. The activeValueChanged signal includes a delta value, giving the incremental change since the previous activeValue. The persistentValue is settable, in case some target item property can be adjusted in multiple ways: the handler's stored value can then be synced up with the item property value after each external change. These features are also added to DragHandler's xAxis and yAxis properties. Task-number: QTBUG-68108 Task-number: QTBUG-76380 Task-number: QTBUG-76379 Task-number: QTBUG-94168 Change-Id: I78a5b43e9ba580448ef05054b6c4bc71b1834dd6 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
Diffstat (limited to 'src/quick/handlers')
-rw-r--r--src/quick/handlers/qquickdragaxis.cpp33
-rw-r--r--src/quick/handlers/qquickdragaxis_p.h36
-rw-r--r--src/quick/handlers/qquickdraghandler.cpp45
-rw-r--r--src/quick/handlers/qquickdraghandler_p.h15
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp229
-rw-r--r--src/quick/handlers/qquickpinchhandler_p.h45
6 files changed, 288 insertions, 115 deletions
diff --git a/src/quick/handlers/qquickdragaxis.cpp b/src/quick/handlers/qquickdragaxis.cpp
index c775058b86..a1fb1920e4 100644
--- a/src/quick/handlers/qquickdragaxis.cpp
+++ b/src/quick/handlers/qquickdragaxis.cpp
@@ -1,14 +1,18 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquickdragaxis_p.h"
+#include "qquickpointerhandler_p.h"
+#include <QtQuick/qquickitem.h>
#include <limits>
QT_BEGIN_NAMESPACE
-QQuickDragAxis::QQuickDragAxis()
- : m_minimum(-std::numeric_limits<qreal>::max())
- , m_maximum(std::numeric_limits<qreal>::max())
- , m_enabled(true)
+Q_LOGGING_CATEGORY(lcDragAxis, "qt.quick.pointer.dragaxis")
+
+QQuickDragAxis::QQuickDragAxis(QQuickPointerHandler *handler, const QString &propertyName,
+ bool boundedActiveValue, qreal initValue)
+ : QObject(handler), m_accumulatedValue(initValue), m_propertyName(propertyName),
+ m_boundedActiveValue(boundedActiveValue)
{
}
@@ -39,6 +43,27 @@ void QQuickDragAxis::setEnabled(bool enabled)
emit enabledChanged();
}
+void QQuickDragAxis::onActiveChanged(bool active, qreal initActiveValue)
+{
+ m_activeValue = initActiveValue;
+ m_startValue = m_accumulatedValue;
+ qCDebug(lcDragAxis) << parent() << m_propertyName << active << ": init active" << m_activeValue
+ << "target start" << m_startValue;
+}
+
+void QQuickDragAxis::updateValue(qreal activeValue, qreal accumulatedValue, qreal delta)
+{
+ if (!m_enabled)
+ return;
+
+ m_activeValue = m_boundedActiveValue ? qBound(m_minimum, activeValue, m_maximum) : activeValue;
+ m_accumulatedValue = qBound(m_minimum, accumulatedValue, m_maximum);
+ qCDebug(lcDragAxis) << parent() << m_propertyName << "values: active" << activeValue
+ << "accumulated" << m_accumulatedValue << "delta" << delta;
+ emit activeValueChanged(delta);
+ emit persistentValueChanged();
+}
+
QT_END_NAMESPACE
#include "moc_qquickdragaxis_p.cpp"
diff --git a/src/quick/handlers/qquickdragaxis_p.h b/src/quick/handlers/qquickdragaxis_p.h
index 17f20f332c..f788999c0f 100644
--- a/src/quick/handlers/qquickdragaxis_p.h
+++ b/src/quick/handlers/qquickdragaxis_p.h
@@ -16,22 +16,29 @@
//
#include <QtQml/qqml.h>
+#include <QtQml/qqmlproperty.h>
#include <private/qtquickglobal_p.h>
QT_BEGIN_NAMESPACE
+class QQuickItem;
+class QQuickPointerHandler;
+
class Q_QUICK_PRIVATE_EXPORT QQuickDragAxis : public QObject
{
Q_OBJECT
Q_PROPERTY(qreal minimum READ minimum WRITE setMinimum NOTIFY minimumChanged)
Q_PROPERTY(qreal maximum READ maximum WRITE setMaximum NOTIFY maximumChanged)
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(qreal activeValue READ activeValue NOTIFY activeValueChanged REVISION(6, 5))
+ Q_PROPERTY(qreal persistentValue READ persistentValue NOTIFY persistentValueChanged REVISION(6, 5))
QML_NAMED_ELEMENT(DragAxis)
QML_ADDED_IN_VERSION(2, 12)
- QML_UNCREATABLE("DragAxis is only available as a grouped property of DragHandler.")
+ QML_UNCREATABLE("DragAxis is only available as a grouped property of DragHandler or PinchHandler.")
public:
- QQuickDragAxis();
+ QQuickDragAxis(QQuickPointerHandler *handler, const QString &propertyName,
+ bool boundedActiveValue = false, qreal initValue = 0);
qreal minimum() const { return m_minimum; }
void setMinimum(qreal minimum);
@@ -42,15 +49,34 @@ public:
bool enabled() const { return m_enabled; }
void setEnabled(bool enabled);
+ qreal activeValue() const { return m_activeValue; }
+
+ qreal persistentValue() const { return m_accumulatedValue; }
+
+protected:
+ void onActiveChanged(bool active, qreal initActiveValue);
+ qreal targetValue();
+ void updateValue(qreal activeValue, qreal accumulatedValue, qreal delta = 0);
+
Q_SIGNALS:
void minimumChanged();
void maximumChanged();
void enabledChanged();
+ Q_REVISION(6, 5) void activeValueChanged(qreal delta);
+ Q_REVISION(6, 5) void persistentValueChanged();
private:
- qreal m_minimum;
- qreal m_maximum;
- bool m_enabled;
+ qreal m_minimum = std::numeric_limits<qreal>::lowest();
+ qreal m_maximum = std::numeric_limits<qreal>::max();
+ qreal m_startValue = 0;
+ qreal m_activeValue = 0;
+ qreal m_accumulatedValue = 0;
+ QString m_propertyName;
+ bool m_enabled = true;
+ bool m_boundedActiveValue = false;
+
+ friend class QQuickDragHandler;
+ friend class QQuickPinchHandler;
};
QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp
index c31eb13d98..b34ca0e7cf 100644
--- a/src/quick/handlers/qquickdraghandler.cpp
+++ b/src/quick/handlers/qquickdraghandler.cpp
@@ -120,7 +120,10 @@ void QQuickDragHandler::setSnapMode(QQuickDragHandler::SnapMode mode)
void QQuickDragHandler::onActiveChanged()
{
QQuickMultiPointHandler::onActiveChanged();
- if (active()) {
+ const bool curActive = active();
+ m_xAxis.onActiveChanged(curActive, 0);
+ m_yAxis.onActiveChanged(curActive, 0);
+ if (curActive) {
if (auto parent = parentItem()) {
if (QQuickDeliveryAgentPrivate::isTouchEvent(currentEvent()))
parent->setKeepTouchGrab(true);
@@ -129,7 +132,6 @@ void QQuickDragHandler::onActiveChanged()
// mouse grab too, whenever dragging occurs in an enabled direction
parent->setKeepMouseGrab(true);
}
- m_startTranslation = m_persistentTranslation;
} else {
m_pressTargetPos = QPointF();
m_pressedInsideTarget = false;
@@ -283,22 +285,25 @@ void QQuickDragHandler::enforceAxisConstraints(QPointF *localPos)
void QQuickDragHandler::setPersistentTranslation(const QVector2D &trans)
{
- if (trans == m_persistentTranslation)
+ if (trans == persistentTranslation())
return;
- m_persistentTranslation = trans;
+ m_xAxis.updateValue(m_xAxis.activeValue(), trans.x());
+ m_yAxis.updateValue(m_yAxis.activeValue(), trans.y());
emit translationChanged();
}
void QQuickDragHandler::setActiveTranslation(const QVector2D &trans)
{
- if (trans == m_activeTranslation)
+ if (trans == activeTranslation())
return;
- m_activeTranslation = trans;
- m_persistentTranslation = m_startTranslation + trans;
- qCDebug(lcDragHandler) << "translation: start" << m_startTranslation
- << "active" << m_activeTranslation << "accumulated" << m_persistentTranslation;
+ const QVector2D delta = trans - activeTranslation();
+ m_xAxis.updateValue(trans.x(), m_xAxis.persistentValue() + delta.x(), delta.x());
+ m_yAxis.updateValue(trans.y(), m_yAxis.persistentValue() + delta.y(), delta.y());
+
+ qCDebug(lcDragHandler) << "translation: delta" << delta
+ << "active" << trans << "accumulated" << persistentTranslation();
emit translationChanged();
}
@@ -307,6 +312,8 @@ void QQuickDragHandler::setActiveTranslation(const QVector2D &trans)
\qmlproperty real QtQuick::DragHandler::xAxis.minimum
\qmlproperty real QtQuick::DragHandler::xAxis.maximum
\qmlproperty bool QtQuick::DragHandler::xAxis.enabled
+ \qmlproperty real QtQuick::DragHandler::xAxis.activeValue
+ \qmlproperty real QtQuick::DragHandler::xAxis.persistentValue
\c xAxis controls the constraints for horizontal dragging.
@@ -315,13 +322,21 @@ void QQuickDragHandler::setActiveTranslation(const QVector2D &trans)
\c maximum is the maximum acceptable value of \l {Item::x}{x} to be
applied to the \l {PointerHandler::target} {target}.
If \c enabled is true, horizontal dragging is allowed.
- */
+ \c activeValue is the same as \l {QtQuick::DragHandler::activeTranslation}{activeTranslation.x}.
+ \c persistentValue is the same as \l {QtQuick::DragHandler::persistentTranslation}{persistentTranslation.x}.
+
+ The \c activeValueChanged signal is emitted when \c activeValue (and therefore
+ \c persistentValue) changes, to provide the increment by which it changed.
+ This is intended for incrementally adjusting one property via multiple handlers.
+*/
/*!
\qmlpropertygroup QtQuick::DragHandler::yAxis
\qmlproperty real QtQuick::DragHandler::yAxis.minimum
\qmlproperty real QtQuick::DragHandler::yAxis.maximum
\qmlproperty bool QtQuick::DragHandler::yAxis.enabled
+ \qmlproperty real QtQuick::DragHandler::yAxis.activeValue
+ \qmlproperty real QtQuick::DragHandler::yAxis.persistentValue
\c yAxis controls the constraints for vertical dragging.
@@ -330,7 +345,15 @@ void QQuickDragHandler::setActiveTranslation(const QVector2D &trans)
\c maximum is the maximum acceptable value of \l {Item::y}{y} to be
applied to the \l {PointerHandler::target} {target}.
If \c enabled is true, vertical dragging is allowed.
- */
+ \c activeValue is the same as \l {QtQuick::DragHandler::activeTranslation}{activeTranslation.y}.
+ \c persistentValue is the same as \l {QtQuick::DragHandler::persistentTranslation}{persistentTranslation.y}.
+
+ The \c activeValueChanged signal is emitted when \c activeValue (and therefore
+ \c persistentValue) changes, to provide the increment by which it changed.
+ This is intended for incrementally adjusting one property via multiple handlers:
+
+ \snippet pointerHandlers/rotateViaWheelOrDrag.qml 0
+*/
/*!
\readonly
diff --git a/src/quick/handlers/qquickdraghandler_p.h b/src/quick/handlers/qquickdraghandler_p.h
index a86ef847e2..925783ec98 100644
--- a/src/quick/handlers/qquickdraghandler_p.h
+++ b/src/quick/handlers/qquickdraghandler_p.h
@@ -20,6 +20,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class Q_QUICK_PRIVATE_EXPORT QQuickDragHandler : public QQuickMultiPointHandler
{
Q_OBJECT
@@ -51,11 +53,11 @@ public:
QQuickDragAxis *yAxis() { return &m_yAxis; }
#if QT_DEPRECATED_SINCE(6, 2)
- QVector2D translation() const { return m_activeTranslation; }
+ QVector2D translation() const { return activeTranslation(); }
#endif
- QVector2D activeTranslation() const { return m_activeTranslation; }
+ QVector2D activeTranslation() const { return QVector2D(QPointF(m_xAxis.activeValue(), m_yAxis.activeValue())); }
void setActiveTranslation(const QVector2D &trans);
- QVector2D persistentTranslation() const { return m_persistentTranslation; }
+ QVector2D persistentTranslation() const { return QVector2D(QPointF(m_xAxis.persistentValue(), m_yAxis.persistentValue())); }
void setPersistentTranslation(const QVector2D &trans);
QQuickDragHandler::SnapMode snapMode() const;
void setSnapMode(QQuickDragHandler::SnapMode mode);
@@ -80,12 +82,9 @@ private:
QPointF m_pressTargetPos; // We must also store the local targetPos, because we cannot deduce
// the press target pos from the scene pos in case there was e.g a
// flick in one of the ancestors during the drag.
- QVector2D m_activeTranslation;
- QVector2D m_persistentTranslation;
- QVector2D m_startTranslation;
- QQuickDragAxis m_xAxis;
- QQuickDragAxis m_yAxis;
+ QQuickDragAxis m_xAxis = {this, u"x"_s};
+ QQuickDragAxis m_yAxis = {this, u"y"_s};
QQuickDragHandler::SnapMode m_snapMode = SnapAuto;
bool m_pressedInsideTarget = false;
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index 6fec0feaa1..f11d8357eb 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -74,10 +74,10 @@ QQuickPinchHandler::QQuickPinchHandler(QQuickItem *parent)
*/
void QQuickPinchHandler::setMinimumScale(qreal minimumScale)
{
- if (qFuzzyCompare(m_minimumScale, minimumScale))
+ if (qFuzzyCompare(m_scaleAxis.minimum(), minimumScale))
return;
- m_minimumScale = minimumScale;
+ m_scaleAxis.setMinimum(minimumScale);
emit minimumScaleChanged();
}
@@ -89,10 +89,10 @@ void QQuickPinchHandler::setMinimumScale(qreal minimumScale)
*/
void QQuickPinchHandler::setMaximumScale(qreal maximumScale)
{
- if (qFuzzyCompare(m_maximumScale, maximumScale))
+ if (qFuzzyCompare(m_scaleAxis.maximum(), maximumScale))
return;
- m_maximumScale = maximumScale;
+ m_scaleAxis.setMaximum(maximumScale);
emit maximumScaleChanged();
}
@@ -104,10 +104,10 @@ void QQuickPinchHandler::setMaximumScale(qreal maximumScale)
*/
void QQuickPinchHandler::setMinimumRotation(qreal minimumRotation)
{
- if (qFuzzyCompare(m_minimumRotation, minimumRotation))
+ if (qFuzzyCompare(m_rotationAxis.minimum(), minimumRotation))
return;
- m_minimumRotation = minimumRotation;
+ m_rotationAxis.setMinimum(minimumRotation);
emit minimumRotationChanged();
}
@@ -119,10 +119,10 @@ void QQuickPinchHandler::setMinimumRotation(qreal minimumRotation)
*/
void QQuickPinchHandler::setMaximumRotation(qreal maximumRotation)
{
- if (qFuzzyCompare(m_maximumRotation, maximumRotation))
+ if (qFuzzyCompare(m_rotationAxis.maximum(), maximumRotation))
return;
- m_maximumRotation = maximumRotation;
+ m_rotationAxis.setMaximum(maximumRotation);
emit maximumRotationChanged();
}
@@ -159,26 +159,110 @@ bool QQuickPinchHandler::wantsPointerEvent(QPointerEvent *event)
\qmlproperty real QtQuick::PinchHandler::xAxis.minimum
\qmlproperty real QtQuick::PinchHandler::xAxis.maximum
\qmlproperty bool QtQuick::PinchHandler::xAxis.enabled
+ \qmlproperty real QtQuick::PinchHandler::xAxis.activeValue
+ \qmlproperty real QtQuick::PinchHandler::xAxis.persistentValue
\c xAxis controls the constraints for horizontal translation of the \l target item.
\c minimum is the minimum acceptable x coordinate of the translation.
\c maximum is the maximum acceptable x coordinate of the translation.
If \c enabled is true, horizontal dragging is allowed.
- */
+
+ The \c activeValueChanged signal is emitted when \c activeValue (and therefore
+ \c persistentValue) changes, to provide the increment by which it changed.
+ This is intended for incrementally adjusting one property via multiple handlers.
+
+ \snippet pointerHandlers/pinchHandlerAxisValueDeltas.qml 0
+
+ \note The snippet is contrived: PinchHandler already knows how to move,
+ scale and rotate its parent item, but this code achieves different behavior
+ in a less-declarative way, to illustrate how to use \c activeValueChanged
+ in special cases.
+*/
/*!
\qmlpropertygroup QtQuick::PinchHandler::yAxis
\qmlproperty real QtQuick::PinchHandler::yAxis.minimum
\qmlproperty real QtQuick::PinchHandler::yAxis.maximum
\qmlproperty bool QtQuick::PinchHandler::yAxis.enabled
+ \qmlproperty real QtQuick::PinchHandler::yAxis.activeValue
+ \qmlproperty real QtQuick::PinchHandler::yAxis.persistentValue
\c yAxis controls the constraints for vertical translation of the \l target item.
\c minimum is the minimum acceptable y coordinate of the translation.
\c maximum is the maximum acceptable y coordinate of the translation.
If \c enabled is true, vertical dragging is allowed.
- */
+
+ The \c activeValueChanged signal is emitted when \c activeValue (and therefore
+ \c persistentValue) changes, to provide the increment by which it changed.
+ This is intended for incrementally adjusting one property via multiple handlers.
+
+ \snippet pointerHandlers/pinchHandlerAxisValueDeltas.qml 0
+
+ \note The snippet is contrived: PinchHandler already knows how to move,
+ scale and rotate its parent item, but this code achieves different behavior
+ in a less-declarative way, to illustrate how to use \c activeValueChanged
+ in special cases.
+*/
+
+/*!
+ \qmlpropertygroup QtQuick::PinchHandler::scaleAxis
+ \qmlproperty real QtQuick::PinchHandler::scaleAxis.minimum
+ \qmlproperty real QtQuick::PinchHandler::scaleAxis.maximum
+ \qmlproperty bool QtQuick::PinchHandler::scaleAxis.enabled
+ \qmlproperty real QtQuick::PinchHandler::scaleAxis.activeValue
+ \qmlproperty real QtQuick::PinchHandler::scaleAxis.persistentValue
+
+ \c scaleAxis controls the constraints for setting the \l {QtQuick::Item::scale}{scale}
+ of the \l target item according to the distance between the touchpoints.
+
+ \c minimum is the minimum acceptable scale.
+ \c maximum is the maximum acceptable scale.
+ If \c enabled is true, scaling is allowed.
+ \c activeValue is the same as \l {QtQuick::PinchHandler::activeScale}.
+ \c persistentValue is the same as \l {QtQuick::PinchHandler::scale}.
+
+ The \c activeValueChanged signal is emitted when \c activeValue (and therefore
+ \c persistentValue) changes, to provide the multiplier for the incremental change.
+ This is intended for incrementally adjusting one property via multiple handlers.
+
+ \snippet pointerHandlers/pinchHandlerAxisValueDeltas.qml 0
+
+ \note The snippet is contrived: PinchHandler already knows how to move,
+ scale and rotate its parent item, but this code achieves different behavior
+ in a less-declarative way, to illustrate how to use \c activeValueChanged
+ in special cases.
+*/
+
+/*!
+ \qmlpropertygroup QtQuick::PinchHandler::rotationAxis
+ \qmlproperty real QtQuick::PinchHandler::rotationAxis.minimum
+ \qmlproperty real QtQuick::PinchHandler::rotationAxis.maximum
+ \qmlproperty bool QtQuick::PinchHandler::rotationAxis.enabled
+ \qmlproperty real QtQuick::PinchHandler::rotationAxis.activeValue
+ \qmlproperty real QtQuick::PinchHandler::rotationAxis.persistentValue
+
+ \c rotationAxis controls the constraints for setting the \l {QtQuick::Item::rotation}{rotation}
+ of the \l target item according to the rotation of the group of touchpoints.
+
+ \c minimum is the minimum acceptable rotation.
+ \c maximum is the maximum acceptable rotation.
+ If \c enabled is true, rotation is allowed.
+ \c activeValue is the same as \l {QtQuick::PinchHandler::rotation}.
+ \c persistentValue holds the accumulated value across multiple gestures.
+
+ The \c activeValueChanged signal is emitted when \c activeValue (and therefore
+ \c persistentValue) changes, to provide the increment by which it changed.
+ This is intended for incrementally adjusting one property via multiple handlers.
+
+ \snippet pointerHandlers/pinchHandlerAxisValueDeltas.qml 0
+
+ \note The snippet is contrived: PinchHandler already knows how to move,
+ scale and rotate its parent item, but this code achieves different behavior
+ in a less-declarative way, to illustrate how to use \c activeValueChanged
+ in special cases.
+*/
/*!
\readonly
@@ -193,22 +277,25 @@ bool QQuickPinchHandler::wantsPointerEvent(QPointerEvent *event)
void QQuickPinchHandler::onActiveChanged()
{
QQuickMultiPointHandler::onActiveChanged();
- if (active()) {
+ const bool curActive = active();
+ if (const QQuickItem *t = target(); curActive && t) {
+ m_xAxis.m_accumulatedValue = t->position().x();
+ m_yAxis.m_accumulatedValue = t->position().y();
+ m_scaleAxis.m_accumulatedValue = t->scale();
+ m_rotationAxis.m_accumulatedValue = t->rotation();
+ }
+ m_xAxis.onActiveChanged(curActive, 0);
+ m_yAxis.onActiveChanged(curActive, 0);
+ m_scaleAxis.onActiveChanged(curActive, 1);
+ m_rotationAxis.onActiveChanged(curActive, 0);
+
+ if (curActive) {
m_startAngles = angles(centroid().sceneGrabPosition());
m_startDistance = averageTouchPointDistance(centroid().sceneGrabPosition());
- m_activeRotation = 0;
- m_activeTranslation = QVector2D();
- if (const QQuickItem *t = target()) {
- m_startScale = t->scale(); // TODO incompatible with independent x/y scaling
- m_startRotation = t->rotation();
- m_startPos = t->position();
- } else {
- m_startScale = m_accumulatedScale;
- m_startRotation = 0; // TODO m_accumulatedRotation (QTBUG-94168)
- }
- qCDebug(lcPinchHandler) << "activated with starting scale" << m_startScale << "rotation" << m_startRotation;
+ qCDebug(lcPinchHandler) << "activated with starting scale" << m_scaleAxis.m_startValue
+ << "target scale" << m_scaleAxis.m_startValue << "rotation" << m_rotationAxis.m_startValue;
} else {
- qCDebug(lcPinchHandler) << "deactivated with scale" << m_activeScale << "rotation" << m_activeRotation;
+ qCDebug(lcPinchHandler) << "deactivated with scale" << m_scaleAxis.m_activeValue << "rotation" << m_rotationAxis.m_activeValue;
}
}
@@ -226,31 +313,27 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event)
const auto gesture = static_cast<const QNativeGestureEvent *>(event);
mutableCentroid().reset(event, event->point(0));
switch (gesture->gestureType()) {
+ case Qt::BeginNativeGesture:
+ setActive(true);
+ // Native gestures for 2-finger pinch do not allow dragging, so
+ // the centroid won't move during the gesture, and translation stays at zero
+ return;
case Qt::EndNativeGesture:
- m_activeScale = 1;
- m_activeRotation = 0;
- m_activeTranslation = QVector2D();
mutableCentroid().reset();
setActive(false);
emit updated();
return;
case Qt::ZoomNativeGesture:
- m_activeScale *= 1 + gesture->value();
- m_activeScale = qBound(m_minimumScale, m_activeScale, m_maximumScale);
+ m_scaleAxis.updateValue(1 + gesture->value(), m_scaleAxis.m_startValue * (1 + gesture->value()));
break;
case Qt::RotateNativeGesture:
- m_activeRotation += gesture->value();
+ m_rotationAxis.updateValue(m_rotationAxis.m_activeValue + gesture->value(),
+ m_rotationAxis.m_startValue + m_rotationAxis.m_activeValue + gesture->value());
break;
default:
// Nothing of interest (which is unexpected, because wantsPointerEvent() should have returned false)
return;
}
- if (!active()) {
- setActive(true);
- // 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_activeTranslation = QVector2D();
- }
} else
#endif // QT_CONFIG(gestures)
{
@@ -333,7 +416,9 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event)
++numberOfPointsDraggedOverThreshold;
}
- const bool requiredNumberOfPointsDraggedOverThreshold = numberOfPointsDraggedOverThreshold >= minimumPointCount() && numberOfPointsDraggedOverThreshold <= maximumPointCount();
+ const bool requiredNumberOfPointsDraggedOverThreshold =
+ numberOfPointsDraggedOverThreshold >= minimumPointCount() &&
+ numberOfPointsDraggedOverThreshold <= maximumPointCount();
accumulatedMovementMagnitude /= currentPoints().size();
QVector2D avgDrag = accumulatedDrag / currentPoints().size();
@@ -346,7 +431,8 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event)
qreal distanceToCentroidDelta = qAbs(accumulatedCentroidDistance - m_accumulatedStartCentroidDistance); // Used to detect scale
if (numberOfPointsDraggedOverThreshold >= 1) {
- if (requiredNumberOfPointsDraggedOverThreshold && avgDrag.lengthSquared() >= dragThresholdSquared && accumulatedMovementMagnitude < dragThreshold) {
+ if (requiredNumberOfPointsDraggedOverThreshold &&
+ avgDrag.lengthSquared() >= dragThresholdSquared && accumulatedMovementMagnitude < dragThreshold) {
// Drag
if (grabPoints(event, chosenPoints))
setActive(true);
@@ -369,62 +455,81 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event)
// 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(centroid().scenePosition());
- m_activeScale = dist / m_startDistance;
- m_activeScale = qBound(m_minimumScale/m_startScale, m_activeScale, m_maximumScale/m_startScale);
+ qreal activeScale = 1;
+ if (m_scaleAxis.enabled()) {
+ dist = averageTouchPointDistance(centroid().scenePosition());
+ activeScale = dist / m_startDistance;
+ activeScale = qBound(m_scaleAxis.minimum() / m_scaleAxis.m_startValue, activeScale,
+ m_scaleAxis.maximum() / m_scaleAxis.m_startValue);
+ m_scaleAxis.updateValue(activeScale, m_scaleAxis.m_startValue * activeScale,
+ activeScale / m_scaleAxis.activeValue());
+ }
// 2. rotate
- QVector<PointData> newAngles = angles(centroid().scenePosition());
- const qreal angleDelta = averageAngleDelta(m_startAngles, newAngles);
- m_activeRotation += angleDelta;
- m_startAngles = std::move(newAngles);
+ if (m_rotationAxis.enabled()) {
+ QVector<PointData> newAngles = angles(centroid().scenePosition());
+ const qreal angleDelta = averageAngleDelta(m_startAngles, newAngles);
+ m_rotationAxis.updateValue(m_rotationAxis.m_activeValue + angleDelta,
+ m_rotationAxis.m_startValue + m_rotationAxis.m_activeValue + angleDelta,
+ angleDelta);
+ m_startAngles = std::move(newAngles);
+ }
if (!containsReleasedPoints)
acceptPoints(chosenPoints);
}
- 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_accumulatedScale = m_startScale * m_activeScale;
if (target() && target()->parentItem()) {
const QPointF centroidParentPos = target()->parentItem()->mapFromScene(centroid().scenePosition());
// 3. Drag/translate
const QPointF centroidStartParentPos = target()->parentItem()->mapFromScene(centroid().sceneGrabPosition());
- m_activeTranslation = QVector2D(centroidParentPos - centroidStartParentPos);
+ auto activeTranslation = QVector2D(centroidParentPos - centroidStartParentPos);
// apply rotation + scaling around the centroid - then apply translation.
QPointF pos = QQuickItemPrivate::get(target())->adjustedPosForTransform(centroidParentPos,
- m_startPos, m_activeTranslation,
- m_startScale, m_activeScale,
- m_startRotation, m_activeRotation);
+ startPos(), activeTranslation,
+ m_scaleAxis.m_startValue,
+ m_scaleAxis.persistentValue() / m_scaleAxis.m_startValue,
+ m_rotationAxis.m_startValue,
+ m_rotationAxis.persistentValue() - m_rotationAxis.m_startValue);
if (xAxis()->enabled())
pos.setX(qBound(xAxis()->minimum(), pos.x(), xAxis()->maximum()));
else
- pos.rx() -= qreal(m_activeTranslation.x());
+ pos.rx() -= qreal(activeTranslation.x());
if (yAxis()->enabled())
pos.setY(qBound(yAxis()->minimum(), pos.y(), yAxis()->maximum()));
else
- pos.ry() -= qreal(m_activeTranslation.y());
+ pos.ry() -= qreal(activeTranslation.y());
- target()->setPosition(pos);
- target()->setRotation(rotation);
- target()->setScale(m_accumulatedScale);
+ m_xAxis.updateValue(activeTranslation.x(), pos.x(), activeTranslation.x() - m_xAxis.activeValue());
+ m_yAxis.updateValue(activeTranslation.y(), pos.y(), activeTranslation.y() - m_yAxis.activeValue());
+ target()->setPosition(QPointF(m_xAxis.persistentValue(), m_yAxis.persistentValue()));
+ target()->setRotation(m_rotationAxis.persistentValue());
+ target()->setScale(m_scaleAxis.persistentValue());
} else {
- m_activeTranslation = QVector2D(centroid().scenePosition() - centroid().scenePressPosition());
+ auto activeTranslation = centroid().scenePosition() - centroid().scenePressPosition();
+ auto accumulated = QPointF(m_xAxis.m_startValue, m_yAxis.m_startValue) + activeTranslation;
+ m_xAxis.updateValue(activeTranslation.x(), accumulated.x(),
+ activeTranslation.x() - m_xAxis.activeValue());
+ m_yAxis.updateValue(activeTranslation.y(), accumulated.y(),
+ activeTranslation.y() - m_yAxis.activeValue());
}
qCDebug(lcPinchHandler) << "centroid" << centroid().scenePressPosition() << "->" << centroid().scenePosition()
<< ", distance" << m_startDistance << "->" << dist
- << ", scale" << m_startScale << "->" << m_accumulatedScale
- << ", activeRotation" << m_activeRotation
- << ", rotation" << rotation
- << " from " << event->device()->type();
+ << ", scale" << m_scaleAxis.m_startValue << "->" << m_scaleAxis.m_accumulatedValue
+ << ", rotation" << m_rotationAxis.m_startValue << "->" << m_rotationAxis.m_accumulatedValue
+ << ", translation" << translation() << " from " << event->device()->type();
emit updated();
}
+QPointF QQuickPinchHandler::startPos()
+{
+ return {m_xAxis.m_startValue, m_yAxis.m_startValue};
+}
+
/*!
\readonly
\qmlproperty QtQuick::HandlerPoint QtQuick::PinchHandler::centroid
diff --git a/src/quick/handlers/qquickpinchhandler_p.h b/src/quick/handlers/qquickpinchhandler_p.h
index 6fff85639e..e788b490eb 100644
--- a/src/quick/handlers/qquickpinchhandler_p.h
+++ b/src/quick/handlers/qquickpinchhandler_p.h
@@ -23,6 +23,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class Q_QUICK_PRIVATE_EXPORT QQuickPinchHandler : public QQuickMultiPointHandler
{
Q_OBJECT
@@ -36,31 +38,35 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPinchHandler : public QQuickMultiPointHandler
Q_PROPERTY(QVector2D translation READ translation NOTIFY updated)
Q_PROPERTY(QQuickDragAxis * xAxis READ xAxis CONSTANT)
Q_PROPERTY(QQuickDragAxis * yAxis READ yAxis CONSTANT)
+ Q_PROPERTY(QQuickDragAxis * scaleAxis READ scaleAxis CONSTANT)
+ Q_PROPERTY(QQuickDragAxis * rotationAxis READ rotationAxis CONSTANT)
QML_NAMED_ELEMENT(PinchHandler)
QML_ADDED_IN_VERSION(2, 12)
public:
explicit QQuickPinchHandler(QQuickItem *parent = nullptr);
- qreal minimumScale() const { return m_minimumScale; }
+ qreal minimumScale() const { return m_scaleAxis.minimum(); }
void setMinimumScale(qreal minimumScale);
- qreal maximumScale() const { return m_maximumScale; }
+ qreal maximumScale() const { return m_scaleAxis.maximum(); }
void setMaximumScale(qreal maximumScale);
- qreal minimumRotation() const { return m_minimumRotation; }
+ qreal minimumRotation() const { return m_rotationAxis.minimum(); }
void setMinimumRotation(qreal minimumRotation);
- qreal maximumRotation() const { return m_maximumRotation; }
+ qreal maximumRotation() const { return m_rotationAxis.maximum(); }
void setMaximumRotation(qreal maximumRotation);
- QVector2D translation() const { return m_activeTranslation; }
- qreal scale() const { return m_accumulatedScale; }
- qreal activeScale() const { return m_activeScale; }
- qreal rotation() const { return m_activeRotation; }
+ QVector2D translation() const { return QVector2D(QPointF(m_xAxis.activeValue(), m_yAxis.activeValue())); }
+ qreal scale() const { return m_scaleAxis.m_accumulatedValue; }
+ qreal activeScale() const { return m_scaleAxis.m_activeValue; }
+ qreal rotation() const { return m_rotationAxis.m_accumulatedValue; }
QQuickDragAxis *xAxis() { return &m_xAxis; }
QQuickDragAxis *yAxis() { return &m_yAxis; }
+ QQuickDragAxis *scaleAxis() { return &m_scaleAxis; }
+ QQuickDragAxis *rotationAxis() { return &m_rotationAxis; }
Q_SIGNALS:
void minimumScaleChanged();
@@ -74,27 +80,16 @@ protected:
void onActiveChanged() override;
void handlePointerEventImpl(QPointerEvent *event) override;
-private:
- // properties
- qreal m_activeScale = 1;
- qreal m_accumulatedScale = 1;
- qreal m_activeRotation = 0;
- QVector2D m_activeTranslation = QVector2D(0, 0);
-
- qreal m_minimumScale = -qInf();
- qreal m_maximumScale = qInf();
+ QPointF startPos();
- qreal m_minimumRotation = -qInf();
- qreal m_maximumRotation = qInf();
-
- QQuickDragAxis m_xAxis;
- QQuickDragAxis m_yAxis;
+private:
+ QQuickDragAxis m_xAxis = {this, u"x"_s};
+ QQuickDragAxis m_yAxis = {this, u"y"_s};
+ QQuickDragAxis m_scaleAxis = {this, u"scale"_s, true, 1};
+ QQuickDragAxis m_rotationAxis = {this, u"rotation"_s, true};
// internal
- qreal m_startScale = 1;
- qreal m_startRotation = 0;
qreal m_startDistance = 0;
- QPointF m_startPos;
qreal m_accumulatedStartCentroidDistance = 0;
QVector<PointData> m_startAngles;
QQuickMatrix4x4 m_transform;