aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickflickable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickflickable.cpp')
-rw-r--r--src/quick/items/qquickflickable.cpp104
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