Handle "interesting" stationary touchpoints as if they moved
Qt Quick will not receive "uninteresting" stationary touchpoints, but only those in which some property has changed. So MultiPointTouchArea should react to stationary touchpoints in the same way as if they moved, so that UIs can react to changes in touchpoint velocity, pressure etc. And QQuickWindow has to be willing to delivery stationary touchpoints to make this possible. However when a QTouchEvent is customized for delivery to a specific Item, by including only the touchpoints that are inside the Item, then if those touchpoints are all stationary, the event only needs to be delivered if at least one of them is an "interesting" stationary touchpoint. So we need to depend on a new per-touchpoint flag that QGuiApplication will set when it discovers that some property of the touchpoint has changed. That is QTouchEventTouchPointPrivate::stationaryWithModifiedProperty. Fixes: QTBUG-77142 Change-Id: I763d56ff55c048b258dca40d88283ed016447c35 Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
This commit is contained in:
parent
7782a211d1
commit
ae346195ef
|
@ -41,6 +41,7 @@
|
|||
#include <QtCore/qmap.h>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <QtGui/private/qtouchdevice_p.h>
|
||||
#include <QtGui/private/qevent_p.h>
|
||||
#include <QtQuick/private/qquickitem_p.h>
|
||||
#include <QtQuick/private/qquickpointerhandler_p.h>
|
||||
#include <QtQuick/private/qquickwindow_p.h>
|
||||
|
@ -1828,6 +1829,7 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i
|
|||
// but that would require changing tst_qquickwindow::touchEvent_velocity(): it expects transformed velocity
|
||||
|
||||
bool anyPressOrReleaseInside = false;
|
||||
bool anyStationaryWithModifiedPropertyInside = false;
|
||||
bool anyGrabber = false;
|
||||
QMatrix4x4 transformMatrix(QQuickItemPrivate::get(item)->windowToItemTransform());
|
||||
for (int i = 0; i < m_pointCount; ++i) {
|
||||
|
@ -1860,6 +1862,8 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i
|
|||
anyPressOrReleaseInside = true;
|
||||
const QTouchEvent::TouchPoint *tp = touchPointById(p->pointId());
|
||||
if (tp) {
|
||||
if (isInside && tp->d->stationaryWithModifiedProperty)
|
||||
anyStationaryWithModifiedPropertyInside = true;
|
||||
eventStates |= tp->state();
|
||||
QTouchEvent::TouchPoint tpCopy = *tp;
|
||||
tpCopy.setPos(item->mapFromScene(tpCopy.scenePos()));
|
||||
|
@ -1873,7 +1877,8 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i
|
|||
|
||||
// Now touchPoints will have only points which are inside the item.
|
||||
// But if none of them were just pressed inside, and the item has no other reason to care, ignore them anyway.
|
||||
if (eventStates == Qt::TouchPointStationary || touchPoints.isEmpty() || (!anyPressOrReleaseInside && !anyGrabber && !isFiltering))
|
||||
if ((eventStates == Qt::TouchPointStationary && !anyStationaryWithModifiedPropertyInside) ||
|
||||
touchPoints.isEmpty() || (!anyPressOrReleaseInside && !anyGrabber && !isFiltering))
|
||||
return nullptr;
|
||||
|
||||
// if all points have the same state, set the event type accordingly
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "qquickmultipointtoucharea_p.h"
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#include <private/qsgadaptationlayer_p.h>
|
||||
#include <private/qevent_p.h>
|
||||
#include <private/qquickitem_p.h>
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <QEvent>
|
||||
|
@ -655,7 +656,8 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
|
|||
// (we may have just obtained enough points to start tracking them -- in that case moved or stationary count as newly pressed)
|
||||
addTouchPoint(&p);
|
||||
started = true;
|
||||
} else if (touchPointState & Qt::TouchPointMoved) {
|
||||
} else if ((touchPointState & Qt::TouchPointMoved) || p.d->stationaryWithModifiedProperty) {
|
||||
// React to a stationary point with a property change (velocity, pressure) as if the point moved. (QTBUG-77142)
|
||||
QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
|
||||
Q_ASSERT(dtp);
|
||||
_movedTouchPoints.append(dtp);
|
||||
|
|
|
@ -72,6 +72,7 @@ private slots:
|
|||
void mouseGestureStarted_data();
|
||||
void mouseGestureStarted();
|
||||
void cancel();
|
||||
void stationaryTouchWithChangingPressure();
|
||||
|
||||
private:
|
||||
QQuickView *createAndShowView(const QString &file);
|
||||
|
@ -1305,6 +1306,42 @@ void tst_QQuickMultiPointTouchArea::cancel()
|
|||
|
||||
}
|
||||
|
||||
void tst_QQuickMultiPointTouchArea::stationaryTouchWithChangingPressure() // QTBUG-77142
|
||||
{
|
||||
QScopedPointer<QQuickView> window(createAndShowView("basic.qml"));
|
||||
QVERIFY(window->rootObject() != nullptr);
|
||||
|
||||
QQuickTouchPoint *point1 = window->rootObject()->findChild<QQuickTouchPoint*>("point1");
|
||||
QCOMPARE(point1->pressed(), false);
|
||||
|
||||
QPoint p1(20,100);
|
||||
QTouchEvent::TouchPoint tp1(1);
|
||||
|
||||
tp1.setScreenPos(window->mapToGlobal(p1));
|
||||
tp1.setState(Qt::TouchPointPressed);
|
||||
tp1.setPressure(0.5);
|
||||
qt_handleTouchEvent(window.data(), device, {tp1});
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
|
||||
QCOMPARE(point1->pressed(), true);
|
||||
QCOMPARE(point1->pressure(), 0.5);
|
||||
|
||||
tp1.setState(Qt::TouchPointStationary);
|
||||
tp1.setPressure(0.6);
|
||||
qt_handleTouchEvent(window.data(), device, {tp1});
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
|
||||
QCOMPARE(point1->pressure(), 0.6);
|
||||
|
||||
tp1.setState(Qt::TouchPointReleased);
|
||||
tp1.setPressure(0);
|
||||
qt_handleTouchEvent(window.data(), device, {tp1});
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
|
||||
QCOMPARE(point1->pressed(), false);
|
||||
QCOMPARE(point1->pressure(), 0);
|
||||
}
|
||||
|
||||
|
||||
QTEST_MAIN(tst_QQuickMultiPointTouchArea)
|
||||
|
||||
|
|
Loading…
Reference in New Issue