diff options
Diffstat (limited to 'src/quick/items/qquickflickable.cpp')
-rw-r--r-- | src/quick/items/qquickflickable.cpp | 104 |
1 files changed, 66 insertions, 38 deletions
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index cc35630fff..85045be411 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -69,10 +69,6 @@ static const int FlickThreshold = 15; // will ensure the Flickable retains the grab on consecutive flicks. static const int RetainGrabVelocity = 100; -#ifdef Q_OS_OSX -static const int MovementEndingTimerInterval = 100; -#endif - // Currently std::round can't be used on Android when using ndk g++, so // use C version instead. We could just define two versions of Round, one // for float and one for double, but then only one of them would be used @@ -248,6 +244,7 @@ QQuickFlickablePrivate::QQuickFlickablePrivate() , stealMouse(false), pressed(false) , scrollingPhase(false), interactive(true), calcVelocity(false) , pixelAligned(false) + , syncDrag(false) , lastPosTime(-1) , lastPressTime(0) , deceleration(QML_FLICK_DEFAULTDECELERATION) @@ -508,7 +505,8 @@ static bool fuzzyLessThanOrEqualTo(qreal a, qreal b) void QQuickFlickablePrivate::updateBeginningEnd() { Q_Q(QQuickFlickable); - bool atBoundaryChange = false; + bool atXBeginningChange = false, atXEndChange = false; + bool atYBeginningChange = false, atYEndChange = false; // Vertical const qreal maxyextent = -q->maxYExtent(); @@ -519,11 +517,11 @@ void QQuickFlickablePrivate::updateBeginningEnd() if (atBeginning != vData.atBeginning) { vData.atBeginning = atBeginning; - atBoundaryChange = true; + atYBeginningChange = true; } if (atEnd != vData.atEnd) { vData.atEnd = atEnd; - atBoundaryChange = true; + atYEndChange = true; } // Horizontal @@ -535,11 +533,11 @@ void QQuickFlickablePrivate::updateBeginningEnd() if (atBeginning != hData.atBeginning) { hData.atBeginning = atBeginning; - atBoundaryChange = true; + atXBeginningChange = true; } if (atEnd != hData.atEnd) { hData.atEnd = atEnd; - atBoundaryChange = true; + atXEndChange = true; } if (vData.extentsChanged) { @@ -560,8 +558,16 @@ void QQuickFlickablePrivate::updateBeginningEnd() } } - if (atBoundaryChange) + if (atXEndChange || atYEndChange || atXBeginningChange || atYBeginningChange) emit q->isAtBoundaryChanged(); + if (atXEndChange) + emit q->atXEndChanged(); + if (atXBeginningChange) + emit q->atXBeginningChanged(); + if (atYEndChange) + emit q->atYEndChanged(); + if (atYBeginningChange) + emit q->atYBeginningChanged(); if (visibleArea) visibleArea->updateVisible(); @@ -984,6 +990,33 @@ void QQuickFlickable::setPixelAligned(bool align) } } +/*! + \qmlproperty bool QtQuick::Flickable::synchronousDrag + \since 5.12 + + If this property is set to true, then when the mouse or touchpoint moves + far enough to begin dragging the content, the content will jump, such that + the content pixel which was under the cursor or touchpoint when pressed + remains under that point. + + The default is \c false, which provides a smoother experience (no jump) + at the cost that some of the drag distance is "lost" at the beginning. +*/ +bool QQuickFlickable::synchronousDrag() const +{ + Q_D(const QQuickFlickable); + return d->syncDrag; +} + +void QQuickFlickable::setSynchronousDrag(bool v) +{ + Q_D(QQuickFlickable); + if (v != d->syncDrag) { + d->syncDrag = v; + emit synchronousDragChanged(); + } +} + qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event) const { if (0 != event->timestamp()) @@ -1100,7 +1133,7 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp if (overThreshold || elapsedSincePress > 200) { if (!vMoved) vData.dragStartOffset = dy; - qreal newY = dy + vData.pressPos - vData.dragStartOffset; + qreal newY = dy + vData.pressPos - (syncDrag ? 0 : vData.dragStartOffset); // Recalculate bounds in case margins have changed, but use the content // size estimate taken at the start of the drag in case the drag causes // the estimate to be altered @@ -1176,7 +1209,7 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp if (overThreshold || elapsedSincePress > 200) { if (!hMoved) hData.dragStartOffset = dx; - qreal newX = dx + hData.pressPos - hData.dragStartOffset; + qreal newX = dx + hData.pressPos - (syncDrag ? 0 : hData.dragStartOffset); const qreal minX = hData.dragMinBound + hData.startMargin; const qreal maxX = hData.dragMaxBound - hData.endMargin; if (!(boundsBehavior & QQuickFlickable::DragOverBounds)) { @@ -1280,7 +1313,7 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event) { Q_Q(QQuickFlickable); - if (!interactive || lastPosTime == -1) + if (!interactive || lastPosTime == -1 || event->buttons() == Qt::NoButton) return; qint64 currentTimestamp = computeCurrentTime(event); @@ -1460,23 +1493,24 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) case Qt::ScrollUpdate: if (d->scrollingPhase) d->pressed = true; -#ifdef Q_OS_MACOS - // TODO eliminate this timer when ScrollMomentum has been added - d->movementEndingTimer.start(MovementEndingTimerInterval, this); -#endif + break; + case Qt::ScrollMomentum: + d->pressed = false; + d->scrollingPhase = false; + d->draggingEnding(); + event->accept(); + d->lastPosTime = -1; break; case Qt::ScrollEnd: - // TODO most of this should be done at transition to ScrollMomentum phase, - // then do what the movementEndingTimer triggers at transition to ScrollEnd phase d->pressed = false; d->scrollingPhase = false; d->draggingEnding(); event->accept(); returnToBounds(); d->lastPosTime = -1; -#ifdef Q_OS_MACOS - d->movementEndingTimer.start(MovementEndingTimerInterval, this); -#endif + d->stealMouse = false; + if (!d->velocityTimeline.isActive() && !d->timeline.isActive()) + movementEnding(true, true); return; } @@ -1672,14 +1706,6 @@ void QQuickFlickable::timerEvent(QTimerEvent *event) if (d->delayedPressEvent) { d->replayDelayedPress(); } - } else if (event->timerId() == d->movementEndingTimer.timerId()) { - d->movementEndingTimer.stop(); - if (!d->scrollingPhase) { - d->pressed = false; - d->stealMouse = false; - if (!d->velocityTimeline.isActive() && !d->timeline.isActive()) - movementEnding(true, true); - } } } @@ -1821,8 +1847,8 @@ void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity) d->vData.velocity = yVelocity; d->hData.vTime = d->vData.vTime = d->timeline.time(); - bool flickedX = d->flickX(xVelocity); - bool flickedY = d->flickY(yVelocity); + const bool flickedX = xflick() && !qFuzzyIsNull(xVelocity) && d->flickX(xVelocity); + const bool flickedY = yflick() && !qFuzzyIsNull(yVelocity) && d->flickY(yVelocity); if (flickedX) d->hMoved = true; @@ -2540,7 +2566,7 @@ void QQuickFlickablePrivate::draggingStarting() void QQuickFlickablePrivate::draggingEnding() { Q_Q(QQuickFlickable); - bool wasDragging = hData.dragging || vData.dragging; + const bool wasDragging = hData.dragging || vData.dragging; if (hData.dragging) { hData.dragging = false; emit q->draggingHorizontallyChanged(); @@ -2549,12 +2575,14 @@ void QQuickFlickablePrivate::draggingEnding() vData.dragging = false; emit q->draggingVerticallyChanged(); } - if (wasDragging && !hData.dragging && !vData.dragging) { - emit q->draggingChanged(); - emit q->dragEnded(); + if (wasDragging) { + if (!hData.dragging && !vData.dragging) { + emit q->draggingChanged(); + emit q->dragEnded(); + } + hData.inRebound = false; + vData.inRebound = false; } - hData.inRebound = false; - vData.inRebound = false; } bool QQuickFlickablePrivate::isViewMoving() const |