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.cpp127
1 files changed, 98 insertions, 29 deletions
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 44612edc49..2ad65058b3 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -44,6 +44,7 @@
#include "qquickwindow_p.h"
#include "qquickevents_p_p.h"
+#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquicktransition_p.h>
#include <private/qqmlglobal_p.h>
@@ -255,6 +256,7 @@ QQuickFlickablePrivate::QQuickFlickablePrivate()
, flickBoost(1.0), fixupMode(Normal), vTime(0), visibleArea(0)
, flickableDirection(QQuickFlickable::AutoFlickDirection)
, boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
+ , boundsMovement(QQuickFlickable::FollowBoundsBehavior)
, rebound(0)
{
}
@@ -269,6 +271,7 @@ void QQuickFlickablePrivate::init()
qmlobject_connect(&velocityTimeline, QQuickTimeLine, SIGNAL(completed()),
q, QQuickFlickable, SLOT(velocityTimelineCompleted()))
q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setAcceptTouchEvents(false); // rely on mouse events synthesized from touch
q->setFiltersChildMouseEvents(true);
QQuickItemPrivate *viewportPrivate = QQuickItemPrivate::get(contentItem);
viewportPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
@@ -564,18 +567,6 @@ void QQuickFlickablePrivate::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 QtQuick::Flickable::dragStarted()
@@ -1579,6 +1570,8 @@ void QQuickFlickablePrivate::replayDelayedPress()
// If we have the grab, release before delivering the event
if (QQuickWindow *w = q->window()) {
+ QQuickWindowPrivate *wpriv = QQuickWindowPrivate::get(w);
+ wpriv->allowChildEventFiltering = false; // don't allow re-filtering during replay
replayingPressEvent = true;
if (w->mouseGrabberItem() == q)
q->ungrabMouse();
@@ -1586,6 +1579,7 @@ void QQuickFlickablePrivate::replayDelayedPress()
// Use the event handler that will take care of finding the proper item to propagate the event
QCoreApplication::sendEvent(w, mouseEvent.data());
replayingPressEvent = false;
+ wpriv->allowChildEventFiltering = true;
}
}
}
@@ -1594,16 +1588,18 @@ void QQuickFlickablePrivate::replayDelayedPress()
void QQuickFlickablePrivate::setViewportX(qreal x)
{
Q_Q(QQuickFlickable);
- if (pixelAligned)
- x = -Round(-x);
-
- contentItem->setX(x);
- if (contentItem->x() != x)
- return; // reentered
+ qreal effectiveX = pixelAligned ? -Round(-x) : x;
const qreal maxX = q->maxXExtent();
const qreal minX = q->minXExtent();
+ if (boundsMovement == int(QQuickFlickable::StopAtBounds))
+ effectiveX = qBound(maxX, effectiveX, minX);
+
+ contentItem->setX(effectiveX);
+ if (contentItem->x() != effectiveX)
+ return; // reentered
+
qreal overshoot = 0.0;
if (x <= maxX)
overshoot = maxX - x;
@@ -1619,16 +1615,18 @@ void QQuickFlickablePrivate::setViewportX(qreal x)
void QQuickFlickablePrivate::setViewportY(qreal y)
{
Q_Q(QQuickFlickable);
- if (pixelAligned)
- y = -Round(-y);
-
- contentItem->setY(y);
- if (contentItem->y() != y)
- return; // reentered
+ qreal effectiveY = pixelAligned ? -Round(-y) : y;
const qreal maxY = q->maxYExtent();
const qreal minY = q->minYExtent();
+ if (boundsMovement == int(QQuickFlickable::StopAtBounds))
+ effectiveY = qBound(maxY, effectiveY, minY);
+
+ contentItem->setY(effectiveY);
+ if (contentItem->y() != effectiveY)
+ return; // reentered
+
qreal overshoot = 0.0;
if (y <= maxY)
overshoot = maxY - y;
@@ -1889,8 +1887,9 @@ QQmlListProperty<QQuickItem> QQuickFlickable::flickableChildren()
beyond the Flickable's boundaries, or overshoot the
Flickable's boundaries when flicked.
- This enables the feeling that the edges of the view are soft,
- rather than a hard physical boundary.
+ When the \l boundsMovement is \c Flickable.FollowBoundsBehavior, a value
+ other than \c Flickable.StopAtBounds will give a feeling that the edges of
+ the view are soft, rather than a hard physical boundary.
The \c boundsBehavior can be one of:
@@ -1906,7 +1905,7 @@ QQmlListProperty<QQuickItem> QQuickFlickable::flickableChildren()
boundary when flicked.
\endlist
- \sa horizontalOvershoot, verticalOvershoot
+ \sa horizontalOvershoot, verticalOvershoot, boundsMovement
*/
QQuickFlickable::BoundsBehavior QQuickFlickable::boundsBehavior() const
{
@@ -2721,7 +2720,11 @@ void QQuickFlickablePrivate::updateVelocity()
The value is negative when the content is dragged or flicked beyond the beginning,
and positive when beyond the end; \c 0.0 otherwise.
- \sa verticalOvershoot, boundsBehavior
+ Whether the values are reported for dragging and/or flicking is determined by
+ \l boundsBehavior. The overshoot distance is reported even when \l boundsMovement
+ is \c Flickable.StopAtBounds.
+
+ \sa verticalOvershoot, boundsBehavior, boundsMovement
*/
qreal QQuickFlickable::horizontalOvershoot() const
{
@@ -2738,7 +2741,11 @@ qreal QQuickFlickable::horizontalOvershoot() const
The value is negative when the content is dragged or flicked beyond the beginning,
and positive when beyond the end; \c 0.0 otherwise.
- \sa horizontalOvershoot, boundsBehavior
+ Whether the values are reported for dragging and/or flicking is determined by
+ \l boundsBehavior. The overshoot distance is reported even when \l boundsMovement
+ is \c Flickable.StopAtBounds.
+
+ \sa horizontalOvershoot, boundsBehavior, boundsMovement
*/
qreal QQuickFlickable::verticalOvershoot() const
{
@@ -2746,6 +2753,68 @@ qreal QQuickFlickable::verticalOvershoot() const
return d->vData.overshoot;
}
+/*!
+ \qmlproperty enumeration QtQuick::Flickable::boundsMovement
+ \since 5.10
+
+ This property holds whether the flickable will give a feeling that the edges of the
+ view are soft, rather than a hard physical boundary.
+
+ The \c boundsMovement can be one of:
+
+ \list
+ \li Flickable.StopAtBounds - this allows implementing custom edge effects where the
+ contents do not follow drags or flicks beyond the bounds of the flickable. The values
+ of \l horizontalOvershoot and \l verticalOvershoot can be utilized to implement custom
+ edge effects.
+ \li Flickable.FollowBoundsBehavior (default) - whether the contents follow drags or
+ flicks beyond the bounds of the flickable is determined by \l boundsBehavior.
+ \endlist
+
+ The following example keeps the contents within bounds and instead applies a flip
+ effect when flicked over horizontal bounds:
+ \code
+ Flickable {
+ id: flickable
+ boundsMovement: Flickable.StopAtBounds
+ boundsBehavior: Flickable.DragAndOvershootBounds
+ transform: Rotation {
+ axis { x: 0; y: 1; z: 0 }
+ origin.x: flickable.width / 2
+ origin.y: flickable.height / 2
+ angle: Math.min(30, Math.max(-30, flickable.horizontalOvershoot))
+ }
+ }
+ \endcode
+
+ The following example keeps the contents within bounds and instead applies an opacity
+ effect when dragged over vertical bounds:
+ \code
+ Flickable {
+ boundsMovement: Flickable.StopAtBounds
+ boundsBehavior: Flickable.DragOverBounds
+ opacity: Math.max(0.5, 1.0 - Math.abs(verticalOvershoot) / height)
+ }
+ \endcode
+
+ \sa boundsBehavior, verticalOvershoot, horizontalOvershoot
+*/
+QQuickFlickable::BoundsMovement QQuickFlickable::boundsMovement() const
+{
+ Q_D(const QQuickFlickable);
+ return d->boundsMovement;
+}
+
+void QQuickFlickable::setBoundsMovement(BoundsMovement movement)
+{
+ Q_D(QQuickFlickable);
+ if (d->boundsMovement == movement)
+ return;
+
+ d->boundsMovement = movement;
+ emit boundsMovementChanged();
+}
+
QT_END_NAMESPACE
#include "moc_qquickflickable_p.cpp"