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:
parent
02bf8f421d
commit
68ef13d791
|
@ -43,6 +43,8 @@ set binding when its \e when clause becomes false.
|
||||||
QDeclarativeExpression can now be directly (and more efficiently) constructed from a
|
QDeclarativeExpression can now be directly (and more efficiently) constructed from a
|
||||||
QDeclarativeScriptString.
|
QDeclarativeScriptString.
|
||||||
|
|
||||||
|
Flickable: added dragging, draggingHorizontally and draggingVerically properties.
|
||||||
|
|
||||||
\section2 QtQuick 1 is now a separate library and module
|
\section2 QtQuick 1 is now a separate library and module
|
||||||
|
|
||||||
Writing C++ applications using QtQuick 1 specific API, i.e. QDeclarativeView or QDeclarativeItem
|
Writing C++ applications using QtQuick 1 specific API, i.e. QDeclarativeView or QDeclarativeItem
|
||||||
|
|
|
@ -428,6 +428,34 @@ void QSGFlickablePrivate::updateBeginningEnd()
|
||||||
visibleArea->updateVisible();
|
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)
|
QSGFlickable::QSGFlickable(QSGItem *parent)
|
||||||
: QSGItem(*(new QSGFlickablePrivate), parent)
|
: QSGItem(*(new QSGFlickablePrivate), parent)
|
||||||
{
|
{
|
||||||
|
@ -698,6 +726,7 @@ void QSGFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hMoved || vMoved) {
|
if (hMoved || vMoved) {
|
||||||
|
draggingStarting();
|
||||||
q->movementStarting();
|
q->movementStarting();
|
||||||
q->viewportMoved();
|
q->viewportMoved();
|
||||||
}
|
}
|
||||||
|
@ -724,8 +753,6 @@ void QSGFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *even
|
||||||
stealMouse = false;
|
stealMouse = false;
|
||||||
q->setKeepMouseGrab(false);
|
q->setKeepMouseGrab(false);
|
||||||
pressed = false;
|
pressed = false;
|
||||||
if (!lastPosTime.isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if we drag then pause before release we should not cause a flick.
|
// if we drag then pause before release we should not cause a flick.
|
||||||
if (QSGItemPrivate::elapsed(lastPosTime) < 100) {
|
if (QSGItemPrivate::elapsed(lastPosTime) < 100) {
|
||||||
|
@ -736,6 +763,11 @@ void QSGFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *even
|
||||||
vData.velocity = 0.0;
|
vData.velocity = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
draggingEnding();
|
||||||
|
|
||||||
|
if (!lastPosTime.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
vTime = timeline.time();
|
vTime = timeline.time();
|
||||||
|
|
||||||
qreal velocity = vData.velocity;
|
qreal velocity = vData.velocity;
|
||||||
|
@ -1231,6 +1263,7 @@ void QSGFlickable::mouseUngrabEvent()
|
||||||
// if our mouse grab has been removed (probably by another Flickable),
|
// if our mouse grab has been removed (probably by another Flickable),
|
||||||
// fix our state
|
// fix our state
|
||||||
d->pressed = false;
|
d->pressed = false;
|
||||||
|
d->draggingEnding();
|
||||||
d->stealMouse = false;
|
d->stealMouse = false;
|
||||||
setKeepMouseGrab(false);
|
setKeepMouseGrab(false);
|
||||||
}
|
}
|
||||||
|
@ -1375,6 +1408,68 @@ bool QSGFlickable::isFlickingVertically() const
|
||||||
return d->flickingVertically;
|
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
|
int QSGFlickable::pressDelay() const
|
||||||
{
|
{
|
||||||
Q_D(const QSGFlickable);
|
Q_D(const QSGFlickable);
|
||||||
|
|
|
@ -75,6 +75,9 @@ class Q_AUTOTEST_EXPORT QSGFlickable : public QSGItem
|
||||||
Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged)
|
Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged)
|
||||||
Q_PROPERTY(bool flickingHorizontally READ isFlickingHorizontally NOTIFY flickingHorizontallyChanged)
|
Q_PROPERTY(bool flickingHorizontally READ isFlickingHorizontally NOTIFY flickingHorizontallyChanged)
|
||||||
Q_PROPERTY(bool flickingVertically READ isFlickingVertically NOTIFY flickingVerticallyChanged)
|
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(FlickableDirection flickableDirection READ flickableDirection WRITE setFlickableDirection NOTIFY flickableDirectionChanged)
|
||||||
|
|
||||||
Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged)
|
Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged)
|
||||||
|
@ -123,6 +126,9 @@ public:
|
||||||
bool isFlicking() const;
|
bool isFlicking() const;
|
||||||
bool isFlickingHorizontally() const;
|
bool isFlickingHorizontally() const;
|
||||||
bool isFlickingVertically() const;
|
bool isFlickingVertically() const;
|
||||||
|
bool isDragging() const;
|
||||||
|
bool isDraggingHorizontally() const;
|
||||||
|
bool isDraggingVertically() const;
|
||||||
|
|
||||||
int pressDelay() const;
|
int pressDelay() const;
|
||||||
void setPressDelay(int delay);
|
void setPressDelay(int delay);
|
||||||
|
@ -164,6 +170,9 @@ Q_SIGNALS:
|
||||||
void flickingChanged();
|
void flickingChanged();
|
||||||
void flickingHorizontallyChanged();
|
void flickingHorizontallyChanged();
|
||||||
void flickingVerticallyChanged();
|
void flickingVerticallyChanged();
|
||||||
|
void draggingChanged();
|
||||||
|
void draggingHorizontallyChanged();
|
||||||
|
void draggingVerticallyChanged();
|
||||||
void horizontalVelocityChanged();
|
void horizontalVelocityChanged();
|
||||||
void verticalVelocityChanged();
|
void verticalVelocityChanged();
|
||||||
void isAtBoundaryChanged();
|
void isAtBoundaryChanged();
|
||||||
|
@ -177,6 +186,8 @@ Q_SIGNALS:
|
||||||
void movementEnded();
|
void movementEnded();
|
||||||
void flickStarted();
|
void flickStarted();
|
||||||
void flickEnded();
|
void flickEnded();
|
||||||
|
void dragStarted();
|
||||||
|
void dragEnded();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool childMouseEventFilter(QSGItem *, QEvent *);
|
virtual bool childMouseEventFilter(QSGItem *, QEvent *);
|
||||||
|
|
|
@ -96,7 +96,7 @@ public:
|
||||||
struct AxisData {
|
struct AxisData {
|
||||||
AxisData(QSGFlickablePrivate *fp, void (QSGFlickablePrivate::*func)(qreal))
|
AxisData(QSGFlickablePrivate *fp, void (QSGFlickablePrivate::*func)(qreal))
|
||||||
: move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true)
|
: move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true)
|
||||||
, fixingUp(false), inOvershoot(false)
|
, fixingUp(false), inOvershoot(false), dragging(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
|
@ -123,6 +123,7 @@ public:
|
||||||
bool atBeginning : 1;
|
bool atBeginning : 1;
|
||||||
bool fixingUp : 1;
|
bool fixingUp : 1;
|
||||||
bool inOvershoot : 1;
|
bool inOvershoot : 1;
|
||||||
|
bool dragging : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
void flickX(qreal velocity);
|
void flickX(qreal velocity);
|
||||||
|
@ -147,6 +148,9 @@ public:
|
||||||
|
|
||||||
void itemGeometryChanged(QSGItem *, const QRectF &, const QRectF &);
|
void itemGeometryChanged(QSGItem *, const QRectF &, const QRectF &);
|
||||||
|
|
||||||
|
void draggingStarting();
|
||||||
|
void draggingEnding();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QSGItem *contentItem;
|
QSGItem *contentItem;
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,7 @@ private slots:
|
||||||
void resizeContent();
|
void resizeContent();
|
||||||
void returnToBounds();
|
void returnToBounds();
|
||||||
void wheel();
|
void wheel();
|
||||||
|
void movingAndDragging();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QDeclarativeEngine engine;
|
QDeclarativeEngine engine;
|
||||||
|
@ -400,6 +401,116 @@ void tst_qsgflickable::wheel()
|
||||||
delete canvas;
|
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>
|
template<typename T>
|
||||||
T *tst_qsgflickable::findItem(QSGItem *parent, const QString &objectName)
|
T *tst_qsgflickable::findItem(QSGItem *parent, const QString &objectName)
|
||||||
|
|
Loading…
Reference in New Issue