diff options
author | J-P Nurmi <jpnurmi@qt.io> | 2017-01-05 08:31:25 +0100 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2017-01-24 11:53:00 +0000 |
commit | 3ac5f0c795a91efa975935d889c99052b8bc2137 (patch) | |
tree | cac6376556969ca008ba1e53b063a71cb429aeca | |
parent | c9902439780ce197b1e8c75d1c8bd7f97f3f43ae (diff) |
QQuickAbstractButton: handle touch events
This makes it possible to interact with multiple buttons at the same
time.
Change-Id: Ice17efcb8b6dc5337455cd38ee88c39dfef2baae
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r-- | src/quicktemplates2/qquickabstractbutton.cpp | 60 | ||||
-rw-r--r-- | src/quicktemplates2/qquickabstractbutton_p.h | 2 | ||||
-rw-r--r-- | src/quicktemplates2/qquickabstractbutton_p_p.h | 3 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_button.qml | 94 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_checkbox.qml | 63 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_delaybutton.qml | 75 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_radiobutton.qml | 54 |
7 files changed, 350 insertions, 1 deletions
diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp index d8810fcd..17e0abea 100644 --- a/src/quicktemplates2/qquickabstractbutton.cpp +++ b/src/quicktemplates2/qquickabstractbutton.cpp @@ -121,6 +121,7 @@ QQuickAbstractButtonPrivate::QQuickAbstractButtonPrivate() autoExclusive(false), autoRepeat(false), wasHeld(false), + touchId(-1), holdTimer(0), delayTimer(0), repeatTimer(0), @@ -164,6 +165,7 @@ void QQuickAbstractButtonPrivate::handleRelease(const QPointF &point) Q_Q(QQuickAbstractButton); bool wasPressed = pressed; q->setPressed(false); + touchId = -1; if (!wasHeld && (keepPressed || q->contains(point))) q->nextCheckState(); @@ -189,6 +191,7 @@ void QQuickAbstractButtonPrivate::handleCancel() return; q->setPressed(false); + touchId = -1; stopPressRepeat(); stopPressAndHold(); emit q->canceled(); @@ -659,6 +662,63 @@ void QQuickAbstractButton::timerEvent(QTimerEvent *event) } } +void QQuickAbstractButton::touchEvent(QTouchEvent *event) +{ + Q_D(QQuickAbstractButton); + 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()); + } + break; + + case QEvent::TouchUpdate: + for (const QTouchEvent::TouchPoint &point : event->touchPoints()) { + if (point.id() != d->touchId) + continue; + + switch (point.state()) { + case Qt::TouchPointPressed: + d->handlePress(point.pos()); + break; + case Qt::TouchPointMoved: + d->handleMove(point.pos()); + break; + case Qt::TouchPointReleased: + d->handleRelease(point.pos()); + break; + default: + break; + } + } + break; + + case QEvent::TouchEnd: + for (const QTouchEvent::TouchPoint &point : event->touchPoints()) { + if (point.id() == d->touchId) + d->handleRelease(point.pos()); + } + break; + + case QEvent::TouchCancel: + d->handleCancel(); + break; + + default: + QQuickControl::touchEvent(event); + break; + } +} + +void QQuickAbstractButton::touchUngrabEvent() +{ + Q_D(QQuickAbstractButton); + QQuickControl::touchUngrabEvent(); + d->handleCancel(); +} + void QQuickAbstractButton::buttonChange(ButtonChange change) { Q_D(QQuickAbstractButton); diff --git a/src/quicktemplates2/qquickabstractbutton_p.h b/src/quicktemplates2/qquickabstractbutton_p.h index 31b306af..82da94bd 100644 --- a/src/quicktemplates2/qquickabstractbutton_p.h +++ b/src/quicktemplates2/qquickabstractbutton_p.h @@ -125,6 +125,8 @@ protected: void mouseDoubleClickEvent(QMouseEvent *event) override; void mouseUngrabEvent() override; void timerEvent(QTimerEvent *event) override; + void touchEvent(QTouchEvent *event) override; + void touchUngrabEvent() override; enum ButtonChange { ButtonAutoRepeatChange, diff --git a/src/quicktemplates2/qquickabstractbutton_p_p.h b/src/quicktemplates2/qquickabstractbutton_p_p.h index cca7d200..e27f5c82 100644 --- a/src/quicktemplates2/qquickabstractbutton_p_p.h +++ b/src/quicktemplates2/qquickabstractbutton_p_p.h @@ -67,7 +67,7 @@ public: return button->d_func(); } - virtual void handlePress(const QPointF &point, Qt::MouseButton button, Qt::MouseButtons buttons); + virtual void handlePress(const QPointF &point, Qt::MouseButton button = Qt::LeftButton, Qt::MouseButtons buttons = Qt::LeftButton); virtual void handleMove(const QPointF &point); virtual void handleRelease(const QPointF &point); virtual void handleCancel(); @@ -95,6 +95,7 @@ public: bool autoExclusive; bool autoRepeat; bool wasHeld; + int touchId; int holdTimer; int delayTimer; int repeatTimer; diff --git a/tests/auto/controls/data/tst_button.qml b/tests/auto/controls/data/tst_button.qml index ea1dda0b..025279f8 100644 --- a/tests/auto/controls/data/tst_button.qml +++ b/tests/auto/controls/data/tst_button.qml @@ -148,6 +148,100 @@ TestCase { verify(sequenceSpy.success) } + function test_touch() { + var control = createTemporaryObject(button, testCase) + verify(control) + + var touch = touchEvent(control) + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + + // click + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(sequenceSpy.success) + + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }], + "released", + "clicked"] + touch.release(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, false) + verify(sequenceSpy.success) + + // release outside + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(sequenceSpy.success) + + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }]] + touch.move(0, control, control.width * 2, control.height * 2).commit() + compare(control.pressed, false) + verify(sequenceSpy.success) + + sequenceSpy.expectedSequence = [["canceled", { "pressed": false }]] + touch.release(0, control, control.width * 2, control.height * 2).commit() + compare(control.pressed, false) + verify(sequenceSpy.success) + } + + function test_multiTouch() { + var control1 = createTemporaryObject(button, testCase) + verify(control1) + + var pressedCount1 = 0 + + var pressedSpy1 = signalSpy.createObject(control1, {target: control1, signalName: "pressedChanged"}) + verify(pressedSpy1.valid) + + var touch = touchEvent(control1) + touch.press(0, control1, 0, 0).commit().move(0, control1, control1.width, control1.height).commit() + + compare(pressedSpy1.count, ++pressedCount1) + compare(control1.pressed, true) + + // second touch point on the same control is ignored + touch.stationary(0).press(1, control1, 0, 0).commit() + touch.stationary(0).move(1, control1).commit() + touch.stationary(0).release(1).commit() + + compare(pressedSpy1.count, pressedCount1) + compare(control1.pressed, true) + + var control2 = createTemporaryObject(button, testCase, {y: control1.height}) + verify(control2) + waitForRendering(control2) + + var pressedCount2 = 0 + + var pressedSpy2 = signalSpy.createObject(control2, {target: control2, signalName: "pressedChanged"}) + verify(pressedSpy2.valid) + + // press the second button + touch.stationary(0).press(2, control2, 0, 0).commit() + + compare(pressedSpy2.count, ++pressedCount2) + compare(control2.pressed, true) + + compare(pressedSpy1.count, pressedCount1) + compare(control1.pressed, true) + + // release both buttons + touch.release(0, control1).release(2, control2).commit() + + compare(pressedSpy2.count, ++pressedCount2) + compare(control2.pressed, false) + + compare(pressedSpy1.count, ++pressedCount1) + compare(control1.pressed, false) + } + function test_keys() { var control = createTemporaryObject(button, testCase) verify(control) diff --git a/tests/auto/controls/data/tst_checkbox.qml b/tests/auto/controls/data/tst_checkbox.qml index eb052e12..cd46b431 100644 --- a/tests/auto/controls/data/tst_checkbox.qml +++ b/tests/auto/controls/data/tst_checkbox.qml @@ -196,6 +196,69 @@ TestCase { verify(sequenceSpy.success) } + function test_touch() { + var control = createTemporaryObject(checkBox, testCase) + verify(control) + + var touch = touchEvent(control) + + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + + // check + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(sequenceSpy.success) + + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], + ["checkStateChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], + ["checkedChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], + "toggled", + "released", + "clicked"] + touch.release(0, control, control.width / 2, control.height / 2).commit() + compare(control.checked, true) + compare(control.checkState, Qt.Checked) + compare(control.pressed, false) + verify(sequenceSpy.success) + + // uncheck + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(sequenceSpy.success) + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], + ["checkStateChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], + ["checkedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], + "toggled", + "released", + "clicked"] + touch.release(0, control, control.width / 2, control.height / 2).commit() + compare(control.checked, false) + compare(control.checkState, Qt.Unchecked) + compare(control.pressed, false) + verify(sequenceSpy.success) + + // release outside + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(sequenceSpy.success) + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }]] + touch.move(0, control, control.width * 2, control.height * 2).commit() + compare(control.pressed, false) + verify(sequenceSpy.success) + sequenceSpy.expectedSequence = [["canceled", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }]] + touch.release(0, control, control.width * 2, control.height * 2).commit() + compare(control.checked, false) + compare(control.checkState, Qt.Unchecked) + compare(control.pressed, false) + verify(sequenceSpy.success) + } + function test_keys() { var control = createTemporaryObject(checkBox, testCase) verify(control) diff --git a/tests/auto/controls/data/tst_delaybutton.qml b/tests/auto/controls/data/tst_delaybutton.qml index 722c676c..c30bec68 100644 --- a/tests/auto/controls/data/tst_delaybutton.qml +++ b/tests/auto/controls/data/tst_delaybutton.qml @@ -169,6 +169,81 @@ TestCase { verify(sequenceSpy.success) } + function test_touch() { + var control = createTemporaryObject(delayButton, testCase) + verify(control) + + var touch = touchEvent(control) + + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + + // click + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], + "pressed", + ["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }], + "released", + "clicked"] + touch.press(0, control).commit() + touch.release(0, control).commit() + verify(sequenceSpy.success) + + // check + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], + "pressed", + "activated"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + tryVerify(function() { return sequenceSpy.success}) + + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }], + ["checkedChanged", { "checked": true }], + "released", + "clicked"] + touch.release(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, false) + verify(sequenceSpy.success) + + // uncheck + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(sequenceSpy.success) + + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }], + ["checkedChanged", { "checked": false }], + "released", + "clicked"] + touch.release(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, false) + verify(sequenceSpy.success) + + // release outside + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(sequenceSpy.success) + + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }]] + touch.move(0, control, control.width * 2, control.height * 2).commit() + compare(control.pressed, false) + verify(sequenceSpy.success) + + sequenceSpy.expectedSequence = [["canceled", { "pressed": false }]] + touch.release(0, control, control.width * 2, control.height * 2).commit() + compare(control.pressed, false) + verify(sequenceSpy.success) + } + function test_keys() { var control = createTemporaryObject(delayButton, testCase) verify(control) diff --git a/tests/auto/controls/data/tst_radiobutton.qml b/tests/auto/controls/data/tst_radiobutton.qml index e9f1d82c..e878e1ba 100644 --- a/tests/auto/controls/data/tst_radiobutton.qml +++ b/tests/auto/controls/data/tst_radiobutton.qml @@ -156,6 +156,60 @@ TestCase { verify(sequenceSpy.success) } + function test_touch() { + var control = createTemporaryObject(radioButton, testCase) + verify(control) + + var touch = touchEvent(control) + + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + + // check + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(sequenceSpy.success) + sequenceSpy.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(sequenceSpy.success) + + // attempt uncheck + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(sequenceSpy.success) + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + touch.release(0, control, control.width / 2, control.height / 2).commit() + compare(control.checked, true) + compare(control.pressed, false) + verify(sequenceSpy.success) + + // release outside + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + touch.press(0, control, control.width / 2, control.height / 2).commit() + compare(control.pressed, true) + verify(sequenceSpy.success) + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }]] + touch.move(0, control, control.width * 2, control.height * 2).commit() + compare(control.pressed, false) + sequenceSpy.expectedSequence = [["canceled", { "pressed": false, "checked": true }]] + touch.release(0, control, control.width * 2, control.height * 2).commit() + compare(control.checked, true) + compare(control.pressed, false) + verify(sequenceSpy.success) + } + function test_keys() { var control = createTemporaryObject(radioButton, testCase) verify(control) |