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>
This commit is contained in:
Martin Jones 2011-07-28 10:49:37 +10:00 committed by Qt by Nokia
parent 02bf8f421d
commit 68ef13d791
5 changed files with 226 additions and 3 deletions

View File

@ -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

View File

@ -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);

View File

@ -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 *);

View File

@ -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;

View File

@ -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)