PinchArea: fix pinches being stolen when in PathView
Keep the mouse grab in addition to touch, as PathView apparently doesn't deal with touch events yet. Fixes: QTBUG-105058 Pick-to: 6.2 6.3 6.4 Change-Id: Id94768aec847138cccdeccfa92e4bc72a19810fe Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
parent
212f31f9ea
commit
10800723ab
|
@ -354,6 +354,7 @@ void QQuickPinchArea::clearPinch(QTouchEvent *event)
|
|||
}
|
||||
}
|
||||
setKeepTouchGrab(false);
|
||||
setKeepMouseGrab(false);
|
||||
}
|
||||
|
||||
void QQuickPinchArea::cancelPinch(QTouchEvent *event)
|
||||
|
@ -395,6 +396,7 @@ void QQuickPinchArea::cancelPinch(QTouchEvent *event)
|
|||
event->setExclusiveGrabber(point, nullptr);
|
||||
}
|
||||
setKeepTouchGrab(false);
|
||||
setKeepMouseGrab(false);
|
||||
}
|
||||
|
||||
void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
|
||||
|
@ -427,6 +429,7 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
|
|||
pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
|
||||
pe.setPoint1(mapFromScene(d->lastPoint1));
|
||||
pe.setPoint2(mapFromScene(d->lastPoint2));
|
||||
setKeepMouseGrab(false);
|
||||
emit pinchFinished(&pe);
|
||||
d->pinchStartDist = 0;
|
||||
d->pinchActivated = false;
|
||||
|
@ -525,6 +528,9 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
|
|||
event->setExclusiveGrabber(touchPoint1, this);
|
||||
event->setExclusiveGrabber(touchPoint2, this);
|
||||
setKeepTouchGrab(true);
|
||||
// So that PinchArea works in PathView, grab mouse events too.
|
||||
// We should be able to remove these setKeepMouseGrab calls when QTBUG-105567 is fixed.
|
||||
setKeepMouseGrab(true);
|
||||
d->inPinch = true;
|
||||
if (d->pinch && d->pinch->target()) {
|
||||
auto targetParent = pinch()->target()->parentItem();
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import QtQuick
|
||||
|
||||
PathView {
|
||||
width: 600
|
||||
height: 200
|
||||
|
||||
model: 3
|
||||
delegate: Rectangle {
|
||||
width: 200
|
||||
height: 200
|
||||
color: "salmon"
|
||||
opacity: PathView.isCurrentItem ? 1 : 0.5
|
||||
|
||||
property alias pinchArea: pinchArea
|
||||
|
||||
Text {
|
||||
text: "Test"
|
||||
font.pixelSize: 100
|
||||
anchors.fill: parent
|
||||
fontSizeMode: Text.Fit
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
PinchArea {
|
||||
id: pinchArea
|
||||
anchors.fill: parent
|
||||
pinch.target: parent
|
||||
pinch.dragAxis: Pinch.XAndYAxis
|
||||
pinch.minimumScale: 1.0
|
||||
pinch.maximumScale: 5.0
|
||||
|
||||
onPinchFinished: (pinch) => {
|
||||
parent.scale = 1
|
||||
parent.x = 0
|
||||
parent.y = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
path: Path {
|
||||
startX: 100
|
||||
startY: 100
|
||||
PathLine {
|
||||
x: 700
|
||||
y: 100
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtCore/private/qvariantanimation_p.h>
|
||||
#include <QtTest/QtTest>
|
||||
#include <QtTest/QSignalSpy>
|
||||
#include <QtGui/QStyleHints>
|
||||
|
@ -8,6 +9,7 @@
|
|||
#include <QtGui/private/qeventpoint_p.h>
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <private/qquickpincharea_p.h>
|
||||
#include <QtQuick/private/qquickpathview_p.h>
|
||||
#include <QtQuick/private/qquickrectangle_p.h>
|
||||
#include <QtQuick/qquickview.h>
|
||||
#include <QtQml/qqmlcontext.h>
|
||||
|
@ -30,6 +32,7 @@ private slots:
|
|||
void transformedPinchArea();
|
||||
void dragTransformedPinchArea_data();
|
||||
void dragTransformedPinchArea();
|
||||
void pinchAreaKeepsDragInView();
|
||||
|
||||
private:
|
||||
QQuickView *createView();
|
||||
|
@ -618,6 +621,92 @@ void tst_QQuickPinchArea::dragTransformedPinchArea() // QTBUG-63673
|
|||
QCOMPARE(pinchArea->pinch()->active(), false);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void forEachLerpStep(int steps, F &&func)
|
||||
{
|
||||
for (int i = 0; i < steps; ++i) {
|
||||
const qreal t = qreal(i) / steps;
|
||||
func(t);
|
||||
}
|
||||
}
|
||||
|
||||
QPoint lerpPoints(const QPoint &point1, const QPoint &point2, qreal t)
|
||||
{
|
||||
return QPoint(_q_interpolate(point1.x(), point2.x(), t), _q_interpolate(point1.y(), point2.y(), t));
|
||||
};
|
||||
|
||||
// QTBUG-105058
|
||||
void tst_QQuickPinchArea::pinchAreaKeepsDragInView()
|
||||
{
|
||||
QQuickView view;
|
||||
view.setSource(testFileUrl("pinchAreaInPathView.qml"));
|
||||
QVERIFY(view.rootObject());
|
||||
view.show();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(&view));
|
||||
|
||||
QQuickPathView *pathView = qobject_cast<QQuickPathView*>(view.rootObject());
|
||||
QVERIFY(pathView);
|
||||
QCOMPARE(pathView->count(), 3);
|
||||
|
||||
const QQuickItem *pinchDelegateItem = pathView->itemAtIndex(0);
|
||||
QQuickPinchArea *pinchArea = pinchDelegateItem->property("pinchArea").value<QQuickPinchArea*>();
|
||||
QVERIFY(pinchArea);
|
||||
|
||||
// Press.
|
||||
QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(&view, device);
|
||||
QPoint point1Start = { 80, 120 };
|
||||
QPoint point2Start = { 120, 80 };
|
||||
const int dragThreshold = qApp->styleHints()->startDragDistance();
|
||||
pinchSequence.press(1, pinchArea->mapToScene(point1Start).toPoint(), &view)
|
||||
.press(2, pinchArea->mapToScene(point2Start).toPoint(), &view).commit();
|
||||
QQuickTouchUtils::flush(&view);
|
||||
|
||||
// Move past the drag threshold to begin the pinch.
|
||||
const int steps = 30;
|
||||
QPoint point1End = point1Start + QPoint(-dragThreshold, dragThreshold);
|
||||
QPoint point2End = point2Start + QPoint(dragThreshold, -dragThreshold);
|
||||
forEachLerpStep(steps, [&](qreal t) {
|
||||
pinchSequence.move(1, lerpPoints(point1Start, point1End, t), &view)
|
||||
.move(2, lerpPoints(point2Start, point2End, t), &view).commit();
|
||||
QQuickTouchUtils::flush(&view);
|
||||
QTest::qWait(5);
|
||||
});
|
||||
QCOMPARE(pinchArea->pinch()->active(), true);
|
||||
QVERIFY2(pinchDelegateItem->scale() > 1.0, qPrintable(QString::number(pinchDelegateItem->scale())));
|
||||
// The PathView contents shouldn't have moved.
|
||||
QCOMPARE(pathView->offset(), 0);
|
||||
|
||||
// Release a touch point.
|
||||
pinchSequence.stationary(1).release(2, point2End, &view).commit();
|
||||
QQuickTouchUtils::flush(&view);
|
||||
|
||||
// Press it again.
|
||||
pinchSequence.stationary(1).press(2, point2End, &view).commit();
|
||||
QQuickTouchUtils::flush(&view);
|
||||
QCOMPARE(pinchArea->pinch()->active(), true);
|
||||
|
||||
// Drag to the right; the PathView still shouldn't move.
|
||||
point1Start = point1End;
|
||||
point2Start = point2End;
|
||||
point1End = point1Start + QPoint(100, 0);
|
||||
point2End = point2Start + QPoint(100, 0);
|
||||
forEachLerpStep(steps, [&](qreal t) {
|
||||
pinchSequence.move(1, lerpPoints(point1Start, point1End, t), &view)
|
||||
.move(2, lerpPoints(point2Start, point2End, t), &view).commit();
|
||||
QQuickTouchUtils::flush(&view);
|
||||
QTest::qWait(5);
|
||||
});
|
||||
QCOMPARE(pinchArea->pinch()->active(), true);
|
||||
QVERIFY2(pinchDelegateItem->scale() > 1.0, qPrintable(QString::number(pinchDelegateItem->scale())));
|
||||
QCOMPARE(pathView->offset(), 0);
|
||||
|
||||
// Release pinch.
|
||||
pinchSequence.release(1, point1End, &view).release(2, point2End, &view).commit();
|
||||
QQuickTouchUtils::flush(&view);
|
||||
QCOMPARE(pinchArea->pinch()->active(), false);
|
||||
QCOMPARE(pathView->offset(), 0);
|
||||
}
|
||||
|
||||
QQuickView *tst_QQuickPinchArea::createView()
|
||||
{
|
||||
QQuickView *window = new QQuickView(nullptr);
|
||||
|
|
Loading…
Reference in New Issue