Fix TapHandler signals in combination with exclusiveSignals
TapHandler does not emit any singleTapped or doubleTapped signals after emitting it once, if exclusiveSignals is set to `SingleTap | DoubleTap`. This change corrects the behavior by resetting m_tapCount properly. Fixes: QTBUG-111800 Pick-to: 6.5 Change-Id: Ice7af2f41c2f30448004033d8330e733abe44110 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
This commit is contained in:
parent
07aaa7c1b6
commit
951ab9f3c0
|
@ -13,7 +13,7 @@ QT_BEGIN_NAMESPACE
|
|||
|
||||
Q_LOGGING_CATEGORY(lcTapHandler, "qt.quick.handler.tap")
|
||||
|
||||
qreal QQuickTapHandler::m_multiTapInterval(0.0);
|
||||
quint64 QQuickTapHandler::m_multiTapInterval(0);
|
||||
// single tap distance is the same as the drag threshold
|
||||
int QQuickTapHandler::m_mouseMultiClickDistanceSquared(-1);
|
||||
int QQuickTapHandler::m_touchMultiTapDistanceSquared(-1);
|
||||
|
@ -57,7 +57,7 @@ QQuickTapHandler::QQuickTapHandler(QQuickItem *parent)
|
|||
: QQuickSinglePointHandler(parent)
|
||||
{
|
||||
if (m_mouseMultiClickDistanceSquared < 0) {
|
||||
m_multiTapInterval = qApp->styleHints()->mouseDoubleClickInterval() / 1000.0;
|
||||
m_multiTapInterval = qApp->styleHints()->mouseDoubleClickInterval();
|
||||
m_mouseMultiClickDistanceSquared = qApp->styleHints()->mouseDoubleClickDistance();
|
||||
m_mouseMultiClickDistanceSquared *= m_mouseMultiClickDistanceSquared;
|
||||
m_touchMultiTapDistanceSquared = qApp->styleHints()->touchDoubleTapDistance();
|
||||
|
@ -355,16 +355,6 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QPointerEvent *event,
|
|||
} else {
|
||||
m_longPressTimer.stop();
|
||||
m_holdTimer.invalidate();
|
||||
if (m_exclusiveSignals == (SingleTap | DoubleTap)) {
|
||||
if (m_tapCount == 0) {
|
||||
m_singleTapReleasedPoint = point;
|
||||
m_singleTapReleasedButton = event->isSinglePointEvent() ? static_cast<QSinglePointEvent *>(event)->button() : Qt::NoButton;
|
||||
qCDebug(lcTapHandler) << objectName() << "waiting to emit singleTapped:" << qApp->styleHints()->mouseDoubleClickInterval() << "ms";
|
||||
m_doubleTapTimer.start(qApp->styleHints()->mouseDoubleClickInterval(), this);
|
||||
} else if (m_doubleTapTimer.isActive()) {
|
||||
qCDebug(lcTapHandler) << objectName() << "tap" << (m_tapCount + 1) << "after" << event->timestamp() / 1000.0 - m_lastTapTimestamp << "sec";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (press) {
|
||||
// on press, grab before emitting changed signals
|
||||
|
@ -376,8 +366,8 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QPointerEvent *event,
|
|||
if (!cancel && !press && parentContains(point)) {
|
||||
if (point.timeHeld() < longPressThreshold()) {
|
||||
// Assuming here that pointerEvent()->timestamp() is in ms.
|
||||
const qreal ts = event->timestamp() / 1000.0;
|
||||
const qreal interval = ts - m_lastTapTimestamp;
|
||||
const quint64 ts = event->timestamp();
|
||||
const quint64 interval = ts - m_lastTapTimestamp;
|
||||
const auto distanceSquared = QVector2D(point.scenePosition() - m_lastTapPos).lengthSquared();
|
||||
const auto singleTapReleasedButton = event->isSinglePointEvent() ? static_cast<QSinglePointEvent *>(event)->button() : Qt::NoButton;
|
||||
if ((interval < m_multiTapInterval && distanceSquared <
|
||||
|
@ -387,6 +377,7 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QPointerEvent *event,
|
|||
++m_tapCount;
|
||||
} else {
|
||||
m_singleTapReleasedButton = singleTapReleasedButton;
|
||||
m_singleTapReleasedPoint = point;
|
||||
m_tapCount = 1;
|
||||
}
|
||||
qCDebug(lcTapHandler) << objectName() << "tapped" << m_tapCount << "times; interval since last:" << interval
|
||||
|
@ -394,11 +385,29 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QPointerEvent *event,
|
|||
auto button = event->isSinglePointEvent() ? static_cast<QSinglePointEvent *>(event)->button() : Qt::NoButton;
|
||||
emit tapped(point, button);
|
||||
emit tapCountChanged();
|
||||
if (m_tapCount == 1 && !m_exclusiveSignals.testFlag(DoubleTap))
|
||||
emit singleTapped(point, button);
|
||||
else if (m_tapCount == 2 && !m_exclusiveSignals.testFlag(SingleTap)) {
|
||||
emit doubleTapped(point, button);
|
||||
switch (m_exclusiveSignals) {
|
||||
case NotExclusive:
|
||||
if (m_tapCount == 1)
|
||||
emit singleTapped(point, button);
|
||||
else if (m_tapCount == 2)
|
||||
emit doubleTapped(point, button);
|
||||
break;
|
||||
case SingleTap:
|
||||
if (m_tapCount == 1)
|
||||
emit singleTapped(point, button);
|
||||
break;
|
||||
case DoubleTap:
|
||||
if (m_tapCount == 2)
|
||||
emit doubleTapped(point, button);
|
||||
break;
|
||||
case (SingleTap | DoubleTap):
|
||||
if (m_tapCount == 1) {
|
||||
qCDebug(lcTapHandler) << objectName() << "waiting to emit singleTapped:" << m_multiTapInterval << "ms";
|
||||
m_doubleTapTimer.start(m_multiTapInterval, this);
|
||||
}
|
||||
}
|
||||
qCDebug(lcTapHandler) << objectName() << "tap" << m_tapCount << "after" << event->timestamp() - m_lastTapTimestamp << "ms";
|
||||
|
||||
m_lastTapTimestamp = ts;
|
||||
m_lastTapPos = point.scenePosition();
|
||||
} else {
|
||||
|
|
|
@ -98,7 +98,7 @@ private:
|
|||
|
||||
private:
|
||||
QPointF m_lastTapPos;
|
||||
qreal m_lastTapTimestamp = 0;
|
||||
quint64 m_lastTapTimestamp = 0;
|
||||
QElapsedTimer m_holdTimer;
|
||||
QBasicTimer m_longPressTimer;
|
||||
QBasicTimer m_doubleTapTimer;
|
||||
|
@ -110,7 +110,7 @@ private:
|
|||
ExclusiveSignals m_exclusiveSignals = NotExclusive;
|
||||
bool m_pressed = false;
|
||||
|
||||
static qreal m_multiTapInterval;
|
||||
static quint64 m_multiTapInterval;
|
||||
static int m_mouseMultiClickDistanceSquared;
|
||||
static int m_touchMultiTapDistanceSquared;
|
||||
};
|
||||
|
|
|
@ -715,12 +715,13 @@ void tst_TapHandler::singleTapDoubleTap()
|
|||
QSignalSpy singleTapSpy(tapHandler, &QQuickTapHandler::singleTapped);
|
||||
QSignalSpy doubleTapSpy(tapHandler, &QQuickTapHandler::doubleTapped);
|
||||
|
||||
auto tap = [window, tapHandler, deviceType, this](const QPoint &p1) {
|
||||
auto tap = [window, tapHandler, deviceType, this](const QPoint &p1, int delay = 10) {
|
||||
switch (static_cast<QPointingDevice::DeviceType>(deviceType)) {
|
||||
case QPointingDevice::DeviceType::Mouse:
|
||||
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, p1, 10);
|
||||
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, p1, delay);
|
||||
break;
|
||||
case QPointingDevice::DeviceType::TouchScreen:
|
||||
QTest::qWait(delay);
|
||||
QTest::touchEvent(window, touchDevice).press(0, p1, window);
|
||||
QTRY_VERIFY(tapHandler->isPressed());
|
||||
QTest::touchEvent(window, touchDevice).release(0, p1, window);
|
||||
|
@ -741,6 +742,23 @@ void tst_TapHandler::singleTapDoubleTap()
|
|||
QTRY_COMPARE(doubleTapSpy.size(), expectedDoubleTapCount);
|
||||
QCOMPARE(tappedSpy.size(), 2);
|
||||
QCOMPARE(singleTapSpy.size(), expectedEndingSingleTapCount);
|
||||
|
||||
// wait past the double-tap interval, then do it again
|
||||
const auto delay = qApp->styleHints()->mouseDoubleClickInterval() + 10;
|
||||
tappedSpy.clear();
|
||||
singleTapSpy.clear();
|
||||
doubleTapSpy.clear();
|
||||
|
||||
// tap once with delay
|
||||
tap(p1, delay);
|
||||
QCOMPARE(tappedSpy.size(), 1);
|
||||
QCOMPARE(doubleTapSpy.size(), 0);
|
||||
|
||||
// tap again immediately afterwards
|
||||
tap(p1);
|
||||
QTRY_COMPARE(doubleTapSpy.size(), expectedDoubleTapCount);
|
||||
QCOMPARE(tappedSpy.size(), 2);
|
||||
QCOMPARE(singleTapSpy.size(), expectedEndingSingleTapCount);
|
||||
}
|
||||
|
||||
void tst_TapHandler::touchLongPress()
|
||||
|
|
Loading…
Reference in New Issue