From 71660c9700f15e224f7bfd8080f58a4f0e1a85e2 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 6 May 2022 16:31:37 +0200 Subject: QQuickFlickable: fix flicking when item is rotated QEventPoint::velocity() is in screen coordinates, as documented; it needs to be transformed to local coordinates in case the Flickable is rotated and/or scaled. windowToItemTransform() gives us a composite transform matrix; we remove the translation components to get only the rotation and scaling. Also fix the press position calculation in handleReleaseEvent(). With the manual test one can pinch to scale and rotate a Flickable, then verify that with a single finger, the Flickable gets scrolled by an appropriate distance in spite of that. Done-with: Ivan Solovev Fixes: QTBUG-99639 Change-Id: I60af1dd932835d358baa1422523cc24b2ab046a0 Reviewed-by: Ivan Solovev Reviewed-by: Paul Olav Tvete (cherry picked from commit 8068bde891eefe99a43deb83e58166b476f65225) Reviewed-by: Qt Cherry-pick Bot --- .../qquickflickable/data/rotatedFlickable.qml | 32 +++++++++ .../quick/qquickflickable/tst_qquickflickable.cpp | 53 ++++++++++++++ tests/manual/pointer/pinchFlickable.qml | 84 ++++++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 tests/auto/quick/qquickflickable/data/rotatedFlickable.qml create mode 100644 tests/manual/pointer/pinchFlickable.qml (limited to 'tests') diff --git a/tests/auto/quick/qquickflickable/data/rotatedFlickable.qml b/tests/auto/quick/qquickflickable/data/rotatedFlickable.qml new file mode 100644 index 0000000000..04816c178b --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/rotatedFlickable.qml @@ -0,0 +1,32 @@ +import QtQuick 2.0 + +Item { + width: 300 + height: 300 + + Flickable { + id: flickable + anchors.fill: parent + contentHeight: column.height + flickDeceleration: 5000 // speed up the test run + + Column { + id: column + width: parent.width + + Repeater { + model: 255 + + delegate: Rectangle { + width: column.width + height: 50 + color: "gray" + Text { + anchors.centerIn: parent + text: index + } + } + } + } + } +} diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index ad785f069f..9682079e84 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -236,6 +236,8 @@ private slots: void ignoreNonLeftMouseButtons(); void ignoreNonLeftMouseButtons_data(); void receiveTapOutsideContentItem(); + void flickWhenRotated_data(); + void flickWhenRotated(); private: void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to); @@ -2800,6 +2802,57 @@ void tst_qquickflickable::receiveTapOutsideContentItem() QCOMPARE(clickedSpy.count(), 2); } +void tst_qquickflickable::flickWhenRotated_data() +{ + QTest::addColumn("rootRotation"); + QTest::addColumn("flickableRotation"); + QTest::addColumn("scale"); + + static constexpr qreal rotations[] = { 0, 30, 90, 180, 270 }; + static constexpr qreal scales[] = { 0.3, 1, 1.5 }; + + for (const auto pr : rotations) { + for (const auto fr : rotations) { + if (pr <= 90) { + for (const auto s : scales) + QTest::addRow("parent: %g, flickable: %g, scale: %g", pr, fr) << pr << fr << s; + } else { + // don't bother trying every scale with every set of rotations, to save time + QTest::addRow("parent: %g, flickable: %g, scale: 1", pr, fr) << pr << fr << qreal(1); + } + } + } +} + +void tst_qquickflickable::flickWhenRotated() // QTBUG-99639 +{ + QFETCH(qreal, rootRotation); + QFETCH(qreal, flickableRotation); + QFETCH(qreal, scale); + + QQuickView window; + QVERIFY(QQuickTest::showView(window, testFileUrl("rotatedFlickable.qml"))); + QQuickItem *rootItem = window.rootObject(); + QVERIFY(rootItem); + QQuickFlickable *flickable = rootItem->findChild(); + QVERIFY(flickable); + + rootItem->setRotation(rootRotation); + flickable->setRotation(flickableRotation); + rootItem->setScale(scale); + QVERIFY(flickable->isAtYBeginning()); + + // Flick in Y direction in Flickable's coordinate system and check how much it moved + const QPointF startPoint = flickable->mapToGlobal(QPoint(20, 180)); + const QPointF endPoint = flickable->mapToGlobal(QPoint(20, 40)); + flick(&window, window.mapFromGlobal(startPoint).toPoint(), window.mapFromGlobal(endPoint).toPoint(), 100); + QTRY_VERIFY(flickable->isMoving()); + QTRY_VERIFY(!flickable->isMoving()); + qCDebug(lcTests) << "flicking from" << startPoint << "to" << endPoint << ": ended at contentY" << flickable->contentY(); + // usually flickable->contentY() is at 275 or very close + QVERIFY(!flickable->isAtYBeginning()); +} + QTEST_MAIN(tst_qquickflickable) #include "tst_qquickflickable.moc" diff --git a/tests/manual/pointer/pinchFlickable.qml b/tests/manual/pointer/pinchFlickable.qml new file mode 100644 index 0000000000..48a00b4b1b --- /dev/null +++ b/tests/manual/pointer/pinchFlickable.qml @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick + +Item { + width: 300 + height: 300 + + Flickable { + id: flickable + anchors.fill: parent + contentHeight: column.height + + Column { + id: column + width: parent.width + + Repeater { + model: 255 + + delegate: Rectangle { + width: column.width + height: 50 + color: flickable.dragging ? "steelblue" : "gray" + Text { + anchors.centerIn: parent + text: index + } + } + } + } + } + PinchHandler { + target: flickable + } +} -- cgit v1.2.3