diff options
Diffstat (limited to 'tests/auto/quick/pointerhandlers')
9 files changed, 620 insertions, 1 deletions
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp index cd18580ccf..35fed99e8b 100644 --- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp +++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp @@ -137,7 +137,6 @@ void tst_MptaInterop::touchDrag() // TODO touchesThenPinch_data with press/release sequences somehow: vectors of touchpoint IDs? or a string representation? void tst_MptaInterop::touchesThenPinch() { - const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); QScopedPointer<QQuickView> windowPtr; createView(windowPtr, "pinchDragMPTA.qml"); QQuickView * window = windowPtr.data(); diff --git a/tests/auto/quick/pointerhandlers/pointerhandlers.pro b/tests/auto/quick/pointerhandlers/pointerhandlers.pro index 950d6835eb..4d6311bdb2 100644 --- a/tests/auto/quick/pointerhandlers/pointerhandlers.pro +++ b/tests/auto/quick/pointerhandlers/pointerhandlers.pro @@ -10,4 +10,5 @@ qtConfig(private_tests) { qquickpointerhandler \ qquickpointhandler \ qquicktaphandler \ + qquickwheelhandler \ } diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml new file mode 100644 index 0000000000..d6eb791700 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 + +Item { + id: root + objectName: "snapMode" + width: 640 + height: 480 + + Rectangle { + id: rect1 + objectName: "rect1" + width: 90 + height: 100 + x: 100 + y: 100 + color: "teal" + + Rectangle { + width: parent.width/2 + height: parent.width/2 + x: width/2 + y: -x + color: dragHandler1.active ? "red" : "salmon" + + DragHandler { + id: dragHandler1 + objectName: "dragHandler1" + target: rect1 + } + } + } + + + Rectangle { + id: rect2 + objectName: "rect2" + width: 90 + height: 100 + x: 200 + y: 100 + color: "teal" + + DragHandler { + id: dragHandler2 + objectName: "dragHandler2" + target: rect2b + } + + Rectangle { + id: rect2b + width: parent.width/2 + height: parent.width/2 + anchors.horizontalCenter: parent.horizontalCenter + y: -width/2 + color: dragHandler2.active ? "red" : "salmon" + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro b/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro index 42c4e46c4f..6258fb9392 100644 --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro @@ -19,3 +19,4 @@ OTHER_FILES += data/DragAnywhereSlider.qml \ data/grabberstate.qml \ data/multipleSliders.qml \ data/reparenting.qml \ + data/snapMode.qml \ diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp index fb0192893f..66314f88a2 100644 --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp @@ -57,6 +57,8 @@ private slots: void mouseDrag_data(); void mouseDrag(); void dragFromMargin(); + void snapMode_data(); + void snapMode(); void touchDragMulti(); void touchDragMultiSliders_data(); void touchDragMultiSliders(); @@ -312,6 +314,78 @@ void tst_DragHandler::dragFromMargin() // QTBUG-74966 QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton); } +void tst_DragHandler::snapMode_data() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QTest::addColumn<QString>("subTree"); + QTest::addColumn<int>("snapMode"); + QTest::addColumn<QPoint>("startDragPos"); + QTest::addColumn<QPoint>("dragMovement"); + QTest::addColumn<QPoint>("expectedMovement"); + + struct TestEntry { + const char *desc; + const char *subTree; + QQuickDragHandler::SnapMode mode; + QPoint startDragPos; + QPoint dragMovement; + QPoint expectedMovement; + }; + + TestEntry testdata[] = { + {"outside the target", "rect1", QQuickDragHandler::SnapAuto, QPoint(45, -10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, 0)}, + {"inside the target", "rect1", QQuickDragHandler::SnapAuto, QPoint(45, 10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, 0)}, + {"outside the target", "rect1", QQuickDragHandler::SnapAlways, QPoint(45, -10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, -50-10)}, + {"outside the target", "rect1", QQuickDragHandler::NoSnap, QPoint(45, -10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, 0)}, + {"outside the target", "rect1", QQuickDragHandler::SnapIfPressedOutsideTarget, QPoint(45, -10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, -50-10)}, + {"inside the target", "rect1", QQuickDragHandler::SnapIfPressedOutsideTarget, QPoint(45, 10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, 0)}, + //targets y pos moves from -25 to (25 + dragThreshold*2) because of snapping to center: + {"outside target, should snap", "rect2", QQuickDragHandler::SnapAuto, QPoint(45, 50), QPoint(0, dragThreshold*2), QPoint(0, 25 + 25 + dragThreshold*2)}, + {"inside target, shouldn't snap", "rect2", QQuickDragHandler::SnapAuto, QPoint(45, 10), QPoint(0, dragThreshold*2), QPoint(0, dragThreshold*2)} + }; + + for (const TestEntry& e : testdata) { + const QMetaEnum menum = QMetaEnum::fromType<QQuickDragHandler::SnapMode>(); + const QString dataTag = QString::fromLatin1("%1, %2, %3").arg(e.subTree).arg(menum.valueToKey(e.mode)).arg(e.desc); + QTest::newRow(dataTag.toUtf8().constData()) << e.subTree << (int)e.mode + << e.startDragPos << e.dragMovement << e.expectedMovement; + } +} + +void tst_DragHandler::snapMode() +{ + QFETCH(QString, subTree); + QFETCH(QPoint, startDragPos); + QFETCH(QPoint, dragMovement); + QFETCH(int, snapMode); + QFETCH(QPoint, expectedMovement); + + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "snapMode.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *rect1 = window->rootObject()->findChild<QQuickItem*>(subTree); + QVERIFY(rect1); + QQuickItem *rect1b = rect1->childItems().first(); + QVERIFY(rect1b); + QQuickDragHandler *dragHandler1 = rect1->findChild<QQuickDragHandler*>(); + QVERIFY(dragHandler1); + dragHandler1->setSnapMode((QQuickDragHandler::SnapMode)snapMode); + QQuickItem *dragTarget = dragHandler1->target(); + QPointF oldTargetPos = dragTarget->position(); + + QPoint p1 = rect1->mapToScene(QPointF(startDragPos)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!dragHandler1->active()); + p1 += dragMovement; + QTest::mouseMove(window, p1); + QTRY_VERIFY(dragHandler1->active()); + QCOMPARE(dragTarget->position(), oldTargetPos + expectedMovement); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!dragHandler1->active()); + QCOMPARE(dragHandler1->centroid().pressedButtons(), Qt::NoButton); +} + void tst_DragHandler::touchDragMulti() { const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); diff --git a/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/nested.qml b/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/nested.qml new file mode 100644 index 0000000000..49e44f2b1f --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/nested.qml @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.14 + +Rectangle { + width: 320; height: 240 + color: "lightsteelblue"; antialiasing: true + border.color: outerWheelHandler.active ? "red" : "white" + + WheelHandler { + id: outerWheelHandler + objectName: "outerWheelHandler" + property: "x" + } + + Rectangle { + width: 120; height: 120; x: 100; y: 60 + color: "beige"; antialiasing: true + border.color: innerWheelHandler.active ? "red" : "white" + + WheelHandler { + id: innerWheelHandler + objectName: "innerWheelHandler" + // TODO should ideally deactivate because events go to the outer handler, not because of timeout + activeTimeout: 0.5 + property: "x" + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/rectWheel.qml b/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/rectWheel.qml new file mode 100644 index 0000000000..d4875d5313 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/rectWheel.qml @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.14 + +Rectangle { + width: 320; height: 240 + color: "green"; antialiasing: true + + Rectangle { + width: 100; height: 2; anchors.centerIn: parent + Rectangle { + width: 2; height: 100; anchors.centerIn: parent + } + } + + WheelHandler { + activeTimeout: 0.5 + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickwheelhandler/qquickwheelhandler.pro b/tests/auto/quick/pointerhandlers/qquickwheelhandler/qquickwheelhandler.pro new file mode 100644 index 0000000000..7509e38dd3 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickwheelhandler/qquickwheelhandler.pro @@ -0,0 +1,14 @@ +CONFIG += testcase +TARGET = tst_qquickwheelhandler +macos:CONFIG -= app_bundle + +SOURCES += tst_qquickwheelhandler.cpp +OTHER_FILES = \ + data/rectWheel.qml \ + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +QT += core-private gui-private qml-private quick-private testlib diff --git a/tests/auto/quick/pointerhandlers/qquickwheelhandler/tst_qquickwheelhandler.cpp b/tests/auto/quick/pointerhandlers/qquickwheelhandler/tst_qquickwheelhandler.cpp new file mode 100644 index 0000000000..2abf2ea8c3 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickwheelhandler/tst_qquickwheelhandler.cpp @@ -0,0 +1,344 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtTest/QSignalSpy> +#include <QtGui/QStyleHints> +#include <qpa/qwindowsysteminterface.h> +#include <private/qquickwheelhandler_p.h> +#include <QtQuick/private/qquickrectangle_p.h> +#include <QtQuick/qquickview.h> +#include <QtQml/qqmlcontext.h> +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_QQuickWheelHandler: public QQmlDataTest +{ + Q_OBJECT +public: + tst_QQuickWheelHandler() { } + +private slots: + void singleHandler_data(); + void singleHandler(); + void nestedHandler_data(); + void nestedHandler(); + +private: + void sendWheelEvent(QQuickView &window, QPoint pos, QPoint angleDelta, + QPoint pixelDelta = QPoint(), Qt::KeyboardModifiers modifiers = Qt::NoModifier, + Qt::ScrollPhase phase = Qt::NoScrollPhase, bool inverted = false); +}; + +void tst_QQuickWheelHandler::sendWheelEvent(QQuickView &window, QPoint pos, QPoint angleDelta, + QPoint pixelDelta, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase, bool inverted) +{ + QWheelEvent wheelEvent(pos, window.mapToGlobal(pos), pixelDelta, angleDelta, + Qt::NoButton, modifiers, phase, inverted); + QGuiApplication::sendEvent(&window, &wheelEvent); + qApp->processEvents(); +} + +void tst_QQuickWheelHandler::singleHandler_data() +{ + // handler properties + QTest::addColumn<Qt::Orientation>("orientation"); + QTest::addColumn<bool>("invertible"); + QTest::addColumn<int>("rotationScale"); + QTest::addColumn<QString>("property"); + QTest::addColumn<qreal>("targetScaleMultiplier"); + QTest::addColumn<bool>("targetTransformAroundCursor"); + // event + QTest::addColumn<QPoint>("eventPos"); + QTest::addColumn<QPoint>("eventAngleDelta"); + QTest::addColumn<QPoint>("eventPixelDelta"); + QTest::addColumn<Qt::KeyboardModifiers>("eventModifiers"); + QTest::addColumn<bool>("eventPhases"); + QTest::addColumn<bool>("eventInverted"); + // result + QTest::addColumn<QPoint>("expectedPosition"); + QTest::addColumn<qreal>("expectedScale"); + QTest::addColumn<int>("expectedRotation"); + + // move the item + QTest::newRow("vertical wheel angle delta to adjust x") + << Qt::Vertical << false << 1 << "x" << 1.5 << true + << QPoint(160, 120) << QPoint(-360, 120) << QPoint() << Qt::KeyboardModifiers(Qt::NoModifier) << false << false + << QPoint(15, 0) << 1.0 << 0; + QTest::newRow("horizontal wheel angle delta to adjust y") + << Qt::Horizontal << false << 1 << "y" << 1.5 << false + << QPoint(160, 120) << QPoint(-360, 120) << QPoint() << Qt::KeyboardModifiers(Qt::NoModifier) << false << false + << QPoint(0, -45) << 1.0 << 0; + QTest::newRow("vertical wheel angle delta to adjust y, amplified and inverted") + << Qt::Vertical << true << 4 << "y" << 1.5 << true + << QPoint(160, 120) << QPoint(60, 60) << QPoint() << Qt::KeyboardModifiers(Qt::NoModifier) << false << true + << QPoint(0, 30) << 1.0 << 0; + QTest::newRow("horizontal wheel angle delta to adjust x, amplified and reversed") + << Qt::Horizontal << false << -4 << "x" << 1.5 << false + << QPoint(160, 120) << QPoint(60, 60) << QPoint() << Qt::KeyboardModifiers(Qt::NoModifier) << false << false + << QPoint(-30, 0) << 1.0 << 0; + QTest::newRow("vertical wheel pixel delta to adjust x") + << Qt::Vertical << false << 1 << "x" << 1.5 << true + << QPoint(160, 120) << QPoint(-360, 120) << QPoint(20, 20) << Qt::KeyboardModifiers(Qt::NoModifier) << true << false + << QPoint(20, 0) << 1.0 << 0; + QTest::newRow("horizontal wheel pixel delta to adjust y") + << Qt::Horizontal << false << 1 << "y" << 1.5 << false + << QPoint(160, 120) << QPoint(-360, 120) << QPoint(20, 20) << Qt::KeyboardModifiers(Qt::NoModifier) << true << false + << QPoint(0, 20) << 1.0 << 0; + QTest::newRow("vertical wheel pixel delta to adjust y, amplified and inverted") + << Qt::Vertical << true << 4 << "y" << 1.5 << true + << QPoint(160, 120) << QPoint(60, 60) << QPoint(20, 20) << Qt::KeyboardModifiers(Qt::NoModifier) << true << true + << QPoint(0, 80) << 1.0 << 0; + QTest::newRow("horizontal wheel pixel delta to adjust x, amplified and reversed") + << Qt::Horizontal << false << -4 << "x" << 1.5 << false + << QPoint(160, 120) << QPoint(60, 60) << QPoint(20, 20) << Qt::KeyboardModifiers(Qt::NoModifier) << true << false + << QPoint(-80, 0) << 1.0 << 0; + + // scale the item + QTest::newRow("vertical wheel angle delta to adjust scale") + << Qt::Vertical << false << 1 << "scale" << 1.5 << true + << QPoint(50, 32) << QPoint(360, 120) << QPoint() << Qt::KeyboardModifiers(Qt::NoModifier) << false << false + << QPoint(55, 44) << 1.5 << 0; + QTest::newRow("horizontal wheel angle delta to adjust scale, amplified and reversed, don't adjust position") + << Qt::Horizontal << false << -2 << "scale" << 1.5 << false + << QPoint(50, 32) << QPoint(-240, 360) << QPoint() << Qt::KeyboardModifiers(Qt::NoModifier) << false << false + << QPoint(0, 0) << 5.0625 << 0; + + // rotate the item + QTest::newRow("vertical wheel angle delta to adjust rotation") + << Qt::Vertical << false << 1 << "rotation" << 1.5 << true + << QPoint(50, 32) << QPoint(360, -120) << QPoint() << Qt::KeyboardModifiers(Qt::NoModifier) << false << false + << QPoint(19, -31) << 1.0 << -15; + QTest::newRow("horizontal wheel angle delta to adjust rotation, amplified and reversed, don't adjust position") + << Qt::Horizontal << false << -2 << "rotation" << 1.5 << false + << QPoint(80, 80) << QPoint(240, 360) << QPoint() << Qt::KeyboardModifiers(Qt::NoModifier) << false << false + << QPoint(0, 0) << 1.0 << -60; +} + +void tst_QQuickWheelHandler::singleHandler() +{ + // handler properties + QFETCH(Qt::Orientation, orientation); + QFETCH(bool, invertible); + QFETCH(int, rotationScale); + QFETCH(QString, property); + QFETCH(qreal, targetScaleMultiplier); + QFETCH(bool, targetTransformAroundCursor); + // event + QFETCH(QPoint, eventPos); + QFETCH(QPoint, eventAngleDelta); + QFETCH(QPoint, eventPixelDelta); + QFETCH(Qt::KeyboardModifiers, eventModifiers); + QFETCH(bool, eventPhases); + QFETCH(bool, eventInverted); + // result + QFETCH(QPoint, expectedPosition); + QFETCH(qreal, expectedScale); + QFETCH(int, expectedRotation); + + QQuickView window; + QByteArray errorMessage; + QVERIFY2(QQuickTest::initView(window, testFileUrl("rectWheel.qml"), true, &errorMessage), errorMessage.constData()); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + QQuickItem *rect = window.rootObject(); + QVERIFY(rect != nullptr); + QQuickWheelHandler *handler = rect->findChild<QQuickWheelHandler*>(); + QVERIFY(handler != nullptr); + handler->setOrientation(orientation); + handler->setInvertible(invertible); + handler->setRotationScale(rotationScale); + handler->setProperty(property); + handler->setTargetScaleMultiplier(targetScaleMultiplier); + handler->setTargetTransformAroundCursor(targetTransformAroundCursor); + QSignalSpy activeChangedSpy(handler, SIGNAL(activeChanged())); + + if (eventPhases) { + sendWheelEvent(window, eventPos, QPoint(), QPoint(), eventModifiers, Qt::ScrollBegin, eventInverted); + sendWheelEvent(window, eventPos, eventAngleDelta, eventPixelDelta, eventModifiers, Qt::ScrollUpdate, eventInverted); + } else { + sendWheelEvent(window, eventPos, eventAngleDelta, eventPixelDelta, eventModifiers, Qt::NoScrollPhase, eventInverted); + } + QCOMPARE(rect->position().toPoint(), expectedPosition); + QCOMPARE(activeChangedSpy.count(), 1); + QCOMPARE(handler->active(), true); + QCOMPARE(rect->scale(), expectedScale); + QCOMPARE(rect->rotation(), expectedRotation); + if (!eventPhases) { + QTRY_COMPARE(handler->active(), false); + QCOMPARE(activeChangedSpy.count(), 2); + } + + // restore by rotating backwards + if (eventPhases) { + sendWheelEvent(window, eventPos, eventAngleDelta * -1, eventPixelDelta * -1, eventModifiers, Qt::ScrollUpdate, eventInverted); + sendWheelEvent(window, eventPos, QPoint(), QPoint(), eventModifiers, Qt::ScrollEnd, eventInverted); + } else { + sendWheelEvent(window, eventPos, eventAngleDelta * -1, eventPixelDelta * -1, eventModifiers, Qt::NoScrollPhase, eventInverted); + } + QCOMPARE(activeChangedSpy.count(), eventPhases ? 2 : 3); + QCOMPARE(handler->active(), !eventPhases); + QCOMPARE(rect->position().toPoint(), QPoint(0, 0)); + QCOMPARE(rect->scale(), 1); + QCOMPARE(rect->rotation(), 0); +} + +void tst_QQuickWheelHandler::nestedHandler_data() +{ + // handler properties + QTest::addColumn<Qt::Orientation>("orientation"); + QTest::addColumn<bool>("invertible"); + QTest::addColumn<int>("rotationScale"); + QTest::addColumn<QString>("property"); + QTest::addColumn<qreal>("targetScaleMultiplier"); + QTest::addColumn<bool>("targetTransformAroundCursor"); + // event + QTest::addColumn<QPoint>("eventPos"); + QTest::addColumn<QPoint>("eventAngleDelta"); + QTest::addColumn<QPoint>("eventPixelDelta"); + QTest::addColumn<Qt::KeyboardModifiers>("eventModifiers"); + QTest::addColumn<bool>("eventPhases"); + QTest::addColumn<bool>("eventInverted"); + QTest::addColumn<int>("eventCount"); + // result: inner handler + QTest::addColumn<QPoint>("innerPosition"); + QTest::addColumn<qreal>("innerScale"); + QTest::addColumn<int>("innerRotation"); + // result: outer handler + QTest::addColumn<QPoint>("outerPosition"); + QTest::addColumn<qreal>("outerScale"); + QTest::addColumn<int>("outerRotation"); + + // move the item + QTest::newRow("vertical wheel angle delta to adjust x") + << Qt::Vertical << false << 1 << "x" << 1.5 << true + << QPoint(160, 120) << QPoint(120, 120) << QPoint() << Qt::KeyboardModifiers(Qt::NoModifier) << false << false << 10 + << QPoint(175,60) << 1.0 << 0 + << QPoint(75, 0) << 1.0 << 0; + QTest::newRow("horizontal wheel pixel delta to adjust y") + << Qt::Horizontal << false << 1 << "y" << 1.5 << false + << QPoint(160, 120) << QPoint(120, 120) << QPoint(50, 50) << Qt::KeyboardModifiers(Qt::NoModifier) << true << false << 4 + << QPoint(100, 160) << 1.0 << 0 + << QPoint(0, 100) << 1.0 << 0; +} + +void tst_QQuickWheelHandler::nestedHandler() +{ + // handler properties + QFETCH(Qt::Orientation, orientation); + QFETCH(bool, invertible); + QFETCH(int, rotationScale); + QFETCH(QString, property); + QFETCH(qreal, targetScaleMultiplier); + QFETCH(bool, targetTransformAroundCursor); + // event + QFETCH(QPoint, eventPos); + QFETCH(QPoint, eventAngleDelta); + QFETCH(QPoint, eventPixelDelta); + QFETCH(Qt::KeyboardModifiers, eventModifiers); + QFETCH(bool, eventPhases); + QFETCH(bool, eventInverted); + QFETCH(int, eventCount); + // result: inner handler + QFETCH(QPoint, innerPosition); + QFETCH(qreal, innerScale); + QFETCH(int, innerRotation); + // result: outer handler + QFETCH(QPoint, outerPosition); + QFETCH(qreal, outerScale); + QFETCH(int, outerRotation); + + QQuickView window; + QByteArray errorMessage; + QVERIFY2(QQuickTest::initView(window, testFileUrl("nested.qml"), true, &errorMessage), errorMessage.constData()); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + QQuickItem *outerRect = window.rootObject(); + QVERIFY(outerRect != nullptr); + QQuickWheelHandler *outerHandler = outerRect->findChild<QQuickWheelHandler*>("outerWheelHandler"); + QVERIFY(outerHandler != nullptr); + QQuickWheelHandler *innerHandler = outerRect->findChild<QQuickWheelHandler*>("innerWheelHandler"); + QVERIFY(innerHandler != nullptr); + QQuickItem *innerRect = innerHandler->parentItem(); + QVERIFY(innerRect != nullptr); + innerHandler->setOrientation(orientation); + innerHandler->setInvertible(invertible); + innerHandler->setRotationScale(rotationScale); + innerHandler->setProperty(property); + innerHandler->setTargetScaleMultiplier(targetScaleMultiplier); + innerHandler->setTargetTransformAroundCursor(targetTransformAroundCursor); + outerHandler->setOrientation(orientation); + outerHandler->setInvertible(invertible); + outerHandler->setRotationScale(rotationScale); + outerHandler->setProperty(property); + outerHandler->setTargetScaleMultiplier(targetScaleMultiplier); + outerHandler->setTargetTransformAroundCursor(targetTransformAroundCursor); + QSignalSpy innerActiveChangedSpy(innerHandler, SIGNAL(activeChanged())); + QSignalSpy outerActiveChangedSpy(outerHandler, SIGNAL(activeChanged())); + + if (eventPhases) + sendWheelEvent(window, eventPos, QPoint(), QPoint(), eventModifiers, Qt::ScrollBegin, eventInverted); + for (int i = 0; i < eventCount; ++i) + sendWheelEvent(window, eventPos, eventAngleDelta, eventPixelDelta, eventModifiers, + (eventPhases ? Qt::ScrollUpdate : Qt::NoScrollPhase), eventInverted); + QCOMPARE(innerRect->position().toPoint(), innerPosition); + + /* + If outer is activated, maybe inner should be deactivated? But the event + doesn't get delivered to inner anymore, so it doesn't find out that + it's no longer getting events. It will get deactivated after the + timeout, just as if the user stopped scrolling. + + This situation is similar to QTBUG-50199, but it's questionable whether + that was really so important. So far in Qt Quick, if you move the mouse + while wheel momentum continues, or if the item moves out from under the + mouse, a different item starts getting the events immediately. In + non-Qt applications on most OSes, that's quite normal. + */ + // QCOMPARE(innerActiveChangedSpy.count(), 2); + // QCOMPARE(innerHandler->active(), false); + QCOMPARE(innerRect->scale(), innerScale); + QCOMPARE(innerRect->rotation(), innerRotation); + QCOMPARE(outerRect->position().toPoint(), outerPosition); + QCOMPARE(outerActiveChangedSpy.count(), 1); + QCOMPARE(outerHandler->active(), true); + QCOMPARE(outerRect->scale(), outerScale); + QCOMPARE(outerRect->rotation(), outerRotation); + if (!eventPhases) { + QTRY_COMPARE(outerHandler->active(), false); + QCOMPARE(outerActiveChangedSpy.count(), 2); + } +} + +QTEST_MAIN(tst_QQuickWheelHandler) + +#include "tst_qquickwheelhandler.moc" |