diff options
Diffstat (limited to 'src/quick/items/qquickflickable.cpp')
-rw-r--r-- | src/quick/items/qquickflickable.cpp | 94 |
1 files changed, 70 insertions, 24 deletions
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 8dc9a9afe6..4ddbfa509a 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -43,6 +43,8 @@ #include "qquickwindow.h" #include "qquickwindow_p.h" #include "qquickevents_p_p.h" +#include "qquickmousearea_p.h" +#include "qquickdrag_p.h" #include <QtQuick/private/qquickpointerhandler_p.h> #include <QtQuick/private/qquicktransition_p.h> @@ -352,7 +354,7 @@ void QQuickFlickablePrivate::AxisData::updateVelocity() } } -void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) +void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeom) { Q_Q(QQuickFlickable); if (item == contentItem) { @@ -361,8 +363,14 @@ void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometr orient |= Qt::Horizontal; if (change.yChange()) orient |= Qt::Vertical; - if (orient) + if (orient) { q->viewportMoved(orient); + const QPointF deltaMoved = item->position() - oldGeom.topLeft(); + if (hData.contentPositionChangedExternallyDuringDrag) + hData.pressPos += deltaMoved.x(); + if (vData.contentPositionChangedExternallyDuringDrag) + vData.pressPos += deltaMoved.y(); + } if (orient & Qt::Horizontal) emit q->contentXChanged(); if (orient & Qt::Vertical) @@ -554,8 +562,8 @@ void QQuickFlickablePrivate::updateBeginningEnd() const qreal maxyextent = -q->maxYExtent(); const qreal minyextent = -q->minYExtent(); const qreal ypos = -vData.move.value(); - bool atBeginning = fuzzyLessThanOrEqualTo(ypos, minyextent); - bool atEnd = fuzzyLessThanOrEqualTo(maxyextent, ypos); + bool atBeginning = fuzzyLessThanOrEqualTo(ypos, std::ceil(minyextent)); + bool atEnd = fuzzyLessThanOrEqualTo(std::floor(maxyextent), ypos); if (atBeginning != vData.atBeginning) { vData.atBeginning = atBeginning; @@ -574,8 +582,8 @@ void QQuickFlickablePrivate::updateBeginningEnd() const qreal maxxextent = -q->maxXExtent(); const qreal minxextent = -q->minXExtent(); const qreal xpos = -hData.move.value(); - atBeginning = fuzzyLessThanOrEqualTo(xpos, minxextent); - atEnd = fuzzyLessThanOrEqualTo(maxxextent, xpos); + atBeginning = fuzzyLessThanOrEqualTo(xpos, std::ceil(minxextent)); + atEnd = fuzzyLessThanOrEqualTo(std::floor(maxxextent), xpos); if (atBeginning != hData.atBeginning) { hData.atBeginning = atBeginning; @@ -822,8 +830,11 @@ void QQuickFlickable::setContentX(qreal pos) d->hData.vTime = d->timeline.time(); if (isMoving() || isFlicking()) movementEnding(true, false); - if (!qFuzzyCompare(-pos, d->hData.move.value())) + if (!qFuzzyCompare(-pos, d->hData.move.value())) { + d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging; d->hData.move.setValue(-pos); + d->hData.contentPositionChangedExternallyDuringDrag = false; + } } qreal QQuickFlickable::contentY() const @@ -840,8 +851,11 @@ void QQuickFlickable::setContentY(qreal pos) d->vData.vTime = d->timeline.time(); if (isMoving() || isFlicking()) movementEnding(false, true); - if (!qFuzzyCompare(-pos, d->vData.move.value())) + if (!qFuzzyCompare(-pos, d->vData.move.value())) { + d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging; d->vData.move.setValue(-pos); + d->vData.contentPositionChangedExternallyDuringDrag = false; + } } /*! @@ -1655,9 +1669,9 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) d->vData.addVelocitySample(instVelocity, d->maxVelocity); d->vData.updateVelocity(); if ((yDelta > 0 && contentY() > -minYExtent()) || (yDelta < 0 && contentY() < -maxYExtent())) { - d->flickY(d->vData.velocity); - d->flickingStarted(false, true); - if (d->vData.flicking) { + const bool newFlick = d->flickY(d->vData.velocity); + if (newFlick && (d->vData.atBeginning != (yDelta > 0) || d->vData.atEnd != (yDelta < 0))) { + d->flickingStarted(false, true); d->vMoved = true; movementStarting(); } @@ -1672,9 +1686,9 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) d->hData.addVelocitySample(instVelocity, d->maxVelocity); d->hData.updateVelocity(); if ((xDelta > 0 && contentX() > -minXExtent()) || (xDelta < 0 && contentX() < -maxXExtent())) { - d->flickX(d->hData.velocity); - d->flickingStarted(true, false); - if (d->hData.flicking) { + const bool newFlick = d->flickX(d->hData.velocity); + if (newFlick && (d->hData.atBeginning != (xDelta > 0) || d->hData.atEnd != (xDelta < 0))) { + d->flickingStarted(true, false); d->hMoved = true; movementStarting(); } @@ -2553,6 +2567,23 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev bool receiverDisabled = receiver && !receiver->isEnabled(); bool stealThisEvent = d->stealMouse; bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab()); + bool receiverRelinquishGrab = false; + + // Special case for MouseArea, try to guess what it does with the event + if (auto *mouseArea = qmlobject_cast<QQuickMouseArea *>(receiver)) { + bool preventStealing = mouseArea->preventStealing(); + if (mouseArea->drag() && mouseArea->drag()->target()) + preventStealing = true; + if (!preventStealing && receiverKeepsGrab) { + receiverRelinquishGrab = !receiverDisabled + || (QQuickDeliveryAgentPrivate::isMouseEvent(event) + && firstPoint.state() == QEventPoint::State::Pressed + && (receiver->acceptedMouseButtons() & static_cast<QMouseEvent *>(event)->button())); + if (receiverRelinquishGrab) + receiverKeepsGrab = false; + } + } + if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) { QScopedPointer<QPointerEvent> localizedEvent(QQuickDeliveryAgentPrivate::clonePointerEvent(event, localPos)); localizedEvent->setAccepted(false); @@ -2563,7 +2594,9 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev case QEventPoint::State::Pressed: d->handlePressEvent(localizedEvent.data()); d->captureDelayedPress(receiver, event); - stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above + // never grab the pointing device on press during filtering: do it later, during a move + d->stealMouse = false; + stealThisEvent = false; break; case QEventPoint::State::Released: d->handleReleaseEvent(localizedEvent.data()); @@ -2580,7 +2613,7 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev event->setExclusiveGrabber(firstPoint, this); } - const bool filtered = stealThisEvent || d->delayedPressEvent || receiverDisabled; + const bool filtered = !receiverRelinquishGrab && (stealThisEvent || d->delayedPressEvent || receiverDisabled); if (filtered) { event->setAccepted(true); } @@ -2606,18 +2639,19 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e) { Q_D(QQuickFlickable); + QPointerEvent *pointerEvent = e->isPointerEvent() ? static_cast<QPointerEvent *>(e) : nullptr; - auto wantsPointerEvent_helper = [this, d, i, e]() { - QPointerEvent *pe = static_cast<QPointerEvent *>(e); - QQuickDeliveryAgentPrivate::localizePointerEvent(pe, this); - const bool wants = d->wantsPointerEvent(pe); + auto wantsPointerEvent_helper = [this, d, i, pointerEvent]() { + Q_ASSERT(pointerEvent); + QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, this); + const bool wants = d->wantsPointerEvent(pointerEvent); // re-localize event back to \a i before returning - QQuickDeliveryAgentPrivate::localizePointerEvent(pe, i); + QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, i); return wants; }; if (!isVisible() || !isEnabled() || !isInteractive() || - (e->isPointerEvent() && !wantsPointerEvent_helper())) { + (pointerEvent && !wantsPointerEvent_helper())) { d->cancelInteraction(); return QQuickItem::childMouseEventFilter(i, e); } @@ -2629,8 +2663,8 @@ bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e) qCDebug(lcFilter) << "filtering UngrabMouse" << spe->points().first() << "for" << i << "grabber is" << grabber; if (grabber != this) mouseUngrabEvent(); // A child has been ungrabbed - } else if (e->isPointerEvent()) { - return filterPointerEvent(i, static_cast<QPointerEvent *>(e)); + } else if (pointerEvent) { + return filterPointerEvent(i, pointerEvent); } return QQuickItem::childMouseEventFilter(i, e); @@ -2898,6 +2932,12 @@ void QQuickFlickable::movementStarting() if (!wasMoving && (d->hData.moving || d->vData.moving)) { emit movingChanged(); emit movementStarted(); +#if QT_CONFIG(accessibility) + if (QAccessible::isActive()) { + QAccessibleEvent ev(this, QAccessible::ScrollingStart); + QAccessible::updateAccessibility(&ev); + } +#endif } } @@ -2942,6 +2982,12 @@ void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding) if (wasMoving && !isMoving()) { emit movingChanged(); emit movementEnded(); +#if QT_CONFIG(accessibility) + if (QAccessible::isActive()) { + QAccessibleEvent ev(this, QAccessible::ScrollingEnd); + QAccessible::updateAccessibility(&ev); + } +#endif } if (hMovementEnding) { |