diff options
author | Martin Jones <martin.jones@nokia.com> | 2011-07-28 10:49:37 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2011-07-28 08:39:33 +0200 |
commit | 68ef13d7915fd86164b1819f7adeea22214a41b7 (patch) | |
tree | 161d8f5cd7719694694551f3adcc50d93a3a0980 | |
parent | 02bf8f421d32ef7449b0fe2fe1ad62fea33bcc61 (diff) |
Add dragging properties to Flickable
This allows the user to determine when a movement is due to the
user dragging the view directly, i.e. excluding any flick that
occurs after the touch is released.
Change-Id: Idf4b699946f808da6fa34ec21a3d2cb2f0ec9de6
Fixes: QTBUG-19685
Reviewed-on: http://codereview.qt.nokia.com/2310
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Bea Lam <bea.lam@nokia.com>
-rw-r--r-- | doc/src/declarative/whatsnew.qdoc | 2 | ||||
-rw-r--r-- | src/declarative/items/qsgflickable.cpp | 99 | ||||
-rw-r--r-- | src/declarative/items/qsgflickable_p.h | 11 | ||||
-rw-r--r-- | src/declarative/items/qsgflickable_p_p.h | 6 | ||||
-rw-r--r-- | tests/auto/declarative/qsgflickable/tst_qsgflickable.cpp | 111 |
5 files changed, 226 insertions, 3 deletions
diff --git a/doc/src/declarative/whatsnew.qdoc b/doc/src/declarative/whatsnew.qdoc index 0bf0fe6f59..f9b6683fa2 100644 --- a/doc/src/declarative/whatsnew.qdoc +++ b/doc/src/declarative/whatsnew.qdoc @@ -43,6 +43,8 @@ set binding when its \e when clause becomes false. QDeclarativeExpression can now be directly (and more efficiently) constructed from a QDeclarativeScriptString. +Flickable: added dragging, draggingHorizontally and draggingVerically properties. + \section2 QtQuick 1 is now a separate library and module Writing C++ applications using QtQuick 1 specific API, i.e. QDeclarativeView or QDeclarativeItem diff --git a/src/declarative/items/qsgflickable.cpp b/src/declarative/items/qsgflickable.cpp index f562a857bb..2c04ab09c6 100644 --- a/src/declarative/items/qsgflickable.cpp +++ b/src/declarative/items/qsgflickable.cpp @@ -428,6 +428,34 @@ void QSGFlickablePrivate::updateBeginningEnd() visibleArea->updateVisible(); } +/* +XXXTODO add docs describing moving, dragging, flicking properties, e.g. + +When the user starts dragging the Flickable, the dragging and moving properties +will be true. + +If the velocity is sufficient when the drag is ended, flicking may begin. + +The moving properties will remain true until all dragging and flicking +is finished. +*/ + +/*! + \qmlsignal QtQuick2::Flickable::onDragStarted() + + This handler is called when the view starts to be dragged due to user + interaction. +*/ + +/*! + \qmlsignal QtQuick2::Flickable::onDragEnded() + + This handler is called when the user stops dragging the view. + + If the velocity of the drag is suffient at the time the + touch/mouse button is released then a flick will start. +*/ + QSGFlickable::QSGFlickable(QSGItem *parent) : QSGItem(*(new QSGFlickablePrivate), parent) { @@ -698,6 +726,7 @@ void QSGFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event) } if (hMoved || vMoved) { + draggingStarting(); q->movementStarting(); q->viewportMoved(); } @@ -724,8 +753,6 @@ void QSGFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *even stealMouse = false; q->setKeepMouseGrab(false); pressed = false; - if (!lastPosTime.isValid()) - return; // if we drag then pause before release we should not cause a flick. if (QSGItemPrivate::elapsed(lastPosTime) < 100) { @@ -736,6 +763,11 @@ void QSGFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *even vData.velocity = 0.0; } + draggingEnding(); + + if (!lastPosTime.isValid()) + return; + vTime = timeline.time(); qreal velocity = vData.velocity; @@ -1231,6 +1263,7 @@ void QSGFlickable::mouseUngrabEvent() // if our mouse grab has been removed (probably by another Flickable), // fix our state d->pressed = false; + d->draggingEnding(); d->stealMouse = false; setKeepMouseGrab(false); } @@ -1375,6 +1408,68 @@ bool QSGFlickable::isFlickingVertically() const return d->flickingVertically; } +/*! + \qmlproperty bool QtQuick2::Flickable::dragging + \qmlproperty bool QtQuick2::Flickable::draggingHorizontally + \qmlproperty bool QtQuick2::Flickable::draggingVertically + + These properties describe whether the view is currently moving horizontally, + vertically or in either direction, due to the user dragging the view. +*/ +bool QSGFlickable::isDragging() const +{ + Q_D(const QSGFlickable); + return d->hData.dragging || d->vData.dragging; +} + +bool QSGFlickable::isDraggingHorizontally() const +{ + Q_D(const QSGFlickable); + return d->hData.dragging; +} + +bool QSGFlickable::isDraggingVertically() const +{ + Q_D(const QSGFlickable); + return d->vData.dragging; +} + +void QSGFlickablePrivate::draggingStarting() +{ + Q_Q(QSGFlickable); + bool wasDragging = hData.dragging || vData.dragging; + if (hMoved && !hData.dragging) { + hData.dragging = true; + emit q->draggingHorizontallyChanged(); + } + if (vMoved && !vData.dragging) { + vData.dragging = true; + emit q->draggingVerticallyChanged(); + } + if (!wasDragging && (hData.dragging || vData.dragging)) { + emit q->draggingChanged(); + emit q->dragStarted(); + } +} + +void QSGFlickablePrivate::draggingEnding() +{ + Q_Q(QSGFlickable); + bool wasDragging = hData.dragging || vData.dragging; + if (hData.dragging) { + hData.dragging = false; + emit q->draggingHorizontallyChanged(); + } + if (vData.dragging) { + vData.dragging = false; + emit q->draggingVerticallyChanged(); + } + if (wasDragging && !hData.dragging && !vData.dragging) { + emit q->draggingChanged(); + emit q->dragEnded(); + } +} + int QSGFlickable::pressDelay() const { Q_D(const QSGFlickable); diff --git a/src/declarative/items/qsgflickable_p.h b/src/declarative/items/qsgflickable_p.h index e934b3a7da..7f12e8a63e 100644 --- a/src/declarative/items/qsgflickable_p.h +++ b/src/declarative/items/qsgflickable_p.h @@ -75,6 +75,9 @@ class Q_AUTOTEST_EXPORT QSGFlickable : public QSGItem Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged) Q_PROPERTY(bool flickingHorizontally READ isFlickingHorizontally NOTIFY flickingHorizontallyChanged) Q_PROPERTY(bool flickingVertically READ isFlickingVertically NOTIFY flickingVerticallyChanged) + Q_PROPERTY(bool dragging READ isDragging NOTIFY draggingChanged) + Q_PROPERTY(bool draggingHorizontally READ isDraggingHorizontally NOTIFY draggingHorizontallyChanged) + Q_PROPERTY(bool draggingVertically READ isDraggingVertically NOTIFY draggingVerticallyChanged) Q_PROPERTY(FlickableDirection flickableDirection READ flickableDirection WRITE setFlickableDirection NOTIFY flickableDirectionChanged) Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged) @@ -123,6 +126,9 @@ public: bool isFlicking() const; bool isFlickingHorizontally() const; bool isFlickingVertically() const; + bool isDragging() const; + bool isDraggingHorizontally() const; + bool isDraggingVertically() const; int pressDelay() const; void setPressDelay(int delay); @@ -164,6 +170,9 @@ Q_SIGNALS: void flickingChanged(); void flickingHorizontallyChanged(); void flickingVerticallyChanged(); + void draggingChanged(); + void draggingHorizontallyChanged(); + void draggingVerticallyChanged(); void horizontalVelocityChanged(); void verticalVelocityChanged(); void isAtBoundaryChanged(); @@ -177,6 +186,8 @@ Q_SIGNALS: void movementEnded(); void flickStarted(); void flickEnded(); + void dragStarted(); + void dragEnded(); protected: virtual bool childMouseEventFilter(QSGItem *, QEvent *); diff --git a/src/declarative/items/qsgflickable_p_p.h b/src/declarative/items/qsgflickable_p_p.h index fd09b0efd4..9e854af62a 100644 --- a/src/declarative/items/qsgflickable_p_p.h +++ b/src/declarative/items/qsgflickable_p_p.h @@ -96,7 +96,7 @@ public: struct AxisData { AxisData(QSGFlickablePrivate *fp, void (QSGFlickablePrivate::*func)(qreal)) : move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true) - , fixingUp(false), inOvershoot(false) + , fixingUp(false), inOvershoot(false), dragging(false) {} void reset() { @@ -123,6 +123,7 @@ public: bool atBeginning : 1; bool fixingUp : 1; bool inOvershoot : 1; + bool dragging : 1; }; void flickX(qreal velocity); @@ -147,6 +148,9 @@ public: void itemGeometryChanged(QSGItem *, const QRectF &, const QRectF &); + void draggingStarting(); + void draggingEnding(); + public: QSGItem *contentItem; diff --git a/tests/auto/declarative/qsgflickable/tst_qsgflickable.cpp b/tests/auto/declarative/qsgflickable/tst_qsgflickable.cpp index d1007819a4..b7c43ce5b0 100644 --- a/tests/auto/declarative/qsgflickable/tst_qsgflickable.cpp +++ b/tests/auto/declarative/qsgflickable/tst_qsgflickable.cpp @@ -77,6 +77,7 @@ private slots: void resizeContent(); void returnToBounds(); void wheel(); + void movingAndDragging(); private: QDeclarativeEngine engine; @@ -400,6 +401,116 @@ void tst_qsgflickable::wheel() delete canvas; } +void tst_qsgflickable::movingAndDragging() +{ + QSGView *canvas = new QSGView; + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/flickable03.qml")); + canvas->show(); + canvas->setFocus(); + QVERIFY(canvas->rootObject() != 0); + + QSGFlickable *flickable = qobject_cast<QSGFlickable*>(canvas->rootObject()); + QVERIFY(flickable != 0); + + QSignalSpy vDragSpy(flickable, SIGNAL(draggingVerticallyChanged())); + QSignalSpy hDragSpy(flickable, SIGNAL(draggingHorizontallyChanged())); + QSignalSpy dragSpy(flickable, SIGNAL(draggingChanged())); + QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged())); + QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); + QSignalSpy moveSpy(flickable, SIGNAL(movingChanged())); + QSignalSpy dragStartSpy(flickable, SIGNAL(dragStarted())); + QSignalSpy dragEndSpy(flickable, SIGNAL(dragEnded())); + + //Vertical + QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 90)); + + QMouseEvent moveEvent(QEvent::MouseMove, QPoint(50, 80), Qt::LeftButton, Qt::LeftButton, 0); + QApplication::sendEvent(canvas, &moveEvent); + + moveEvent = QMouseEvent(QEvent::MouseMove, QPoint(50, 70), Qt::LeftButton, Qt::LeftButton, 0); + QApplication::sendEvent(canvas, &moveEvent); + + moveEvent = QMouseEvent(QEvent::MouseMove, QPoint(50, 60), Qt::LeftButton, Qt::LeftButton, 0); + QApplication::sendEvent(canvas, &moveEvent); + + QVERIFY(!flickable->isDraggingHorizontally()); + QVERIFY(flickable->isDraggingVertically()); + QVERIFY(flickable->isDragging()); + QCOMPARE(vDragSpy.count(), 1); + QCOMPARE(dragSpy.count(), 1); + QCOMPARE(hDragSpy.count(), 0); + QCOMPARE(dragStartSpy.count(), 1); + QCOMPARE(dragEndSpy.count(), 0); + + QVERIFY(!flickable->isMovingHorizontally()); + QVERIFY(flickable->isMovingVertically()); + QVERIFY(flickable->isMoving()); + QCOMPARE(vMoveSpy.count(), 1); + QCOMPARE(moveSpy.count(), 1); + QCOMPARE(hMoveSpy.count(), 0); + + QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 60)); + + QVERIFY(!flickable->isDraggingVertically()); + QVERIFY(!flickable->isDragging()); + QCOMPARE(vDragSpy.count(), 2); + QCOMPARE(dragSpy.count(), 2); + QCOMPARE(hDragSpy.count(), 0); + QCOMPARE(dragStartSpy.count(), 1); + QCOMPARE(dragEndSpy.count(), 1); + + // Don't test moving because a flick could occur + + //Horizontal + vDragSpy.clear(); + hDragSpy.clear(); + dragSpy.clear(); + vMoveSpy.clear(); + hMoveSpy.clear(); + moveSpy.clear(); + dragStartSpy.clear(); + dragEndSpy.clear(); + + QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(90, 50)); + + moveEvent = QMouseEvent(QEvent::MouseMove, QPoint(80, 50), Qt::LeftButton, Qt::LeftButton, 0); + QApplication::sendEvent(canvas, &moveEvent); + + moveEvent = QMouseEvent(QEvent::MouseMove, QPoint(70, 50), Qt::LeftButton, Qt::LeftButton, 0); + QApplication::sendEvent(canvas, &moveEvent); + + moveEvent = QMouseEvent(QEvent::MouseMove, QPoint(60, 50), Qt::LeftButton, Qt::LeftButton, 0); + QApplication::sendEvent(canvas, &moveEvent); + + QVERIFY(flickable->isDraggingHorizontally()); + QVERIFY(flickable->isDragging()); + QCOMPARE(vDragSpy.count(), 0); + QCOMPARE(dragSpy.count(), 1); + QCOMPARE(hDragSpy.count(), 1); + QCOMPARE(dragStartSpy.count(), 1); + QCOMPARE(dragEndSpy.count(), 0); + + QVERIFY(!flickable->isMovingVertically()); + QVERIFY(flickable->isMovingHorizontally()); + QVERIFY(flickable->isMoving()); + QCOMPARE(vMoveSpy.count(), 0); + QCOMPARE(moveSpy.count(), 1); + QCOMPARE(hMoveSpy.count(), 1); + + QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(60, 50)); + + QVERIFY(!flickable->isDraggingHorizontally()); + QVERIFY(!flickable->isDragging()); + QCOMPARE(vDragSpy.count(), 0); + QCOMPARE(dragSpy.count(), 2); + QCOMPARE(hDragSpy.count(), 2); + QCOMPARE(dragStartSpy.count(), 1); + QCOMPARE(dragEndSpy.count(), 1); + + // Don't test moving because a flick could occur + + delete canvas; +} template<typename T> T *tst_qsgflickable::findItem(QSGItem *parent, const QString &objectName) |