diff options
4 files changed, 81 insertions, 4 deletions
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp index b1dca9a905..fffcc2f848 100644 --- a/src/quick/handlers/qquickpinchhandler.cpp +++ b/src/quick/handlers/qquickpinchhandler.cpp @@ -91,6 +91,8 @@ Q_LOGGING_CATEGORY(lcPinchHandler, "qt.quick.handler.pinch") QQuickPinchHandler::QQuickPinchHandler(QQuickItem *parent) : QQuickMultiPointHandler(parent, 2) { + // Tell QQuickPointerDeviceHandler::wantsPointerEvent() to ignore button state + d_func()->acceptedButtons = Qt::NoButton; } /*! @@ -235,7 +237,7 @@ void QQuickPinchHandler::onActiveChanged() m_startRotation = t->rotation(); m_startPos = t->position(); } else { - m_startScale = m_accumulatedScale; + m_startScale = 1; m_startRotation = 0; } qCDebug(lcPinchHandler) << "activated with starting scale" << m_startScale << "rotation" << m_startRotation; @@ -448,7 +450,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event) qCDebug(lcPinchHandler) << "centroid" << centroid().scenePressPosition() << "->" << centroid().scenePosition() << ", distance" << m_startDistance << "->" << dist - << ", startScale" << m_startScale << "->" << m_accumulatedScale + << ", scale" << m_startScale << "->" << m_accumulatedScale << ", activeRotation" << m_activeRotation << ", rotation" << rotation << " from " << event->device()->type(); diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp index a838f46d83..27f9c3fc36 100644 --- a/src/quick/handlers/qquickpointerdevicehandler.cpp +++ b/src/quick/handlers/qquickpointerdevicehandler.cpp @@ -305,7 +305,7 @@ bool QQuickPointerDeviceHandler::wantsPointerEvent(QPointerEvent *event) return false; if (d->acceptedModifiers != Qt::KeyboardModifierMask && event->modifiers() != d->acceptedModifiers) return false; - // HoverHandler sets acceptedButtons to Qt::NoButton to indicate that button state is irrelevant. + // Some handlers (HoverHandler, PinchHandler) set acceptedButtons to Qt::NoButton to indicate that button state is irrelevant. if (event->pointingDevice()->pointerType() != QPointingDevice::PointerType::Finger && acceptedButtons() != Qt::NoButton && event->type() != QEvent::Wheel && (static_cast<QSinglePointEvent *>(event)->buttons() & acceptedButtons()) == 0 && diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp index f9ae620c75..11c29ee812 100644 --- a/src/quick/handlers/qquickpointerhandler.cpp +++ b/src/quick/handlers/qquickpointerhandler.cpp @@ -625,7 +625,8 @@ void QQuickPointerHandler::handlePointerEvent(QPointerEvent *event) if (wants) { handlePointerEventImpl(event); } else { - setActive(false); + if (event->type() != QEvent::NativeGesture) + setActive(false); for (int i = 0; i < event->pointCount(); ++i) { auto &pt = event->point(i); if (event->exclusiveGrabber(pt) == this && pt.state() != QEventPoint::Stationary) { diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp index cd24d8643e..3c46c415f6 100644 --- a/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp @@ -50,6 +50,7 @@ private slots: void pinchProperties(); void scale(); void scaleThreeFingers(); + void scaleNativeGesture(); void pan(); void dragAxesEnabled_data(); void dragAxesEnabled(); @@ -353,6 +354,79 @@ void tst_QQuickPinchHandler::scaleThreeFingers() QCOMPARE(pinchHandler->active(), false); } +void tst_QQuickPinchHandler::scaleNativeGesture() +{ + QQuickView *window = createView(); + QScopedPointer<QQuickView> scope(window); + window->setSource(testFileUrl("pinchproperties.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(window->rootObject() != nullptr); + qApp->processEvents(); + + QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler"); + QVERIFY(pinchHandler != nullptr); + QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); + QVERIFY(root != nullptr); + QQuickItem *target = window->rootObject()->findChild<QQuickItem*>("blackrect"); + QVERIFY(target != nullptr); + + QPointF targetPos = target->position(); + ulong ts = 1; + + // first pinch: scale it up + const qreal expectedScale = 1.1; + QPointF pinchPos(75, 75); + QPointF pinchLocalPos = target->mapFromScene(pinchPos); + // target position is adjusted in QQuickItemPrivate::adjustedPosForTransform() + // so as to compensate for the change in size, to hold the centroid in place + const QPointF expectedPos = targetPos + QPointF( (pinchPos.x() - target->x()) * (expectedScale - 1), + (pinchPos.y() - target->y()) * (expectedScale - 1) ); + QWindowSystemInterface::handleGestureEvent(window, ts++, QPointingDevice::primaryPointingDevice(), + Qt::BeginNativeGesture, pinchPos, pinchPos); + QWindowSystemInterface::handleGestureEventWithRealValue(window, ts++, QPointingDevice::primaryPointingDevice(), + Qt::ZoomNativeGesture, expectedScale - 1, pinchPos, pinchPos); + QTRY_COMPARE(target->scale(), expectedScale); + QCOMPARE(pinchHandler->active(), true); + QCOMPARE(pinchHandler->centroid().position(), pinchLocalPos); + QCOMPARE(pinchHandler->centroid().scenePosition(), pinchPos); + QVERIFY(qAbs(target->position().x() - expectedPos.x()) < 0.001); + QVERIFY(qAbs(target->position().y() - expectedPos.y()) < 0.001); + QCOMPARE(pinchHandler->scale(), expectedScale); + QCOMPARE(pinchHandler->activeScale(), expectedScale); + QCOMPARE(pinchHandler->translation(), QVector2D()); + QCOMPARE(pinchHandler->rotation(), 0); + QWindowSystemInterface::handleGestureEvent(window, ts++, QPointingDevice::primaryPointingDevice(), + Qt::EndNativeGesture, pinchPos, pinchPos); + QTRY_COMPARE(pinchHandler->active(), false); + QCOMPARE(target->scale(), expectedScale); + QCOMPARE(pinchHandler->scale(), expectedScale); + QCOMPARE(pinchHandler->activeScale(), 1); + QCOMPARE(pinchHandler->translation(), QVector2D()); + QCOMPARE(pinchHandler->rotation(), 0); + + // second pinch at a different position: scale it down to original size again + const qreal reverseScale = (1 / expectedScale); + pinchPos = QPointF(125, 125); + pinchLocalPos = target->mapFromScene(pinchPos); + QWindowSystemInterface::handleGestureEvent(window, ts++, QPointingDevice::primaryPointingDevice(), + Qt::BeginNativeGesture, pinchPos, pinchPos); + QWindowSystemInterface::handleGestureEventWithRealValue(window, ts++, QPointingDevice::primaryPointingDevice(), + Qt::ZoomNativeGesture, reverseScale - 1, pinchPos, pinchPos); + QTRY_COMPARE(target->scale(), 1); + QCOMPARE(pinchHandler->active(), true); + QCOMPARE(pinchHandler->centroid().position(), pinchLocalPos); + QCOMPARE(pinchHandler->centroid().scenePosition(), pinchPos); + QCOMPARE(pinchHandler->scale(), 1); + QCOMPARE(pinchHandler->activeScale(), reverseScale); + QWindowSystemInterface::handleGestureEvent(window, ts++, QPointingDevice::primaryPointingDevice(), + Qt::EndNativeGesture, pinchPos, pinchPos); + QTRY_COMPARE(pinchHandler->active(), false); + QCOMPARE(target->scale(), 1); + QCOMPARE(pinchHandler->scale(), 1); + QCOMPARE(pinchHandler->activeScale(), 1); +} + void tst_QQuickPinchHandler::pan() { QQuickView *window = createView(); |