aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2017-01-24 10:48:46 +0100
committerJ-P Nurmi <jpnurmi@qt.io>2017-01-24 11:53:02 +0000
commitdc5f909fe1337aa6d7adf2c2445adaec547c5c6f (patch)
tree00a4691b9ca2ae294ff3c06e119d33df6d249ce6
parent3ac5f0c795a91efa975935d889c99052b8bc2137 (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.cpp66
-rw-r--r--src/quicktemplates2/qquickswitch_p.h3
-rw-r--r--tests/auto/controls/data/tst_switch.qml202
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)