summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2021-05-03 20:33:56 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2021-05-05 06:17:06 +0200
commitdefe68463230b454d3ddfb039ca423c01cddab91 (patch)
tree2ab1e3d9da35d3532a8f42b2b1d3de7636bdfb22
parentdb2bf9152013c97753d10ed46b05b59b6ab22849 (diff)
Make PinchArea translate correctly inside a rotated parent
Also includes 9dacc312e5b0f5aeb0f8370f4f7722b57754a3c2: fuzzy comparison in the test to avoid failure due to roundoff. Fixes: QTBUG-63673 Change-Id: I91231bb8555b7eb02a9580f9f184b261d8bd44c8 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io> (cherry picked from commit 7642205be45135add120373299df02e05f4ffc58) Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
-rw-r--r--src/quick/items/qquickpincharea.cpp8
-rw-r--r--tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml70
-rw-r--r--tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp66
3 files changed, 143 insertions, 1 deletions
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index b41815d88b..ed8506b440 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -563,7 +563,10 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
setKeepTouchGrab(true);
d->inPinch = true;
if (d->pinch && d->pinch->target()) {
- d->pinchStartPos = pinch()->target()->position();
+ auto targetParent = pinch()->target()->parentItem();
+ d->pinchStartPos = targetParent ?
+ targetParent->mapToScene(pinch()->target()->position()) :
+ pinch()->target()->position();
d->pinchStartScale = d->pinch->target()->scale();
d->pinchStartRotation = d->pinch->target()->rotation();
d->pinch->setActive(true);
@@ -611,6 +614,9 @@ void QQuickPinchArea::updatePinchTarget()
s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale());
pinch()->target()->setScale(s);
QPointF pos = d->sceneLastCenter - d->sceneStartCenter + d->pinchStartPos;
+ if (auto targetParent = pinch()->target()->parentItem())
+ pos = targetParent->mapFromScene(pos);
+
if (pinch()->axis() & QQuickPinch::XAxis) {
qreal x = pos.x();
if (x < pinch()->xmin())
diff --git a/tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml b/tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml
new file mode 100644
index 0000000000..3acf67b4b6
--- /dev/null
+++ b/tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml
@@ -0,0 +1,70 @@
+import QtQuick 2.12
+
+Rectangle {
+ id: root
+ width: 600
+ height: 600
+
+ Rectangle {
+ objectName: "paContainer"
+ width: parent.width -100
+ height: parent.height - 100
+ border.color: "black"
+ anchors.centerIn: parent
+ transformOrigin: Item.Center
+
+ Rectangle {
+ width: 300
+ height: 300
+ color: "tomato"
+ PinchArea {
+ id: pa
+ anchors.fill: parent
+ pinch.target: parent
+ pinch.minimumScale: 0.5
+ pinch.maximumScale: 2
+ pinch.minimumRotation: -360
+ pinch.maximumRotation: 360
+ pinch.dragAxis: Pinch.XAndYAxis
+ pinch.minimumX: -100
+ pinch.maximumX: 300
+ pinch.minimumY: -100
+ pinch.maximumY: 300
+ }
+
+
+ Text { text: "this way up" }
+ }
+ }
+
+ // only for touch feedback / troubleshooting
+ Item {
+ id: glassPane
+ z: 10000
+ anchors.fill: parent
+
+ PointHandler {
+ id: ph1
+ target: Rectangle {
+ parent: glassPane
+ color: "green"
+ visible: ph1.active
+ x: ph1.point.position.x - width / 2
+ y: ph1.point.position.y - height / 2
+ width: 20; height: width; radius: width / 2
+ }
+ }
+
+ PointHandler {
+ id: ph2
+ target: Rectangle {
+ parent: glassPane
+ color: "blue"
+ visible: ph2.active
+ x: ph2.point.position.x - width / 2
+ y: ph2.point.position.y - height / 2
+ width: 20; height: width; radius: width / 2
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
index a9f35e8727..55fb07f744 100644
--- a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
+++ b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
@@ -52,6 +52,8 @@ private slots:
void cancel();
void transformedPinchArea_data();
void transformedPinchArea();
+ void dragTransformedPinchArea_data();
+ void dragTransformedPinchArea();
private:
QQuickView *createView();
@@ -576,6 +578,70 @@ void tst_QQuickPinchArea::transformedPinchArea()
}
}
+void tst_QQuickPinchArea::dragTransformedPinchArea_data()
+{
+ QTest::addColumn<int>("rotation");
+ QTest::addColumn<QPoint>("p1");
+ QTest::addColumn<QPoint>("p2");
+ QTest::addColumn<QPoint>("delta");
+
+ QTest::newRow("unrotated")
+ << 0 << QPoint(100, 100) << QPoint(200, 100) << QPoint(40, 40);
+ QTest::newRow("20 deg")
+ << 20 << QPoint(100, 100) << QPoint(200, 100) << QPoint(40, 40);
+ QTest::newRow("90 deg")
+ << 90 << QPoint(100, 100) << QPoint(200, 100) << QPoint(0, 40);
+ QTest::newRow("180 deg")
+ << 180 << QPoint(100, 100) << QPoint(200, 100) << QPoint(40, 0);
+ QTest::newRow("225 deg")
+ << 210 << QPoint(200, 200) << QPoint(300, 200) << QPoint(80, 80);
+}
+
+void tst_QQuickPinchArea::dragTransformedPinchArea() // QTBUG-63673
+{
+ QFETCH(int, rotation);
+ QFETCH(QPoint, p1);
+ QFETCH(QPoint, p2);
+ QFETCH(QPoint, delta);
+ const int threshold = qApp->styleHints()->startDragDistance();
+
+ QQuickView *view = createView();
+ QScopedPointer<QQuickView> scope(view);
+ view->setSource(testFileUrl("draggablePinchArea.qml"));
+ view->show();
+ QVERIFY(QTest::qWaitForWindowExposed(view));
+ QVERIFY(view->rootObject());
+ QQuickPinchArea *pinchArea = view->rootObject()->findChild<QQuickPinchArea*>();
+ QVERIFY(pinchArea);
+ QQuickItem *pinchAreaTarget = pinchArea->parentItem();
+ QVERIFY(pinchAreaTarget);
+ QQuickItem *pinchAreaContainer = pinchAreaTarget->parentItem();
+ QVERIFY(pinchAreaContainer);
+ pinchAreaContainer->setRotation(rotation);
+
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(view, device);
+ // start pinch
+ pinchSequence.press(1, pinchArea->mapToScene(p1).toPoint(), view)
+ .press(2, pinchArea->mapToScene(p2).toPoint(), view).commit();
+ QQuickTouchUtils::flush(view);
+ pinchSequence.move(1, pinchArea->mapToScene(p1 + QPoint(threshold, threshold)).toPoint(), view)
+ .move(2, pinchArea->mapToScene(p2 + QPoint(threshold, threshold)).toPoint(), view).commit();
+ QQuickTouchUtils::flush(view);
+ pinchSequence.move(1, pinchArea->mapToScene(p1 + delta).toPoint(), view)
+ .move(2, pinchArea->mapToScene(p2 + delta).toPoint(), view).commit();
+ QQuickTouchUtils::flush(view);
+ QCOMPARE(pinchArea->pinch()->active(), true);
+ auto error = delta - QPoint(threshold, threshold) -
+ pinchAreaTarget->position().toPoint(); // expect 0, 0
+ QVERIFY(qAbs(error.x()) <= 1);
+ QVERIFY(qAbs(error.y()) <= 1);
+
+ // release pinch
+ pinchSequence.release(1, p1, view).release(2, p2, view).commit();
+ QQuickTouchUtils::flush(view);
+ QCOMPARE(pinchArea->pinch()->active(), false);
+}
+
QQuickView *tst_QQuickPinchArea::createView()
{
QQuickView *window = new QQuickView(nullptr);