diff options
author | Vladimir Belyavsky <[email protected]> | 2024-10-24 16:22:18 +0300 |
---|---|---|
committer | Shawn Rutledge <[email protected]> | 2024-10-26 10:52:39 +0200 |
commit | 49fbf2f86afa62b8c1c2be330620a0b310584a34 (patch) | |
tree | e8ea2d10a9c5f8d8c69337cc1c744d2d526246ec | |
parent | 27ee3aa4403c7e3f3d189220228876690eb4308b (diff) |
PinchHandler: Set target properties only if respective axis enabled
If the user has disabled the rotation or scale axis, the target item's
rotation or scale property must not be set at all, to avoid breaking
bindings that were set differently.
Fixes: QTBUG-130517
Pick-to: 6.8 6.5
Change-Id: I8f84f6845532f748bbdcc3af91a398d6659156ca
Reviewed-by: Richard Moe Gustavsen <[email protected]>
-rw-r--r-- | src/quick/handlers/qquickpinchhandler.cpp | 12 | ||||
-rw-r--r-- | tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp | 96 |
2 files changed, 77 insertions, 31 deletions
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp index 64a571a999..fa790ecfa5 100644 --- a/src/quick/handlers/qquickpinchhandler.cpp +++ b/src/quick/handlers/qquickpinchhandler.cpp @@ -697,9 +697,17 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event) m_xAxis.updateValue(activeTranslation.x(), m_xAxis.persistentValue() + delta.x(), delta.x()); m_yAxis.updateValue(activeTranslation.y(), m_yAxis.persistentValue() + delta.y(), delta.y()); emit translationChanged(delta); + // xAxis or yAxis may be disabled; nevertheless, we use setPosition() to compensate for + // other aspects of the transform. So it should not be skipped. Above, we've already + // subtracted activeTranslation if necessary. t->setPosition(pos); - t->setRotation(m_rotationAxis.persistentValue()); - t->setScale(m_scaleAxis.persistentValue()); + // Set rotation and scale properties only if the respective axes are enabled. + // We've already checked above, so we don't expect activeScale or activeRotation to change + // if the axis is disabled; but then don't call the setter at all, to avoid breaking bindings. + if (m_rotationAxis.enabled()) + t->setRotation(m_rotationAxis.persistentValue()); + if (m_scaleAxis.enabled()) + t->setScale(m_scaleAxis.persistentValue()); } else { auto activeTranslation = centroid().scenePosition() - centroid().scenePressPosition(); auto accumulated = QPointF(m_xAxis.m_startValue, m_yAxis.m_startValue) + activeTranslation; diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp index 350dfeff88..4c171cdfac 100644 --- a/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp @@ -217,14 +217,17 @@ void tst_QQuickPinchHandler::scale_data() { QTest::addColumn<QUrl>("qmlfile"); QTest::addColumn<bool>("hasTarget"); - QTest::newRow("targetModifying") << testFileUrl("pinchproperties.qml") << true; - QTest::newRow("nullTarget") << testFileUrl("nullTarget.qml") << false; + QTest::addColumn<bool>("axisEnabled"); + QTest::newRow("targetModifying") << testFileUrl("pinchproperties.qml") << true << true; + QTest::newRow("nullTarget") << testFileUrl("nullTarget.qml") << false << true; + QTest::newRow("axisDiabled") << testFileUrl("pinchproperties.qml") << true << false; } void tst_QQuickPinchHandler::scale() { QFETCH(QUrl, qmlfile); QFETCH(bool, hasTarget); + QFETCH(bool, axisEnabled); QQuickView window; QVERIFY(QQuickTest::showView(window, qmlfile)); @@ -232,6 +235,7 @@ void tst_QQuickPinchHandler::scale() QVERIFY(root != nullptr); auto *pinchHandler = static_cast<PinchHandler *>(root->findChild<QQuickPinchHandler*>()); QVERIFY(pinchHandler != nullptr); + pinchHandler->scaleAxis()->setEnabled(axisEnabled); QQuickItem *blackRect = (hasTarget ? pinchHandler->target() : pinchHandler->parentItem()); QVERIFY(blackRect != nullptr); QSignalSpy grabChangedSpy(pinchHandler, SIGNAL(grabChanged(QPointingDevice::GrabTransition,QEventPoint))); @@ -271,10 +275,13 @@ void tst_QQuickPinchHandler::scale() QCOMPARE(grabChangedSpy.size(), 3); QLineF line(p0, p1); const qreal startLength = line.length(); + // to be redefined below + qreal lastScale = pinchHandler->persistentScale(); + qreal expectedIncrement = 0; // move the same point even further and observe the change in scale for (int i = 0; i < 2; ++i) { - qreal lastScale = pinchHandler->activeScale(); + lastScale = pinchHandler->activeScale(); p1 += pd; pinchSequence.stationary(0).move(1, p1, &window).commit(); QQuickTouchUtils::flush(&window); @@ -284,21 +291,27 @@ void tst_QQuickPinchHandler::scale() qCDebug(lcPointerTests) << "pinchScale" << root->property("pinchScale").toReal() << "expected" << expectedScale << "; target scale" << blackRect->scale() << "increments" << scaleChangedSpy.size() - << "multiplier" << scaleChangedSpy.last().first().toReal(); - QVERIFY(qFloatDistance(root->property("pinchScale").toReal(), expectedScale) < 10); - QVERIFY(qFloatDistance(blackRect->scale(), expectedScale) < 10); + << "multiplier" << (scaleChangedSpy.isEmpty() ? 1 : scaleChangedSpy.last().first().toReal()); + if (axisEnabled) { + QVERIFY(qFloatDistance(root->property("pinchScale").toReal(), expectedScale) < 10); + QVERIFY(qFloatDistance(blackRect->scale(), expectedScale) < 10); + } else { + QCOMPARE(root->property("pinchScale").toInt(), 1); + QCOMPARE(blackRect->scale(), 1); + } QCOMPARE(pinchHandler->persistentScale(), root->property("pinchScale").toReal()); QCOMPARE(pinchHandler->persistentScale(), pinchHandler->activeScale()); // in sync for the first gesture QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), pinchHandler->activeScale()); QCOMPARE(pinchHandler->scaleAxis()->activeValue(), pinchHandler->activeScale()); - const qreal expectedIncrement = pinchHandler->activeScale() / lastScale; - QCOMPARE(scaleChangedSpy.size(), i + 1); - QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); + expectedIncrement = pinchHandler->activeScale() / lastScale; + QCOMPARE(scaleChangedSpy.size(), axisEnabled ? i + 1 : 0); + if (axisEnabled) + QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); QPointF expectedCentroid = p0 + (p1 - p0) / 2; QCOMPARE(pinchHandler->centroid().scenePosition(), expectedCentroid); } - qreal lastScale = pinchHandler->persistentScale(); + lastScale = pinchHandler->persistentScale(); pinchSequence.release(0, p0, &window).release(1, p1, &window).commit(); QQuickTouchUtils::flush(&window); if (lcPointerTests().isDebugEnabled()) QTest::qWait(500); @@ -328,21 +341,29 @@ void tst_QQuickPinchHandler::scale() pinchSequence.stationary(0).move(1, p1, &window).commit(); QQuickTouchUtils::flush(&window); if (lcPointerTests().isDebugEnabled()) QTest::qWait(500); - QCOMPARE_GT(pinchHandler->persistentScale(), lastScale); + if (axisEnabled) + QCOMPARE_GT(pinchHandler->persistentScale(), lastScale); + else + QCOMPARE(pinchHandler->persistentScale(), 1); line.setP2(p1); qreal expectedActiveScale = line.length() / startLength; qCDebug(lcPointerTests) << i << "activeScale" << pinchHandler->activeScale() << "expected" << expectedActiveScale << "; scale" << pinchHandler->persistentScale() << "increments" << scaleChangedSpy.size() - << "multiplier" << scaleChangedSpy.last().first().toReal(); - QVERIFY(qFloatDistance(pinchHandler->activeScale(), expectedActiveScale) < 10); + << "multiplier" << (scaleChangedSpy.isEmpty() ? 1 : scaleChangedSpy.last().first().toReal()); + if (axisEnabled) { + QVERIFY(qFloatDistance(pinchHandler->activeScale(), expectedActiveScale) < 10); + QCOMPARE_NE(pinchHandler->persistentScale(), pinchHandler->activeScale()); // not in sync anymore + } else { + QCOMPARE(pinchHandler->persistentScale(), pinchHandler->activeScale()); + } QCOMPARE(pinchHandler->persistentScale(), root->property("pinchScale").toReal()); QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), root->property("pinchScale").toReal()); - QCOMPARE_NE(pinchHandler->persistentScale(), pinchHandler->activeScale()); // not in sync anymore QCOMPARE(pinchHandler->scaleAxis()->activeValue(), pinchHandler->activeScale()); - const qreal expectedIncrement = pinchHandler->persistentScale() / lastScale; - QCOMPARE(scaleChangedSpy.size(), i + 3); - QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); + expectedIncrement = pinchHandler->persistentScale() / lastScale; + QCOMPARE(scaleChangedSpy.size(), axisEnabled ? i + 3 : 0); + if (axisEnabled) + QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); } // scale beyond maximumScale @@ -351,12 +372,13 @@ void tst_QQuickPinchHandler::scale() pinchSequence.stationary(0).move(1, p1, &window).commit(); QQuickTouchUtils::flush(&window); if (lcPointerTests().isDebugEnabled()) QTest::qWait(500); - QCOMPARE(blackRect->scale(), qreal(4)); - QCOMPARE(pinchHandler->persistentScale(), qreal(4)); // limited by maximumScale - QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), 4); - const qreal expectedIncrement = pinchHandler->activeScale() / lastScale; - QCOMPARE(scaleChangedSpy.size(), 5); - QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); + QCOMPARE(blackRect->scale(), axisEnabled ? 4 : 1); + QCOMPARE(pinchHandler->persistentScale(), axisEnabled ? 4 : 1); // limited by maximumScale + QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), axisEnabled ? 4 : 1); + expectedIncrement = pinchHandler->activeScale() / lastScale; + QCOMPARE(scaleChangedSpy.size(), axisEnabled ? 5 : 0); + if (axisEnabled) + QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); pinchSequence.release(0, p0, &window).release(1, p1, &window).commit(); QQuickTouchUtils::flush(&window); QCOMPARE(pinchHandler->active(), false); @@ -559,19 +581,25 @@ void tst_QQuickPinchHandler::cumulativeNativeGestures_data() QTest::addColumn<const QPointingDevice*>("device"); QTest::addColumn<Qt::NativeGestureType>("gesture"); QTest::addColumn<qreal>("value"); + QTest::addColumn<bool>("scalingEnabled"); + QTest::addColumn<bool>("rotationEnabled"); QTest::addColumn<QList<QPoint>>("expectedTargetTranslations"); const auto *touchpadDevice = touchpad.get(); const auto *mouse = QPointingDevice::primaryPointingDevice(); - QTest::newRow("touchpad: rotate") << touchpadDevice << Qt::RotateNativeGesture << 5.0 + QTest::newRow("touchpad: rotate") << touchpadDevice << Qt::RotateNativeGesture << 5.0 << true << true << QList<QPoint>{{-2, 2}, {-5, 4}, {-7, 6}, {-10, 7}}; - QTest::newRow("touchpad: scale") << touchpadDevice << Qt::ZoomNativeGesture << 0.1 + QTest::newRow("touchpad: scale") << touchpadDevice << Qt::ZoomNativeGesture << 0.1 << true << true + << QList<QPoint>{{3, 3}, {5, 5}, {8, 8}, {12, 12}}; + QTest::newRow("touchpad: rotate disabled") << touchpadDevice << Qt::RotateNativeGesture << 5.0 << true << false + << QList<QPoint>{{-2, 2}, {-5, 4}, {-7, 6}, {-10, 7}}; + QTest::newRow("touchpad: scale disabled") << touchpadDevice << Qt::ZoomNativeGesture << 0.1 << false << true << QList<QPoint>{{3, 3}, {5, 5}, {8, 8}, {12, 12}}; if (mouse->type() == QInputDevice::DeviceType::Mouse) { - QTest::newRow("mouse: rotate") << mouse << Qt::RotateNativeGesture << 5.0 + QTest::newRow("mouse: rotate") << mouse << Qt::RotateNativeGesture << 5.0 << true << true << QList<QPoint>{{-2, 2}, {-5, 4}, {-7, 6}, {-10, 7}}; - QTest::newRow("mouse: scale") << mouse << Qt::ZoomNativeGesture << 0.1 + QTest::newRow("mouse: scale") << mouse << Qt::ZoomNativeGesture << 0.1 << true << true << QList<QPoint>{{3, 3}, {5, 5}, {8, 8}, {12, 12}}; } else { qCWarning(lcPointerTests) << "skipping mouse tests: primary device is not a mouse" << mouse; @@ -583,6 +611,8 @@ void tst_QQuickPinchHandler::cumulativeNativeGestures() QFETCH(const QPointingDevice*, device); QFETCH(Qt::NativeGestureType, gesture); QFETCH(qreal, value); + QFETCH(bool, scalingEnabled); + QFETCH(bool, rotationEnabled); QFETCH(QList<QPoint>, expectedTargetTranslations); QCOMPARE(expectedTargetTranslations.size(), 4); @@ -596,6 +626,8 @@ void tst_QQuickPinchHandler::cumulativeNativeGestures() QVERIFY(root != nullptr); QQuickPinchHandler *pinchHandler = root->findChild<QQuickPinchHandler*>("pinchHandler"); QVERIFY(pinchHandler != nullptr); + pinchHandler->scaleAxis()->setEnabled(scalingEnabled); + pinchHandler->rotationAxis()->setEnabled(rotationEnabled); QQuickItem *target = root->findChild<QQuickItem*>("blackrect"); QVERIFY(target != nullptr); QCOMPARE(pinchHandler->target(), target); @@ -622,6 +654,10 @@ void tst_QQuickPinchHandler::cumulativeNativeGestures() default: break; // PinchHandler doesn't react to the others } + if (!rotationEnabled) + expectedRotation = 0; + if (!scalingEnabled) + expectedScale = 1; qCDebug(lcPointerTests) << i << gesture << "with value" << value << ": scale" << target->scale() << "expected" << expectedScale @@ -643,8 +679,10 @@ void tst_QQuickPinchHandler::cumulativeNativeGestures() qCDebug(lcPointerTests) << "target moved by" << delta << "to" << target->position() << "active trans" << pinchHandler->activeTranslation() << "perst trans" << pinchHandler->persistentTranslation(); - QCOMPARE_NE(target->position(), initialTargetPos); - QCOMPARE(delta.toPoint(), expectedTargetTranslations.at(i - 1)); + if (scalingEnabled && rotationEnabled) { + QCOMPARE_NE(target->position(), initialTargetPos); + QCOMPARE(delta.toPoint(), expectedTargetTranslations.at(i - 1)); + } // The native pinch gesture cannot include a translation component (and // the cursor doesn't move while you are performing the gesture on a touchpad). QCOMPARE(pinchHandler->activeTranslation(), QPointF()); |