diff options
author | Andrew den Exter <andrew.den.exter@jollamobile.com> | 2013-02-16 17:59:50 +1000 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-02-22 02:53:35 +0100 |
commit | 67db779665b1d95a20720c0dee058c47f7df8726 (patch) | |
tree | e8a7fc3b94304c31438cd86c9271e4a0e71c63e2 | |
parent | f7680b55f0d1d1ef102d40166f74cf4eee605e44 (diff) |
MouseArea shouldn't grab the mouse until there is an effective drag.
A MouseArea shouldn't prevent a parent MouseArea or Flickable from
handling a drag event unless it is going to do something useful with
it.
Task-number: QTBUG-29717
Change-Id: I17caa51ebc2e547e73e727fd185e60644591ad2b
Reviewed-by: Alan Alpert <aalpert@rim.com>
3 files changed, 137 insertions, 22 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp index a7c38ea8..9fa325b0 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea.cpp +++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp @@ -530,37 +530,32 @@ void QDeclarativeMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event) curLocalPos = event->scenePos(); } - const int dragThreshold = QApplication::startDragDistance(); - qreal dx = qAbs(curLocalPos.x() - startLocalPos.x()); - qreal dy = qAbs(curLocalPos.y() - startLocalPos.y()); - if (keepMouseGrab() && d->stealMouse) d->drag->setActive(true); bool dragX = drag()->axis() & QDeclarativeDrag::XAxis; bool dragY = drag()->axis() & QDeclarativeDrag::YAxis; - if (dragX && d->drag->active()) { - qreal x = (curLocalPos.x() - startLocalPos.x()) + d->startX; - if (x < drag()->xmin()) - x = drag()->xmin(); - else if (x > drag()->xmax()) - x = drag()->xmax(); - drag()->target()->setX(x); - } - if (dragY && d->drag->active()) { - qreal y = (curLocalPos.y() - startLocalPos.y()) + d->startY; - if (y < drag()->ymin()) - y = drag()->ymin(); - else if (y > drag()->ymax()) - y = drag()->ymax(); - drag()->target()->setY(y); + const qreal x = dragX + ? qBound(d->drag->xmin(), d->startX + curLocalPos.x() - startLocalPos.x(), d->drag->xmax()) + : d->startX; + const qreal y = dragY + ? qBound(d->drag->ymin(), d->startY + curLocalPos.y() - startLocalPos.y(), d->drag->ymax()) + : d->startY; + + if (d->drag->active()) { + if (dragX && dragY) + d->drag->target()->setPos(x, y); + else if (dragX) + d->drag->target()->setX(x); + else if (dragY) + d->drag->target()->setY(y); } if (!keepMouseGrab()) { - if ((!dragY && dy < dragThreshold && dragX && dx > dragThreshold) - || (!dragX && dx < dragThreshold && dragY && dy > dragThreshold) - || (dragX && dragY && (dx > dragThreshold || dy > dragThreshold))) { + const int dragThreshold = QApplication::startDragDistance(); + + if (qAbs(x - d->startX) > dragThreshold || qAbs(y - d->startY) > dragThreshold) { setKeepMouseGrab(true); d->stealMouse = true; } diff --git a/tests/auto/declarative/qdeclarativemousearea/data/nestedStopAtBounds.qml b/tests/auto/declarative/qdeclarativemousearea/data/nestedStopAtBounds.qml new file mode 100644 index 00000000..0379964d --- /dev/null +++ b/tests/auto/declarative/qdeclarativemousearea/data/nestedStopAtBounds.qml @@ -0,0 +1,44 @@ +import QtQuick 1.1 + +Rectangle { + width: 400 + height: 400 + + MouseArea { + id: outer + objectName: "outer" + x: 50 + y: 50 + width: 300 + height: 300 + + drag.target: outer + drag.filterChildren: true + + Rectangle { + anchors.fill: parent + color: "yellow" + } + + MouseArea { + id: inner + objectName: "inner" + + x: 0 + y: 0 + width: 200 + height: 200 + + drag.target: inner + drag.minimumX: 0 + drag.maximumX: 100 + drag.minimumY: 0 + drag.maximumY: 100 + + Rectangle { + anchors.fill: parent + color: "blue" + } + } + } +} diff --git a/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp b/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp index b28381ef..855ad602 100644 --- a/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp +++ b/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp @@ -71,6 +71,8 @@ private slots: void preventContextMenu(); #endif // QT_NO_CONTEXTMENU void changeAxis(); + void nestedStopAtBounds(); + void nestedStopAtBounds_data(); private: QDeclarativeView *createView(); @@ -776,6 +778,80 @@ void tst_QDeclarativeMouseArea::changeAxis() delete canvas; } +void tst_QDeclarativeMouseArea::nestedStopAtBounds_data() +{ + QTest::addColumn<bool>("transpose"); + QTest::addColumn<bool>("invert"); + + QTest::newRow("left") << false << false; + QTest::newRow("right") << false << true; + QTest::newRow("top") << true << false; + QTest::newRow("bottom") << true << true; +} + +void tst_QDeclarativeMouseArea::nestedStopAtBounds() +{ + QFETCH(bool, transpose); + QFETCH(bool, invert); + + QDeclarativeView view; + view.setSource(QUrl::fromLocalFile(SRCDIR "/data/nestedStopAtBounds.qml")); + view.show(); + view.activateWindow(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QVERIFY(view.rootObject()); + + QDeclarativeMouseArea *outer = view.rootObject()->findChild<QDeclarativeMouseArea*>("outer"); + QVERIFY(outer); + + QDeclarativeMouseArea *inner = outer->findChild<QDeclarativeMouseArea*>("inner"); + QVERIFY(inner); + inner->drag()->setAxis(transpose ? QDeclarativeDrag::YAxis : QDeclarativeDrag::XAxis); + inner->setX(invert ? 100 : 0); + inner->setY(invert ? 100 : 0); + + const int threshold = QApplication::startDragDistance(); + + QPoint position(200, 200); + int &axis = transpose ? position.ry() : position.rx(); + + QGraphicsSceneMouseEvent moveEvent(QEvent::GraphicsSceneMouseMove); + moveEvent.setButton(Qt::LeftButton); + moveEvent.setButtons(Qt::LeftButton); + + // drag toward the aligned boundary. Outer mouse area dragged. + QTest::mousePress(view.viewport(), Qt::LeftButton, 0, position); + QTest::qWait(10); + axis += invert ? threshold * 2 : -threshold * 2; + moveEvent.setScenePos(position); + QApplication::sendEvent(view.scene(), &moveEvent); + axis += invert ? threshold : -threshold; + moveEvent.setScenePos(position); + QApplication::sendEvent(view.scene(), &moveEvent); + QCOMPARE(outer->drag()->active(), true); + QCOMPARE(inner->drag()->active(), false); + QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, position); + + QVERIFY(!outer->drag()->active()); + + axis = 200; + outer->setX(50); + outer->setY(50); + + // drag away from the aligned boundary. Inner mouse area dragged. + QTest::mousePress(view.viewport(), Qt::LeftButton, 0, position); + QTest::qWait(10); + axis += invert ? -threshold * 2 : threshold * 2; + moveEvent.setScenePos(position); + QApplication::sendEvent(view.scene(), &moveEvent); + axis += invert ? -threshold : threshold; + moveEvent.setScenePos(position); + QApplication::sendEvent(view.scene(), &moveEvent); + QCOMPARE(outer->drag()->active(), false); + QCOMPARE(inner->drag()->active(), true); + QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, position); +} + QTEST_MAIN(tst_QDeclarativeMouseArea) #include "tst_qdeclarativemousearea.moc" |