PinchHandler null target: remember accumulated scale between pinches
This restores behavior fromb4d31c9ff5
which got broken infc636af3a7
. As documented, PinchHandler.scale is the accumulated scale that would be applied to the target item (even if there is no target), whereas activeScale is the scale during one pinch gesture. After the first gesture, these two values are supposed to diverge, even if there is no target; that way you can bind scale to some property, to scale something else in the same way that PinchHandler would normally scale its target. Pick-to: 6.2 6.4 Fixes: QTBUG-108549 Task-number: QTBUG-68941 Task-number: QTBUG-92064 Change-Id: I32ff37e394fd8466128603eddd5697ba1cc1a0ed Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
parent
b0a3a07a68
commit
3046fe153d
|
@ -203,8 +203,8 @@ void QQuickPinchHandler::onActiveChanged()
|
|||
m_startRotation = t->rotation();
|
||||
m_startPos = t->position();
|
||||
} else {
|
||||
m_startScale = 1;
|
||||
m_startRotation = 0;
|
||||
m_startScale = m_accumulatedScale;
|
||||
m_startRotation = 0; // TODO m_accumulatedRotation (QTBUG-94168)
|
||||
}
|
||||
qCDebug(lcPinchHandler) << "activated with starting scale" << m_startScale << "rotation" << m_startRotation;
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
import QtQuick 2.15
|
||||
|
||||
Item {
|
||||
width: 320; height: 320
|
||||
property alias pinchScale: pinch.scale
|
||||
|
||||
Rectangle {
|
||||
objectName: "blackrect"
|
||||
width: 200; height: 200
|
||||
color: "black"
|
||||
antialiasing: true
|
||||
scale: pinch.scale
|
||||
rotation: pinch.rotation
|
||||
x: pinch.translation.x
|
||||
y: pinch.translation.y
|
||||
|
||||
PinchHandler {
|
||||
id: pinch
|
||||
target: null
|
||||
minimumScale: 0.5
|
||||
maximumScale: 4
|
||||
}
|
||||
|
||||
Text {
|
||||
color: "cyan"
|
||||
anchors.centerIn: parent
|
||||
text: "scale " + pinch.scale.toFixed(2) + " activeScale " + pinch.activeScale.toFixed(2)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ public:
|
|||
private slots:
|
||||
void cleanupTestCase();
|
||||
void pinchProperties();
|
||||
void scale_data();
|
||||
void scale();
|
||||
void scaleThreeFingers();
|
||||
void scaleNativeGesture_data();
|
||||
|
@ -179,16 +180,26 @@ QEventPoint makeTouchPoint(int id, QPoint p, QQuickView *v, QQuickItem *i)
|
|||
return touchPoint;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void tst_QQuickPinchHandler::scale()
|
||||
{
|
||||
QQuickView window;
|
||||
QVERIFY(QQuickTest::showView(window, testFileUrl("pinchproperties.qml")));
|
||||
QFETCH(QUrl, qmlfile);
|
||||
QFETCH(bool, hasTarget);
|
||||
|
||||
QQuickView window;
|
||||
QVERIFY(QQuickTest::showView(window, qmlfile));
|
||||
QQuickItem *root = qobject_cast<QQuickItem*>(window.rootObject());
|
||||
QVERIFY(root != nullptr);
|
||||
auto *pinchHandler = static_cast<PinchHandler *>(root->findChild<QQuickPinchHandler*>());
|
||||
QVERIFY(pinchHandler != nullptr);
|
||||
QQuickItem *blackRect = pinchHandler->target();
|
||||
QQuickItem *blackRect = (hasTarget ? pinchHandler->target() : pinchHandler->parentItem());
|
||||
QVERIFY(blackRect != nullptr);
|
||||
QSignalSpy grabChangedSpy(pinchHandler, SIGNAL(grabChanged(QPointingDevice::GrabTransition, QEventPoint)));
|
||||
|
||||
|
@ -240,6 +251,40 @@ void tst_QQuickPinchHandler::scale()
|
|||
QCOMPARE(pinchHandler->centroid().scenePosition(), expectedCentroid);
|
||||
}
|
||||
|
||||
qreal lastScale = pinchHandler->scale();
|
||||
pinchSequence.release(0, p0, &window).release(1, p1, &window).commit();
|
||||
QQuickTouchUtils::flush(&window);
|
||||
if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
|
||||
// scale property is persistent after release
|
||||
QCOMPARE(pinchHandler->scale(), lastScale);
|
||||
|
||||
// pinch a second time: scale picks up where we left off
|
||||
p0 = QPoint(80, 80);
|
||||
p1 = QPoint(100, 100);
|
||||
pinchSequence.press(0, p0, &window).press(1, p1, &window).commit();
|
||||
// move one point until PinchHandler activates
|
||||
for (int pi = 0; pi < 10 && !pinchHandler->active(); ++pi) {
|
||||
p1 += pd;
|
||||
pinchSequence.stationary(0).move(1, p1, &window).commit();
|
||||
QQuickTouchUtils::flush(&window);
|
||||
}
|
||||
if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
|
||||
QCOMPARE(pinchHandler->active(), true);
|
||||
QCOMPARE(pinchHandler->scale(), lastScale); // just activated, not scaling further yet
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
lastScale = pinchHandler->scale();
|
||||
p1 += pd;
|
||||
pinchSequence.stationary(0).move(1, p1, &window).commit();
|
||||
QQuickTouchUtils::flush(&window);
|
||||
if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
|
||||
QCOMPARE_GT(pinchHandler->scale(), lastScale);
|
||||
line.setP2(p1);
|
||||
qreal expectedActiveScale = line.length() / startLength;
|
||||
QVERIFY(qFloatDistance(pinchHandler->activeScale(), expectedActiveScale) < 10);
|
||||
QCOMPARE(pinchHandler->scale(), root->property("pinchScale").toReal());
|
||||
QCOMPARE_NE(pinchHandler->scale(), pinchHandler->activeScale()); // not in sync anymore
|
||||
}
|
||||
|
||||
// scale beyond maximumScale
|
||||
p1 = QPoint(310, 310);
|
||||
pinchSequence.stationary(0).move(1, p1, &window).commit();
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
import QtQuick 2.15
|
||||
|
||||
Rectangle {
|
||||
width: 1024; height: 600
|
||||
color: "#eee"
|
||||
|
||||
function getTransformationDetails(item, pinchhandler) {
|
||||
return "\n\npinch.scale:" + pinchhandler.scale.toFixed(2)
|
||||
+ "\npinch.activeScale:" + pinchhandler.activeScale.toFixed(2)
|
||||
+ "\npinch.rotation:" + pinchhandler.rotation.toFixed(2)
|
||||
+ "\npinch.translation:" + "(" + pinchhandler.translation.x.toFixed(2) + "," + pinchhandler.translation.y.toFixed(2) + ")"
|
||||
+ "\nrect.scale: " + item.scale.toFixed(2)
|
||||
+ "\nrect.rotation: " + item.rotation.toFixed(2)
|
||||
+ "\nrect.position: " + "(" + item.x.toFixed(2) + "," + item.y.toFixed(2) + ")"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width - 100; height: parent.height - 100; x: 50; y: 50
|
||||
color: "lightsteelblue"
|
||||
antialiasing: true
|
||||
scale: pinch.scale
|
||||
|
||||
PinchHandler {
|
||||
id: pinch
|
||||
target: null
|
||||
minimumScale: 0.5
|
||||
maximumScale: 3
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Pinch with 2 fingers to scale, rotate and translate"
|
||||
+ getTransformationDetails(parent, pinch)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: centroidIndicator
|
||||
x: pinch.centroid.scenePosition.x - radius
|
||||
y: pinch.centroid.scenePosition.y - radius
|
||||
z: 1
|
||||
visible: pinch.active
|
||||
radius: width / 2
|
||||
width: 10
|
||||
height: width
|
||||
color: "red"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue