From fe2de633f9b9454ec8a9c2a5874ad85f49d8d54d Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 8 May 2013 15:21:59 +0200 Subject: MultiPointTouchArea: handles mouse too, unless mouseEnabled is false A new boolean property mouseEnabled is introduced (true by default). If set to true, then it will handle any non-synthetic mouse event as if it were a touch point. If set to false, the area becomes transparent for real mouse events so that a MultiPointTouchArea can be stacked on top of a MouseArea in order to separate handling of touch and mouse. In either case it continues to absorb and ignore synthesized mouse events (including touch-to-mouse synthesis in QQuickWindow). [ChangeLog][QtQuick][MultiPointTouchArea]handles mouse as a touchpoint; added mouseEnabled property to permit transparent pass-through to mouse-sensitive items Change-Id: I4af94d838f0060154494589c0f15c6858ee89ddb Task-number: QTBUG-31047 Reviewed-by: Frederik Gladhorn --- src/quick/items/qquickmultipointtoucharea.cpp | 156 ++++++++++- src/quick/items/qquickmultipointtoucharea_p.h | 10 + .../data/dualGestures.qml | 94 +++++++ .../qquickmultipointtoucharea/data/inMouseArea.qml | 30 +++ .../quick/qquickmultipointtoucharea/data/mouse.qml | 29 +++ .../tst_qquickmultipointtoucharea.cpp | 285 +++++++++++++++++++++ 6 files changed, 594 insertions(+), 10 deletions(-) create mode 100644 tests/auto/quick/qquickmultipointtoucharea/data/dualGestures.qml create mode 100644 tests/auto/quick/qquickmultipointtoucharea/data/inMouseArea.qml create mode 100644 tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index 973f6efdcc..6a5ba931c7 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -236,7 +236,14 @@ void QQuickTouchPoint::setSceneY(qreal sceneY) A MultiPointTouchArea is an invisible item that is used to track multiple touch points. The \l Item::enabled property is used to enable and disable touch handling. When disabled, - the touch area becomes transparent to mouse/touch events. + the touch area becomes transparent to mouse and touch events. + + By default, the mouse will be handled the same way as a single touch point, + and items under the touch area will not receive mouse events because the + touch area is handling them. But if the \l mouseEnabled property is set to + false, it becomes transparent to mouse events so that another + mouse-sensitive Item (such as a MouseArea) can be used to handle mouse + interaction separately. MultiPointTouchArea can be used in two ways: @@ -313,6 +320,10 @@ void QQuickTouchPoint::setSceneY(qreal sceneY) This property holds a set of user-defined touch point objects that can be bound to. + If mouseEnabled is true (the default) and the left mouse button is pressed + while the mouse is over the touch area, the current mouse position will be + one of these touch points. + In the following example, we have two small rectangles that follow our touch points. \snippet qml/multipointtoucharea/multipointtoucharea.qml 0 @@ -326,7 +337,9 @@ QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent) : QQuickItem(parent), _minimumTouchPoints(0), _maximumTouchPoints(INT_MAX), - _stealMouse(false) + _mouseTouchPoint(Q_NULLPTR), + _stealMouse(false), + _mouseEnabled(true) { setAcceptedMouseButtons(Qt::LeftButton); setFiltersChildMouseEvents(true); @@ -358,6 +371,11 @@ QQuickMultiPointTouchArea::~QQuickMultiPointTouchArea() one handling two finger touches, and another handling three finger touches. By default, all touch points within the touch area are handled. + + If mouseEnabled is true, the mouse acts as a touch point, so it is also + subject to these constraints: for example if maximumTouchPoints is two, you + can use the mouse as one touch point and a finger as another touch point + for a total of two. */ int QQuickMultiPointTouchArea::minimumTouchPoints() const @@ -386,6 +404,25 @@ void QQuickMultiPointTouchArea::setMaximumTouchPoints(int num) emit maximumTouchPointsChanged(); } +/*! + \qmlproperty bool QtQuick::MultiPointTouchArea::mouseEnabled + + This property controls whether the MultiPointTouchArea will handle mouse + events too. If it is true (the default), the touch area will treat the + mouse the same as a single touch point; if it is false, the touch area will + ignore mouse events and allow them to "pass through" so that they can be + handled by other items underneath. +*/ +void QQuickMultiPointTouchArea::setMouseEnabled(bool arg) +{ + if (_mouseEnabled != arg) { + _mouseEnabled = arg; + if (_mouseTouchPoint && !arg) + _mouseTouchPoint = Q_NULLPTR; + emit mouseEnabledChanged(); + } +} + void QQuickMultiPointTouchArea::touchEvent(QTouchEvent *event) { switch (event->type()) { @@ -434,10 +471,46 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) bool ended = false; bool moved = false; bool started = false; + bool isMouseEvent = false; clearTouchLists(); - QTouchEvent *e = static_cast(event); - QList touchPoints = e->touchPoints(); + QList touchPoints; + + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + touchPoints = static_cast(event)->touchPoints(); + break; + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: { + QMouseEvent *me = static_cast(event); + _mouseQpaTouchPoint.setPos(me->localPos()); + _mouseQpaTouchPoint.setScenePos(me->windowPos()); + _mouseQpaTouchPoint.setScreenPos(me->screenPos()); + if (event->type() == QEvent::MouseMove) + _mouseQpaTouchPoint.setState(Qt::TouchPointMoved); + else if (event->type() == QEvent::MouseButtonRelease) + _mouseQpaTouchPoint.setState(Qt::TouchPointReleased); + else { // QEvent::MouseButtonPress + _mouseQpaTouchPoint.setState(Qt::TouchPointPressed); + _pressedTouchPoints.append(_mouseTouchPoint); + } + touchPoints << _mouseQpaTouchPoint; + isMouseEvent = true; + break; + } + default: + qWarning("updateTouchData: unhandled event type %d", event->type()); + break; + } + + if (!isMouseEvent && _mouseTouchPoint) { + QQuickWindow *c = window(); + if (c && c->mouseGrabberItem() == this) + touchPoints << _mouseQpaTouchPoint; + } int numTouchPoints = touchPoints.count(); //always remove released touches, and make sure we handle all releases before adds. foreach (const QTouchEvent::TouchPoint &p, touchPoints) { @@ -517,10 +590,12 @@ void QQuickMultiPointTouchArea::clearTouchLists() { foreach (QObject *obj, _releasedTouchPoints) { QQuickTouchPoint *dtp = static_cast(obj); - if (!dtp->isQmlDefined()) + if (!dtp->isQmlDefined()) { + _touchPoints.remove(dtp->pointId()); delete dtp; - else + } else { dtp->setInUse(false); + } } _releasedTouchPoints.clear(); _pressedTouchPoints.clear(); @@ -547,6 +622,25 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p) _pressedTouchPoints.append(dtp); } +void QQuickMultiPointTouchArea::addTouchPoint(const QMouseEvent *e) +{ + QQuickTouchPoint *dtp = 0; + foreach (QQuickTouchPoint *tp, _touchPrototypes) + if (!tp->inUse()) { + tp->setInUse(true); + dtp = tp; + break; + } + + if (dtp == 0) + dtp = new QQuickTouchPoint(false); + updateTouchPoint(dtp, e); + dtp->setPressed(true); + _touchPoints.insert(-1, dtp); + _pressedTouchPoints.append(dtp); + _mouseTouchPoint = dtp; +} + #ifdef Q_OS_OSX void QQuickMultiPointTouchArea::hoverEnterEvent(QHoverEvent *event) { @@ -597,9 +691,23 @@ void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QT dtp->setSceneY(p->scenePos().y()); } +void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QMouseEvent *e) +{ + dtp->setPreviousX(dtp->x()); + dtp->setPreviousY(dtp->y()); + dtp->setX(e->localPos().x()); + dtp->setY(e->localPos().y()); + if (e->type() == QEvent::MouseButtonPress) { + dtp->setStartX(e->localPos().x()); + dtp->setStartY(e->localPos().y()); + } + dtp->setSceneX(e->windowPos().x()); + dtp->setSceneY(e->windowPos().y()); +} + void QQuickMultiPointTouchArea::mousePressEvent(QMouseEvent *event) { - if (!isEnabled()) { + if (!isEnabled() || !_mouseEnabled || event->button() != Qt::LeftButton) { QQuickItem::mousePressEvent(event); return; } @@ -607,25 +715,53 @@ void QQuickMultiPointTouchArea::mousePressEvent(QMouseEvent *event) _stealMouse = false; setKeepMouseGrab(false); event->setAccepted(true); + _mousePos = event->localPos(); + + if (event->source() != Qt::MouseEventNotSynthesized) + return; + + if (_touchPoints.count() >= _minimumTouchPoints - 1 && _touchPoints.count() < _maximumTouchPoints) { + addTouchPoint(event); + updateTouchData(event); + emit pressed(_pressedTouchPoints); + } } void QQuickMultiPointTouchArea::mouseMoveEvent(QMouseEvent *event) { - if (!isEnabled()) { + if (!isEnabled() || !_mouseEnabled) { QQuickItem::mouseMoveEvent(event); return; } - //do nothing + if (event->source() != Qt::MouseEventNotSynthesized) + return; + + _movedTouchPoints.clear(); + updateTouchData(event); } void QQuickMultiPointTouchArea::mouseReleaseEvent(QMouseEvent *event) { _stealMouse = false; - if (!isEnabled()) { + if (!isEnabled() || !_mouseEnabled) { QQuickItem::mouseReleaseEvent(event); return; } + + if (event->source() != Qt::MouseEventNotSynthesized) + return; + + if (_mouseTouchPoint) { + updateTouchData(event); + _mouseTouchPoint->setPressed(false); + _mouseTouchPoint->setInUse(false); + _releasedTouchPoints.append(_mouseTouchPoint); + emit released(_releasedTouchPoints); + _releasedTouchPoints.removeAll(_mouseTouchPoint); + _mouseTouchPoint = Q_NULLPTR; + } + QQuickWindow *c = window(); if (c && c->mouseGrabberItem() == this) ungrabMouse(); diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h index 83cc407401..9dbca2be54 100644 --- a/src/quick/items/qquickmultipointtoucharea_p.h +++ b/src/quick/items/qquickmultipointtoucharea_p.h @@ -191,6 +191,7 @@ class Q_AUTOTEST_EXPORT QQuickMultiPointTouchArea : public QQuickItem Q_PROPERTY(QQmlListProperty touchPoints READ touchPoints) Q_PROPERTY(int minimumTouchPoints READ minimumTouchPoints WRITE setMinimumTouchPoints NOTIFY minimumTouchPointsChanged) Q_PROPERTY(int maximumTouchPoints READ maximumTouchPoints WRITE setMaximumTouchPoints NOTIFY maximumTouchPointsChanged) + Q_PROPERTY(bool mouseEnabled READ mouseEnabled WRITE setMouseEnabled NOTIFY mouseEnabledChanged) public: QQuickMultiPointTouchArea(QQuickItem *parent=0); @@ -200,6 +201,8 @@ public: void setMinimumTouchPoints(int num); int maximumTouchPoints() const; void setMaximumTouchPoints(int num); + bool mouseEnabled() const { return _mouseEnabled; } + void setMouseEnabled(bool arg); QQmlListProperty touchPoints() { return QQmlListProperty(this, 0, QQuickMultiPointTouchArea::touchPoint_append, QQuickMultiPointTouchArea::touchPoint_count, QQuickMultiPointTouchArea::touchPoint_at, 0); @@ -229,6 +232,7 @@ Q_SIGNALS: void touchUpdated(const QList &touchPoints); void minimumTouchPointsChanged(); void maximumTouchPointsChanged(); + void mouseEnabledChanged(); protected: void touchEvent(QTouchEvent *); @@ -241,9 +245,11 @@ protected: void addTouchPrototype(QQuickTouchPoint* prototype); void addTouchPoint(const QTouchEvent::TouchPoint *p); + void addTouchPoint(const QMouseEvent *e); void clearTouchLists(); void updateTouchPoint(QQuickTouchPoint*, const QTouchEvent::TouchPoint*); + void updateTouchPoint(QQuickTouchPoint *dtp, const QMouseEvent *e); void updateTouchData(QEvent*); bool sendMouseEvent(QMouseEvent *event); @@ -265,7 +271,11 @@ private: QList _movedTouchPoints; int _minimumTouchPoints; int _maximumTouchPoints; + QQuickTouchPoint *_mouseTouchPoint; // exists when mouse button is down and _mouseEnabled is true; null otherwise + QTouchEvent::TouchPoint _mouseQpaTouchPoint; // synthetic QPA touch point to hold state and position of the mouse + QPointF _mousePos; bool _stealMouse; + bool _mouseEnabled; }; QT_END_NAMESPACE diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/dualGestures.qml b/tests/auto/quick/qquickmultipointtoucharea/data/dualGestures.qml new file mode 100644 index 0000000000..dfb667df30 --- /dev/null +++ b/tests/auto/quick/qquickmultipointtoucharea/data/dualGestures.qml @@ -0,0 +1,94 @@ +/* From the docs about minimumTouchPoints/maximumTouchPoints: + "...allow you to, for example, have nested MultiPointTouchAreas, + one handling two finger touches, and another handling three finger touches." + But in this test they are side-by-side: the left one handles any number + of touches up to 2, and the right one requires 3. +*/ +import QtQuick 2.0 + +Row { + width: 640 + height: 480 + + Rectangle { + color: "black" + border.color: "white" + height: parent.height + width: parent.width / 2 + MultiPointTouchArea { + objectName: "dualTouchArea" + anchors.fill: parent + maximumTouchPoints: 2 + touchPoints: [ + TouchPoint { id: touch1 }, + TouchPoint { id: touch2 } + ] + Rectangle { + objectName: "touch1rect" + color: "red" + width: 30 + height: width + radius: width / 2 + x: touch1.x + y: touch1.y + border.color: touch1.pressed ? "white" : "transparent" + } + Rectangle { + objectName: "touch2rect" + color: "yellow" + width: 30 + height: width + radius: width / 2 + x: touch2.x + y: touch2.y + border.color: touch2.pressed ? "white" : "transparent" + } + } + } + + + Rectangle { + color: "black" + border.color: "white" + height: parent.height + width: parent.width / 2 + MultiPointTouchArea { + objectName: "tripleTouchArea" + anchors.fill: parent + minimumTouchPoints: 3 + maximumTouchPoints: 3 + touchPoints: [ + TouchPoint { id: touch3 }, + TouchPoint { id: touch4 }, + TouchPoint { id: touch5 } + ] + Rectangle { + objectName: "touch3rect" + color: "green" + width: 30 + height: width + x: touch3.x + y: touch3.y + border.color: touch3.pressed ? "white" : "transparent" + } + Rectangle { + objectName: "touch4rect" + color: "blue" + width: 30 + height: width + x: touch4.x + y: touch4.y + border.color: touch4.pressed ? "white" : "transparent" + } + Rectangle { + objectName: "touch5rect" + color: "violet" + width: 30 + height: width + x: touch5.x + y: touch5.y + border.color: touch5.pressed ? "white" : "transparent" + } + } + } +} diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/inMouseArea.qml b/tests/auto/quick/qquickmultipointtoucharea/data/inMouseArea.qml new file mode 100644 index 0000000000..9c5d758e13 --- /dev/null +++ b/tests/auto/quick/qquickmultipointtoucharea/data/inMouseArea.qml @@ -0,0 +1,30 @@ +import QtQuick 2.2 + +MouseArea { + id: root + width: 240 + height: 320 + acceptedButtons: Qt.LeftButton | Qt.RightButton + + Rectangle { + anchors.fill: parent + color: "black" + border.width: 5 + border.color: parent.pressed ? "red" : "blue" + + Rectangle { + anchors.fill: parent + anchors.margins: 25 + color: mpta.pressed ? "orange" : "cyan" + + MultiPointTouchArea { + id: mpta + objectName: "mpta" + property bool pressed: false + anchors.fill: parent + onPressed: pressed = true + onReleased: pressed = false + } + } + } +} diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml b/tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml new file mode 100644 index 0000000000..0abcc76f7c --- /dev/null +++ b/tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml @@ -0,0 +1,29 @@ +import QtQuick 2.0 + +MultiPointTouchArea { + width: 240 + height: 320 + + property int touchCount: 0 + property int cancelCount: 0 + + minimumTouchPoints: 1 + maximumTouchPoints: 4 + touchPoints: [ + TouchPoint { id: p1; objectName: "point1" }, + TouchPoint { objectName: "point2" } + ] + + onPressed: { touchCount = touchPoints.length } + onTouchUpdated: { touchCount = touchPoints.length } + onCanceled: { cancelCount = touchPoints.length } + + Rectangle { + color: "red" + height: 30 + width: 30 + x: p1.x + y: p1.y + } + +} diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp index 2bddac4ef3..1d4932c432 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp +++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -72,9 +73,13 @@ private slots: void nested(); void inFlickable(); void inFlickable2(); + void inMouseArea(); + void mouseAsTouchpoint(); void invisible(); void transformedTouchArea_data(); void transformedTouchArea(); + void mouseInteraction(); + void mouseInteraction_data(); private: QQuickView *createAndShowView(const QString &file); @@ -550,6 +555,9 @@ void tst_QQuickMultiPointTouchArea::inFlickable() QQuickFlickable *flickable = qobject_cast(window->rootObject()); QVERIFY(flickable != 0); + QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild(); + QVERIFY(mpta != 0); + QQuickTouchPoint *point11 = window->rootObject()->findChild("point1"); QQuickTouchPoint *point12 = window->rootObject()->findChild("point2"); @@ -625,6 +633,8 @@ void tst_QQuickMultiPointTouchArea::inFlickable() p1 = QPoint(20,100); p2 = QPoint(40,100); QTest::touchEvent(window.data(), device).press(0, p1).press(1, p2); + // ensure that mouse events do not fall through to the Flickable + mpta->setMaximumTouchPoints(3); QTest::mousePress(window.data(), Qt::LeftButton, 0, p1); QCOMPARE(point11->pressed(), true); @@ -744,6 +754,239 @@ void tst_QQuickMultiPointTouchArea::inFlickable2() QTRY_VERIFY(!flickable->isMoving()); } +// QTBUG-31047 +void tst_QQuickMultiPointTouchArea::inMouseArea() +{ + QScopedPointer window(createAndShowView("inMouseArea.qml")); + QVERIFY(window->rootObject() != 0); + + QQuickMouseArea *mouseArea = qobject_cast(window->rootObject()); + QVERIFY(mouseArea != 0); + + QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild("mpta"); + QVERIFY(mpta != 0); + + QPoint innerPoint(40,100); + QPoint outerPoint(10,100); + + QTest::touchEvent(window.data(), device).press(0, innerPoint); + QVERIFY(mpta->property("pressed").toBool()); + QTest::touchEvent(window.data(), device).release(0, innerPoint); + QVERIFY(!mpta->property("pressed").toBool()); + + QTest::mousePress(window.data(), Qt::LeftButton, 0, outerPoint); + QVERIFY(mouseArea->property("pressed").toBool()); + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, outerPoint); + QVERIFY(!mouseArea->property("pressed").toBool()); + + QTest::mousePress(window.data(), Qt::LeftButton, 0, innerPoint); + QVERIFY(mpta->property("pressed").toBool()); + QVERIFY(!mouseArea->property("pressed").toBool()); + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, innerPoint); + QVERIFY(!mpta->property("pressed").toBool()); + QVERIFY(!mouseArea->property("pressed").toBool()); + + QTest::touchEvent(window.data(), device).press(0, innerPoint); + QVERIFY(mpta->property("pressed").toBool()); + QTest::touchEvent(window.data(), device).release(0, innerPoint); + QVERIFY(!mpta->property("pressed").toBool()); + + QTest::touchEvent(window.data(), device).press(0, outerPoint); + QVERIFY(mouseArea->property("pressed").toBool()); + QVERIFY(!mpta->property("pressed").toBool()); + QTest::touchEvent(window.data(), device).release(0, outerPoint); + QVERIFY(!mouseArea->property("pressed").toBool()); + QVERIFY(!mpta->property("pressed").toBool()); + + // Right click should pass through + QTest::mousePress(window.data(), Qt::RightButton, 0, innerPoint); + QVERIFY(mouseArea->property("pressed").toBool()); + QVERIFY(!mpta->property("pressed").toBool()); + QTest::mouseRelease(window.data(), Qt::RightButton, 0, innerPoint); + + mpta->setProperty("mouseEnabled", false); + + QTest::touchEvent(window.data(), device).press(0, innerPoint); + QVERIFY(mpta->property("pressed").toBool()); + QVERIFY(!mouseArea->property("pressed").toBool()); + QTest::touchEvent(window.data(), device).release(0, innerPoint); + QVERIFY(!mpta->property("pressed").toBool()); + QVERIFY(!mouseArea->property("pressed").toBool()); + + QTest::mousePress(window.data(), Qt::LeftButton, 0, outerPoint); + QVERIFY(mouseArea->property("pressed").toBool()); + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, outerPoint); + QVERIFY(!mouseArea->property("pressed").toBool()); + + QTest::mousePress(window.data(), Qt::LeftButton, 0, innerPoint); + QVERIFY(!mpta->property("pressed").toBool()); + QVERIFY(mouseArea->property("pressed").toBool()); + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, innerPoint); + QVERIFY(!mpta->property("pressed").toBool()); + QVERIFY(!mouseArea->property("pressed").toBool()); + + QTest::touchEvent(window.data(), device).press(0, innerPoint); + QVERIFY(mpta->property("pressed").toBool()); + QTest::touchEvent(window.data(), device).release(0, innerPoint); + QVERIFY(!mpta->property("pressed").toBool()); + + QTest::touchEvent(window.data(), device).press(0, outerPoint); + QVERIFY(mouseArea->property("pressed").toBool()); + QVERIFY(!mpta->property("pressed").toBool()); + QTest::touchEvent(window.data(), device).release(0, outerPoint); + QVERIFY(!mouseArea->property("pressed").toBool()); + QVERIFY(!mpta->property("pressed").toBool()); +} + +void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() +{ + QScopedPointer window(createAndShowView("dualGestures.qml")); + QVERIFY(window->rootObject() != 0); + + QQuickMultiPointTouchArea *dualmpta = window->rootObject()->findChild("dualTouchArea"); + QVERIFY(dualmpta != 0); + + QQuickItem *touch1rect = window->rootObject()->findChild("touch1rect"); + QQuickItem *touch2rect = window->rootObject()->findChild("touch2rect"); + QQuickItem *touch3rect = window->rootObject()->findChild("touch3rect"); + QQuickItem *touch4rect = window->rootObject()->findChild("touch4rect"); + QQuickItem *touch5rect = window->rootObject()->findChild("touch5rect"); + + { + QPoint touch1(40,10); + QPoint touch2(40,100); + QPoint touch3(10,10); + + // Touch both, release one, manipulate other touchpoint with mouse + QTest::touchEvent(window.data(), device).press(1, touch1); + QTest::touchEvent(window.data(), device).press(2, touch2); + QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); + QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); + QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); + QTest::touchEvent(window.data(), device).release(1, touch1); + touch1.setY(20); + QTest::mousePress(window.data(), Qt::LeftButton, 0, touch1); + QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); + QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); + QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); + QTest::touchEvent(window.data(), device).release(2, touch2); + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, touch1); + + // Start with mouse, move it, touch second point, move it + QTest::mousePress(window.data(), Qt::LeftButton, 0, touch1); + touch1.setX(60); + QTest::mouseMove(window.data(), touch1); + QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); + touch2.setX(60); + QTest::touchEvent(window.data(), device).press(3, touch2); + QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); + QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); + QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); + touch2.setY(150); + QTest::touchEvent(window.data(), device).move(3, touch2); + QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); + QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); + QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); + + // Touch third point - nothing happens + QTest::touchEvent(window.data(), device).press(4, touch3); + QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); + QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); + QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); + + // Release all + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, touch1); + QTest::touchEvent(window.data(), device).release(3, touch2); + QTest::touchEvent(window.data(), device).release(4, touch3); + QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); + QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); + QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); + } + + // Mouse and touch on left, touch 3 points on right + { + QPoint mouse1(40,10); + QPoint touch1(10,10); + QPoint touch2(340,10); + QPoint touch3(340,100); + QPoint touch4(540,10); + + QTest::mousePress(window.data(), Qt::LeftButton, 0, mouse1); + QCOMPARE(touch1rect->property("x").toInt(), mouse1.x()); + QCOMPARE(touch1rect->property("y").toInt(), mouse1.y()); + QTest::touchEvent(window.data(), device).press(1, touch1); + QCOMPARE(touch1rect->property("x").toInt(), mouse1.x()); + QCOMPARE(touch1rect->property("y").toInt(), mouse1.y()); + QCOMPARE(touch2rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch2rect->property("y").toInt(), touch1.y()); + + QTest::touchEvent(window.data(), device).press(2, touch2).press(3, touch3).press(4, touch4); + QCOMPARE(touch1rect->property("x").toInt(), mouse1.x()); + QCOMPARE(touch1rect->property("y").toInt(), mouse1.y()); + QCOMPARE(touch2rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch2rect->property("y").toInt(), touch1.y()); + QCOMPARE(touch3rect->property("x").toInt(), touch2.x() - 320); + QCOMPARE(touch3rect->property("y").toInt(), touch2.y()); + QCOMPARE(touch4rect->property("x").toInt(), touch3.x() - 320); + QCOMPARE(touch4rect->property("y").toInt(), touch3.y()); + QCOMPARE(touch5rect->property("x").toInt(), touch4.x() - 320); + QCOMPARE(touch5rect->property("y").toInt(), touch4.y()); + + // Release all + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, mouse1); + QTest::touchEvent(window.data(), device).release(1, touch1).release(2, touch2).release(3, touch3).release(4, touch4); + } + + dualmpta->setProperty("mouseEnabled", false); + { + QPoint mouse1(40,10); + QPoint touch1(10,10); + QPoint touch2(100,10); + + touch1rect->setX(10); + touch1rect->setY(10); + touch2rect->setX(20); + touch2rect->setY(10); + + // Start with mouse, move it, touch a point, move it, touch another. + // Mouse is ignored, both touch points are heeded. + QTest::mousePress(window.data(), Qt::LeftButton, 0, mouse1); + mouse1.setX(60); + QTest::mouseMove(window.data(), mouse1); + QCOMPARE(touch1rect->property("x").toInt(), 10); + QCOMPARE(touch1rect->property("y").toInt(), 10); + + QTest::touchEvent(window.data(), device).press(1, touch1); + QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); + touch1.setY(150); + QTest::touchEvent(window.data(), device).move(1, touch1); + QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); + QTest::touchEvent(window.data(), device).press(2, touch2); + QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); + QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); + QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); + + // Release all + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, mouse1); + QTest::touchEvent(window.data(), device).release(1, touch1); + QTest::touchEvent(window.data(), device).release(2, touch2); + QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); + QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); + QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); + QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); + } +} + // QTBUG-23327 void tst_QQuickMultiPointTouchArea::invisible() { @@ -841,6 +1084,48 @@ QQuickView *tst_QQuickMultiPointTouchArea::createAndShowView(const QString &file return window; } +void tst_QQuickMultiPointTouchArea::mouseInteraction_data() +{ + QTest::addColumn("buttons"); + QTest::addColumn("accept"); + + QTest::newRow("left") << (int) Qt::LeftButton << 1; + QTest::newRow("right") << (int) Qt::RightButton << 0; + QTest::newRow("middle") << (int) Qt::MiddleButton << 0; +} + +void tst_QQuickMultiPointTouchArea::mouseInteraction() +{ + QFETCH(int, buttons); + QFETCH(int, accept); + + QScopedPointer view(createAndShowView("mouse.qml")); + QVERIFY(view->rootObject() != 0); + + QQuickMultiPointTouchArea *area = qobject_cast(view->rootObject()); + QVERIFY(area != 0); + QQuickTouchPoint *point1 = view->rootObject()->findChild("point1"); + QCOMPARE(point1->pressed(), false); + + QCOMPARE(area->property("touchCount").toInt(), 0); + QPoint p1 = QPoint(100, 100); + QTest::mousePress(view.data(), (Qt::MouseButton) buttons, 0, p1); + QCOMPARE(area->property("touchCount").toInt(), accept); + QCOMPARE(point1->pressed(), accept); + p1 += QPoint(10, 10); + QTest::mouseMove(view.data(), p1); + QCOMPARE(point1->pressed(), accept); + QCOMPARE(area->property("touchCount").toInt(), accept); + p1 += QPoint(10, 10); + QTest::mouseMove(view.data(), p1); + QCOMPARE(point1->pressed(), accept); + QCOMPARE(area->property("touchCount").toInt(), accept); + QTest::mouseRelease(view.data(), (Qt::MouseButton) buttons); + QCOMPARE(point1->pressed(), false); + QCOMPARE(area->property("touchCount").toInt(), 0); +} + + QTEST_MAIN(tst_QQuickMultiPointTouchArea) #include "tst_qquickmultipointtoucharea.moc" -- cgit v1.2.3