diff options
author | J-P Nurmi <jpnurmi@qt.io> | 2017-01-03 16:05:46 +0100 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2017-01-03 18:26:08 +0000 |
commit | 28a9f66ea4910657b98cd4db548d84b298cf844e (patch) | |
tree | a397993c9cf1cf1ac0000d47e37c26228cb653b8 | |
parent | 0b290018b52bc15534bedebe39f183e74eaee24e (diff) |
QQuickDial: handle touch events
In comparison to handling synthesized mouse events, handling touch
events has the advantage that it gives multi-touch support. That is,
it is possible to move multiple dials at the same time, each handling
its own touch point.
Change-Id: Icabd971147f291fa4df00c6215c847d7976fda5f
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r-- | src/quicktemplates2/qquickdial.cpp | 62 | ||||
-rw-r--r-- | src/quicktemplates2/qquickdial_p.h | 2 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_dial.qml | 128 |
3 files changed, 191 insertions, 1 deletions
diff --git a/src/quicktemplates2/qquickdial.cpp b/src/quicktemplates2/qquickdial.cpp index bd59f057..3f37a73b 100644 --- a/src/quicktemplates2/qquickdial.cpp +++ b/src/quicktemplates2/qquickdial.cpp @@ -96,6 +96,7 @@ class QQuickDialPrivate : public QQuickControlPrivate public: QQuickDialPrivate() : + touchId(-1), from(0), to(1), value(0), @@ -122,6 +123,7 @@ public: void handleRelease(const QPointF &point); void handleUngrab(); + int touchId; qreal from; qreal to; qreal value; @@ -241,12 +243,14 @@ void QQuickDialPrivate::handleRelease(const QPointF &point) q->setPressed(false); pressPoint = QPointF(); + touchId = -1; } void QQuickDialPrivate::handleUngrab() { Q_Q(QQuickDial); pressPoint = QPointF(); + touchId = -1; q->setPressed(false); } @@ -685,6 +689,64 @@ void QQuickDial::mouseUngrabEvent() d->handleUngrab(); } +void QQuickDial::touchEvent(QTouchEvent *event) +{ + Q_D(QQuickDial); + switch (event->type()) { + case QEvent::TouchBegin: + if (d->touchId == -1) { + const QTouchEvent::TouchPoint point = event->touchPoints().first(); + d->touchId = point.id(); + d->handlePress(point.pos()); + } else { + event->ignore(); + } + break; + + case QEvent::TouchUpdate: + for (const QTouchEvent::TouchPoint &point : event->touchPoints()) { + if (point.id() != d->touchId) + continue; + + if (!keepMouseGrab()) { + bool overXDragThreshold = QQuickWindowPrivate::dragOverThreshold(point.pos().x() - d->pressPoint.x(), Qt::XAxis, &point); + setKeepMouseGrab(overXDragThreshold); + + if (!overXDragThreshold) { + bool overYDragThreshold = QQuickWindowPrivate::dragOverThreshold(point.pos().y() - d->pressPoint.y(), Qt::YAxis, &point); + setKeepMouseGrab(overYDragThreshold); + } + } + d->handleMove(point.pos()); + } + break; + + case QEvent::TouchEnd: + for (const QTouchEvent::TouchPoint &point : event->touchPoints()) { + if (point.id() != d->touchId) + continue; + + d->handleRelease(point.pos()); + } + break; + + case QEvent::TouchCancel: + d->handleUngrab(); + break; + + default: + QQuickControl::touchEvent(event); + break; + } +} + +void QQuickDial::touchUngrabEvent() +{ + Q_D(QQuickDial); + QQuickControl::touchUngrabEvent(); + d->handleUngrab(); +} + void QQuickDial::wheelEvent(QWheelEvent *event) { Q_D(QQuickDial); diff --git a/src/quicktemplates2/qquickdial_p.h b/src/quicktemplates2/qquickdial_p.h index cfaf1f32..efb43165 100644 --- a/src/quicktemplates2/qquickdial_p.h +++ b/src/quicktemplates2/qquickdial_p.h @@ -138,6 +138,8 @@ protected: void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseUngrabEvent() override; + void touchEvent(QTouchEvent *event) override; + void touchUngrabEvent() override; void wheelEvent(QWheelEvent *event) override; void mirrorChange() override; diff --git a/tests/auto/controls/data/tst_dial.qml b/tests/auto/controls/data/tst_dial.qml index 599bd03b..fb33892e 100644 --- a/tests/auto/controls/data/tst_dial.qml +++ b/tests/auto/controls/data/tst_dial.qml @@ -165,6 +165,15 @@ TestCase { mouseRelease(dial, dial.width / 2, dial.height / 2); verify(!dial.pressed); compare(pressSpy.count, 2); + + var touch = touchEvent(dial); + touch.press(0).commit(); + verify(dial.pressed); + compare(pressSpy.count, 3); + + touch.release(0).commit(); + verify(!dial.pressed); + compare(pressSpy.count, 4); } SignalSpy { @@ -272,6 +281,90 @@ TestCase { verify(dial.position > positionAtPress); } + function test_touch() { + var dial = createTemporaryObject(dialComponent, testCase); + verify(dial); + + var touch = touchEvent(dial); + + // Ensure that dragging from bottom left to bottom right doesn't work. + var yPos = dial.height * 0.75; + touch.press(0, dial, dial.width * 0.25, yPos).commit(); + var positionAtPress = dial.position; + touch.move(0, dial, dial.width * 0.5, yPos).commit(); + compare(dial.position, positionAtPress); + touch.move(0, dial, dial.width * 0.75, yPos).commit(); + compare(dial.position, positionAtPress); + touch.release(0, dial, dial.width * 0.75, yPos).commit(); + compare(dial.position, positionAtPress); + + // Try the same thing, but a bit higher. + yPos = dial.height * 0.6; + touch.press(0, dial, dial.width * 0.25, yPos).commit(); + positionAtPress = dial.position; + touch.move(0, dial, dial.width * 0.5, yPos).commit(); + compare(dial.position, positionAtPress); + touch.move(0, dial, dial.width * 0.75, yPos).commit(); + compare(dial.position, positionAtPress); + touch.release(0, dial, dial.width * 0.75, yPos).commit(); + compare(dial.position, positionAtPress); + + // Going from below the center of the dial to above it should work (once it gets above the center). + touch.press(0, dial, dial.width * 0.25, dial.height * 0.75).commit(); + positionAtPress = dial.position; + touch.move(0, dial, dial.width * 0.5, dial.height * 0.6).commit(); + compare(dial.position, positionAtPress); + touch.move(0, dial, dial.width * 0.75, dial.height * 0.4).commit(); + verify(dial.position > positionAtPress); + touch.release(0, dial, dial.width * 0.75, dial.height * 0.3).commit(); + verify(dial.position > positionAtPress); + } + + function test_multiTouch() { + var dial1 = createTemporaryObject(dialComponent, testCase); + verify(dial1); + + var touch = touchEvent(dial1); + touch.press(0, dial1).commit().move(0, dial1, dial1.width / 4, dial1.height / 4).commit(); + compare(dial1.pressed, true); + verify(dial1.position > 0.0); + + var pos1Before = dial1.position; + + // second touch point on the same control is ignored + touch.stationary(0).press(1, dial1, 0, 0).commit() + touch.stationary(0).move(1, dial1).commit() + touch.stationary(0).release(1).commit() + compare(dial1.pressed, true); + compare(dial1.position, pos1Before); + + var dial2 = createTemporaryObject(dialComponent, testCase, {y: dial1.height}); + verify(dial2); + waitForRendering(dial2); + + // press the second dial + touch.stationary(0).press(2, dial2, 0, 0).commit(); + compare(dial2.pressed, true); + compare(dial2.position, 0.0); + + pos1Before = dial1.position; + var pos2Before = dial2.position; + + // move both dials + touch.move(0, dial1).move(2, dial2, dial2.width / 4, dial2.height / 4).commit(); + compare(dial1.pressed, true); + verify(dial1.position !== pos1Before); + compare(dial2.pressed, true); + verify(dial2.position !== pos2Before); + + // release both dials + touch.release(0, dial1).release(2, dial2).commit(); + compare(dial1.pressed, false); + compare(dial1.value, dial1.position); + compare(dial2.pressed, false); + compare(dial2.value, dial2.position); + } + property Component focusTest: Component { FocusScope { signal receivedKeyPress @@ -376,7 +469,11 @@ TestCase { ] } - function test_snapMode(data) { + function test_snapMode_mouse_data() { + return test_snapMode_data() + } + + function test_snapMode_mouse(data) { var dial = createTemporaryObject(dialComponent, testCase); verify(dial); @@ -400,6 +497,35 @@ TestCase { fuzzyCompare(dial.position, data.positions[2], fuzz); } + function test_snapMode_touch_data() { + return test_snapMode_data() + } + + function test_snapMode_touch(data) { + var dial = createTemporaryObject(dialComponent, testCase); + verify(dial); + + dial.snapMode = data.snapMode; + dial.from = data.from; + dial.to = data.to; + dial.stepSize = 0.2; + + var fuzz = 0.05; + + var touch = touchEvent(dial); + touch.press(0, dial, dial.width * 0.25, dial.height * 0.75).commit() + compare(dial.value, data.values[0]); + compare(dial.position, data.positions[0]); + + touch.move(0, dial, dial.width * 0.5, dial.height * 0.25).commit(); + fuzzyCompare(dial.value, data.values[1], fuzz); + fuzzyCompare(dial.position, data.positions[1], fuzz); + + touch.release(0, dial, dial.width * 0.5, dial.height * 0.25).commit(); + fuzzyCompare(dial.value, data.values[2], fuzz); + fuzzyCompare(dial.position, data.positions[2], fuzz); + } + function test_wheel_data() { return [ { tag: "horizontal", orientation: Qt.Horizontal, dx: 120, dy: 0 }, |