aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2017-01-05 08:31:25 +0100
committerJ-P Nurmi <jpnurmi@qt.io>2017-01-24 11:53:00 +0000
commit3ac5f0c795a91efa975935d889c99052b8bc2137 (patch)
treecac6376556969ca008ba1e53b063a71cb429aeca
parentc9902439780ce197b1e8c75d1c8bd7f97f3f43ae (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.cpp60
-rw-r--r--src/quicktemplates2/qquickabstractbutton_p.h2
-rw-r--r--src/quicktemplates2/qquickabstractbutton_p_p.h3
-rw-r--r--tests/auto/controls/data/tst_button.qml94
-rw-r--r--tests/auto/controls/data/tst_checkbox.qml63
-rw-r--r--tests/auto/controls/data/tst_delaybutton.qml75
-rw-r--r--tests/auto/controls/data/tst_radiobutton.qml54
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)