diff options
author | J-P Nurmi <jpnurmi@qt.io> | 2017-01-24 10:48:46 +0100 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2017-01-24 11:53:02 +0000 |
commit | dc5f909fe1337aa6d7adf2c2445adaec547c5c6f (patch) | |
tree | 00a4691b9ca2ae294ff3c06e119d33df6d249ce6 | |
parent | 3ac5f0c795a91efa975935d889c99052b8bc2137 (diff) |
QQuickSwitch: handle touch events
This makes it possible to interact with multiple switches at the same
time.
Change-Id: I1a8c2ff6ddb7e867b3d9d66f15c49ae5b70231e7
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r-- | src/quicktemplates2/qquickswitch.cpp | 66 | ||||
-rw-r--r-- | src/quicktemplates2/qquickswitch_p.h | 3 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_switch.qml | 202 |
3 files changed, 247 insertions, 24 deletions
diff --git a/src/quicktemplates2/qquickswitch.cpp b/src/quicktemplates2/qquickswitch.cpp index f96fa391..ece9802d 100644 --- a/src/quicktemplates2/qquickswitch.cpp +++ b/src/quicktemplates2/qquickswitch.cpp @@ -86,6 +86,10 @@ public: qreal positionAt(const QPointF &point) const; + bool canDrag(const QPointF &movePoint) const; + void handleMove(const QPointF &point) override; + void handleRelease(const QPointF &point) override; + qreal position; }; @@ -100,6 +104,32 @@ qreal QQuickSwitchPrivate::positionAt(const QPointF &point) const return pos; } +bool QQuickSwitchPrivate::canDrag(const QPointF &movePoint) const +{ + // don't start dragging the handle unless the initial press was at the indicator, + // or the drag has reached the indicator area. this prevents unnatural jumps when + // dragging far outside the indicator. + const qreal pressPos = positionAt(pressPoint); + const qreal movePos = positionAt(movePoint); + return (pressPos >= 0.0 && pressPos <= 1.0) || (movePos >= 0.0 && movePos <= 1.0); +} + +void QQuickSwitchPrivate::handleMove(const QPointF &point) +{ + Q_Q(QQuickSwitch); + QQuickAbstractButtonPrivate::handleMove(point); + if (q->keepMouseGrab() || q->keepTouchGrab()) + q->setPosition(positionAt(point)); +} + +void QQuickSwitchPrivate::handleRelease(const QPointF &point) +{ + Q_Q(QQuickSwitch); + QQuickAbstractButtonPrivate::handleRelease(point); + q->setKeepMouseGrab(false); + q->setKeepTouchGrab(false); +} + QQuickSwitch::QQuickSwitch(QQuickItem *parent) : QQuickAbstractButton(*(new QQuickSwitchPrivate), parent) { @@ -146,35 +176,29 @@ qreal QQuickSwitch::visualPosition() const return d->position; } -void QQuickSwitch::mousePressEvent(QMouseEvent *event) -{ - QQuickAbstractButton::mousePressEvent(event); -} - void QQuickSwitch::mouseMoveEvent(QMouseEvent *event) { Q_D(QQuickSwitch); - QQuickAbstractButton::mouseMoveEvent(event); - - const QPointF movePoint = event->localPos(); if (!keepMouseGrab()) { - // don't start dragging the handle unless the initial press was at the indicator, - // or the drag has reached the indicator area. this prevents unnatural jumps when - // dragging far outside the indicator. - const qreal pressPos = d->positionAt(d->pressPoint); - const qreal movePos = d->positionAt(movePoint); - if ((pressPos >= 0.0 && pressPos <= 1.0) || (movePos >= 0.0 && movePos <= 1.0)) + const QPointF movePoint = event->localPos(); + if (d->canDrag(movePoint)) setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(), Qt::XAxis, event)); } - - if (keepMouseGrab()) - setPosition(d->positionAt(movePoint)); + QQuickAbstractButton::mouseMoveEvent(event); } -void QQuickSwitch::mouseReleaseEvent(QMouseEvent *event) +void QQuickSwitch::touchEvent(QTouchEvent *event) { - QQuickAbstractButton::mouseReleaseEvent(event); - setKeepMouseGrab(false); + Q_D(QQuickSwitch); + if (!keepTouchGrab() && event->type() == QEvent::TouchUpdate) { + for (const QTouchEvent::TouchPoint &point : event->touchPoints()) { + if (point.id() != d->touchId || point.state() != Qt::TouchPointMoved) + continue; + if (d->canDrag(point.pos())) + setKeepTouchGrab(QQuickWindowPrivate::dragOverThreshold(point.pos().x() - d->pressPoint.x(), Qt::XAxis, &point)); + } + } + QQuickAbstractButton::touchEvent(event); } void QQuickSwitch::mirrorChange() @@ -186,7 +210,7 @@ void QQuickSwitch::mirrorChange() void QQuickSwitch::nextCheckState() { Q_D(QQuickSwitch); - if (keepMouseGrab()) { + if (keepMouseGrab() || keepTouchGrab()) { d->toggle(d->position > 0.5); // the checked state might not change => force a position update to // avoid that the handle is left somewhere in the middle (QTBUG-57944) diff --git a/src/quicktemplates2/qquickswitch_p.h b/src/quicktemplates2/qquickswitch_p.h index ccdb23a8..5b93cd32 100644 --- a/src/quicktemplates2/qquickswitch_p.h +++ b/src/quicktemplates2/qquickswitch_p.h @@ -73,9 +73,8 @@ Q_SIGNALS: void visualPositionChanged(); protected: - void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; + void touchEvent(QTouchEvent *event) override; void mirrorChange() override; diff --git a/tests/auto/controls/data/tst_switch.qml b/tests/auto/controls/data/tst_switch.qml index 6e424609..59575e89 100644 --- a/tests/auto/controls/data/tst_switch.qml +++ b/tests/auto/controls/data/tst_switch.qml @@ -213,7 +213,100 @@ TestCase { verify(spy.success) } - function test_drag() { + function test_touch() { + var control = createTemporaryObject(swtch, testCase) + verify(control) + + var touch = touchEvent(control) + + // check + var spy = signalSequenceSpy.createObject(control, {target: control}) + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(spy.success) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "toggled", + "released", + "clicked"] + touch.release(0, control, control.width / 2, control.height / 2).commit() + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + // uncheck + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(spy.success) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "toggled", + "released", + "clicked"] + touch.release(0, control, control.width / 2, control.height / 2).commit() + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + // release on the right + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(spy.success) + touch.move(0, control, control.width * 2, control.height / 2).commit() + compare(control.pressed, true) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "toggled", + "released", + "clicked"] + touch.release(0, control, control.width * 2, control.height / 2).commit() + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + // release on the left + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(spy.success) + touch.move(0, control, -control.width, control.height / 2).commit() + compare(control.pressed, true) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "toggled", + "released", + "clicked"] + touch.release(0, control, -control.width, control.height / 2).commit() + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + // release in the middle + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + touch.press(0, control, 0, 0).commit() + compare(control.pressed, true) + verify(spy.success) + touch.move(0, control, control.width / 4, control.height / 4).commit() + compare(control.pressed, true) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] + touch.release(0, control, control.width / 4, control.height / 4).commit() + compare(control.checked, false) + compare(control.pressed, false) + tryCompare(control, "position", 0) // QTBUG-57944 + verify(spy.success) + } + + function test_mouseDrag() { var control = createTemporaryObject(swtch, testCase, {leftPadding: 100, rightPadding: 100}) verify(control) @@ -318,6 +411,113 @@ TestCase { verify(spy.success) } + function test_touchDrag() { + var control = createTemporaryObject(swtch, testCase, {leftPadding: 100, rightPadding: 100}) + verify(control) + + var touch = touchEvent(control) + + var spy = signalSequenceSpy.createObject(control, {target: control}) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, false) + + // press-drag-release inside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + touch.press(0, control.indicator, 0).commit() + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + verify(spy.success) + + touch.move(0, control.indicator, control.width).commit() + compare(control.position, 1.0) + compare(control.checked, false) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "toggled", + "released", + "clicked"] + touch.release(0, control.indicator, control.indicator.width).commit() + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + // press-drag-release outside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + touch.press(0, control, 0).commit() + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, true) + verify(spy.success) + + touch.move(0, control, control.width - control.rightPadding).commit() + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, true) + + touch.move(0, control, control.width / 2).commit() + compare(control.position, 0.5) + compare(control.checked, true) + compare(control.pressed, true) + + touch.move(0, control, control.leftPadding).commit() + compare(control.position, 0.0) + compare(control.checked, true) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "toggled", + "released", + "clicked"] + touch.release(0, control, control.width).commit() + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + // press-drag-release from and to outside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + touch.press(0, control, control.width).commit() + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + verify(spy.success) + + touch.move(0, control, control.width - control.rightPadding).commit() + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + + touch.move(0, control, control.width / 2).commit() + compare(control.position, 0.5) + compare(control.checked, false) + compare(control.pressed, true) + + touch.move(0, control, control.width - control.rightPadding).commit() + compare(control.position, 1.0) + compare(control.checked, false) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "toggled", + "released", + "clicked"] + touch.release(0, control, control.width).commit() + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + } + function test_keys() { var control = createTemporaryObject(swtch, testCase) verify(control) |