2011-04-27 12:13:26 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2012-01-05 04:29:18 +00:00
|
|
|
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
2012-01-20 04:04:27 +00:00
|
|
|
** Contact: http://www.qt-project.org/
|
2011-04-27 12:13:26 +00:00
|
|
|
**
|
|
|
|
** This file is part of the QtDeclarative module of the Qt Toolkit.
|
|
|
|
**
|
|
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
|
|
|
** GNU Lesser General Public License Usage
|
2011-07-07 12:52:03 +00:00
|
|
|
** This file may be used under the terms of the GNU Lesser General Public
|
|
|
|
** License version 2.1 as published by the Free Software Foundation and
|
|
|
|
** appearing in the file LICENSE.LGPL included in the packaging of this
|
|
|
|
** file. Please review the following information to ensure the GNU Lesser
|
|
|
|
** General Public License version 2.1 requirements will be met:
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2011-04-27 12:13:26 +00:00
|
|
|
**
|
|
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
2011-07-07 12:52:03 +00:00
|
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
2011-04-27 12:13:26 +00:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
2011-07-07 12:52:03 +00:00
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU General
|
|
|
|
** Public License version 3.0 as published by the Free Software Foundation
|
|
|
|
** and appearing in the file LICENSE.GPL included in the packaging of this
|
|
|
|
** file. Please review the following information to ensure the GNU General
|
|
|
|
** Public License version 3.0 requirements will be met:
|
|
|
|
** http://www.gnu.org/copyleft/gpl.html.
|
|
|
|
**
|
|
|
|
** Other Usage
|
|
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
2011-04-27 12:13:26 +00:00
|
|
|
**
|
|
|
|
**
|
|
|
|
**
|
|
|
|
**
|
|
|
|
**
|
2012-01-24 03:37:23 +00:00
|
|
|
**
|
2011-04-27 12:13:26 +00:00
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
#include "qquickflickable_p.h"
|
|
|
|
#include "qquickflickable_p_p.h"
|
|
|
|
#include "qquickcanvas.h"
|
|
|
|
#include "qquickcanvas_p.h"
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
#include <QtDeclarative/qdeclarativeinfo.h>
|
2011-08-30 14:48:57 +00:00
|
|
|
#include <QtGui/qevent.h>
|
2011-08-30 11:17:00 +00:00
|
|
|
#include <QtGui/qguiapplication.h>
|
|
|
|
#include <QtGui/qstylehints.h>
|
2011-05-04 07:53:51 +00:00
|
|
|
#include "qplatformdefs.h"
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
2011-05-04 07:53:51 +00:00
|
|
|
// The maximum number of pixels a flick can overshoot
|
|
|
|
#ifndef QML_FLICK_OVERSHOOT
|
|
|
|
#define QML_FLICK_OVERSHOOT 200
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// The number of samples to use in calculating the velocity of a flick
|
|
|
|
#ifndef QML_FLICK_SAMPLEBUFFER
|
|
|
|
#define QML_FLICK_SAMPLEBUFFER 3
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// The number of samples to discard when calculating the flick velocity.
|
|
|
|
// Touch panels often produce inaccurate results as the finger is lifted.
|
|
|
|
#ifndef QML_FLICK_DISCARDSAMPLES
|
|
|
|
#define QML_FLICK_DISCARDSAMPLES 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// The default maximum velocity of a flick.
|
|
|
|
#ifndef QML_FLICK_DEFAULTMAXVELOCITY
|
|
|
|
#define QML_FLICK_DEFAULTMAXVELOCITY 2500
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// The default deceleration of a flick.
|
|
|
|
#ifndef QML_FLICK_DEFAULTDECELERATION
|
|
|
|
#define QML_FLICK_DEFAULTDECELERATION 1500
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// How much faster to decelerate when overshooting
|
|
|
|
#ifndef QML_FLICK_OVERSHOOTFRICTION
|
|
|
|
#define QML_FLICK_OVERSHOOTFRICTION 8
|
|
|
|
#endif
|
|
|
|
|
2012-01-30 23:12:13 +00:00
|
|
|
// Multiflick acceleration minimum flick velocity threshold
|
|
|
|
#ifndef QML_FLICK_MULTIFLICK_THRESHOLD
|
|
|
|
#define QML_FLICK_MULTIFLICK_THRESHOLD 1250
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Multiflick acceleration minimum contentSize/viewSize ratio
|
|
|
|
#ifndef QML_FLICK_MULTIFLICK_RATIO
|
|
|
|
#define QML_FLICK_MULTIFLICK_RATIO 10
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Multiflick acceleration maximum velocity multiplier
|
|
|
|
#ifndef QML_FLICK_MULTIFLICK_MAXBOOST
|
|
|
|
#define QML_FLICK_MULTIFLICK_MAXBOOST 3.0
|
|
|
|
#endif
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
// FlickThreshold determines how far the "mouse" must have moved
|
|
|
|
// before we perform a flick.
|
|
|
|
static const int FlickThreshold = 20;
|
|
|
|
|
|
|
|
// RetainGrabVelocity is the maxmimum instantaneous velocity that
|
|
|
|
// will ensure the Flickable retains the grab on consecutive flicks.
|
|
|
|
static const int RetainGrabVelocity = 15;
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickFlickableVisibleArea::QQuickFlickableVisibleArea(QQuickFlickable *parent)
|
2011-04-27 12:13:26 +00:00
|
|
|
: QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
|
|
|
|
, m_yPosition(0.), m_heightRatio(0.)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickableVisibleArea::widthRatio() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
return m_widthRatio;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickableVisibleArea::xPosition() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
return m_xPosition;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickableVisibleArea::heightRatio() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
return m_heightRatio;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickableVisibleArea::yPosition() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
return m_yPosition;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickableVisibleArea::updateVisible()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickFlickablePrivate *p = QQuickFlickablePrivate::get(flickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
bool changeX = false;
|
|
|
|
bool changeY = false;
|
|
|
|
bool changeWidth = false;
|
|
|
|
bool changeHeight = false;
|
|
|
|
|
|
|
|
// Vertical
|
|
|
|
const qreal viewheight = flickable->height();
|
|
|
|
const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent();
|
|
|
|
qreal pagePos = (-p->vData.move.value() + flickable->minYExtent()) / (maxyextent + viewheight);
|
|
|
|
qreal pageSize = viewheight / (maxyextent + viewheight);
|
|
|
|
|
|
|
|
if (pageSize != m_heightRatio) {
|
|
|
|
m_heightRatio = pageSize;
|
|
|
|
changeHeight = true;
|
|
|
|
}
|
|
|
|
if (pagePos != m_yPosition) {
|
|
|
|
m_yPosition = pagePos;
|
|
|
|
changeY = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Horizontal
|
|
|
|
const qreal viewwidth = flickable->width();
|
|
|
|
const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
|
|
|
|
pagePos = (-p->hData.move.value() + flickable->minXExtent()) / (maxxextent + viewwidth);
|
|
|
|
pageSize = viewwidth / (maxxextent + viewwidth);
|
|
|
|
|
|
|
|
if (pageSize != m_widthRatio) {
|
|
|
|
m_widthRatio = pageSize;
|
|
|
|
changeWidth = true;
|
|
|
|
}
|
|
|
|
if (pagePos != m_xPosition) {
|
|
|
|
m_xPosition = pagePos;
|
|
|
|
changeX = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changeX)
|
|
|
|
emit xPositionChanged(m_xPosition);
|
|
|
|
if (changeY)
|
|
|
|
emit yPositionChanged(m_yPosition);
|
|
|
|
if (changeWidth)
|
|
|
|
emit widthRatioChanged(m_widthRatio);
|
|
|
|
if (changeHeight)
|
|
|
|
emit heightRatioChanged(m_heightRatio);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickFlickablePrivate::QQuickFlickablePrivate()
|
|
|
|
: contentItem(new QQuickItem)
|
|
|
|
, hData(this, &QQuickFlickablePrivate::setViewportX)
|
|
|
|
, vData(this, &QQuickFlickablePrivate::setViewportY)
|
2011-04-27 12:13:26 +00:00
|
|
|
, hMoved(false), vMoved(false)
|
|
|
|
, stealMouse(false), pressed(false), interactive(true), calcVelocity(false)
|
2011-09-09 06:48:03 +00:00
|
|
|
, pixelAligned(false)
|
2011-11-29 14:24:27 +00:00
|
|
|
, lastPosTime(-1)
|
|
|
|
, lastPressTime(0)
|
2011-05-04 07:53:51 +00:00
|
|
|
, deceleration(QML_FLICK_DEFAULTDECELERATION)
|
|
|
|
, maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100)
|
|
|
|
, delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(400)
|
2012-01-30 23:12:13 +00:00
|
|
|
, flickBoost(1.0), fixupMode(Normal), vTime(0), visibleArea(0)
|
2011-10-14 08:51:42 +00:00
|
|
|
, flickableDirection(QQuickFlickable::AutoFlickDirection)
|
|
|
|
, boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::init()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
QDeclarative_setParent_noEvent(contentItem, q);
|
|
|
|
contentItem->setParentItem(q);
|
2011-09-22 03:14:00 +00:00
|
|
|
FAST_CONNECT(&timeline, SIGNAL(completed()), q, SLOT(movementEnding()))
|
2011-04-27 12:13:26 +00:00
|
|
|
q->setAcceptedMouseButtons(Qt::LeftButton);
|
|
|
|
q->setFiltersChildMouseEvents(true);
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickItemPrivate *viewportPrivate = QQuickItemPrivate::get(contentItem);
|
|
|
|
viewportPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Returns the amount to overshoot by given a velocity.
|
|
|
|
Will be roughly in range 0 - size/4
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickablePrivate::overShootDistance(qreal size)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
if (maxVelocity <= 0)
|
|
|
|
return 0.0;
|
|
|
|
|
2011-05-04 07:53:51 +00:00
|
|
|
return qMin(qreal(QML_FLICK_OVERSHOOT), size/3);
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity)
|
2011-05-04 07:53:51 +00:00
|
|
|
{
|
|
|
|
if (v > maxVelocity)
|
|
|
|
v = maxVelocity;
|
|
|
|
else if (v < -maxVelocity)
|
|
|
|
v = -maxVelocity;
|
|
|
|
velocityBuffer.append(v);
|
|
|
|
if (velocityBuffer.count() > QML_FLICK_SAMPLEBUFFER)
|
|
|
|
velocityBuffer.remove(0);
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::AxisData::updateVelocity()
|
2011-05-04 07:53:51 +00:00
|
|
|
{
|
2011-09-12 02:40:20 +00:00
|
|
|
velocity = 0;
|
2011-05-04 07:53:51 +00:00
|
|
|
if (velocityBuffer.count() > QML_FLICK_DISCARDSAMPLES) {
|
|
|
|
int count = velocityBuffer.count()-QML_FLICK_DISCARDSAMPLES;
|
|
|
|
for (int i = 0; i < count; ++i) {
|
|
|
|
qreal v = velocityBuffer.at(i);
|
|
|
|
velocity += v;
|
|
|
|
}
|
|
|
|
velocity /= count;
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeom, const QRectF &oldGeom)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (item == contentItem) {
|
2012-01-06 06:14:53 +00:00
|
|
|
bool xChanged = newGeom.x() != oldGeom.x();
|
|
|
|
bool yChanged = newGeom.y() != oldGeom.y();
|
|
|
|
if (xChanged || yChanged)
|
|
|
|
q->viewportMoved();
|
|
|
|
if (xChanged)
|
2011-04-27 12:13:26 +00:00
|
|
|
emit q->contentXChanged();
|
2012-01-06 06:14:53 +00:00
|
|
|
if (yChanged)
|
2011-04-27 12:13:26 +00:00
|
|
|
emit q->contentYChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::flickX(qreal velocity)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, velocity);
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::flickY(qreal velocity)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, velocity);
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal,
|
2011-04-27 12:13:26 +00:00
|
|
|
QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
|
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
qreal maxDistance = -1;
|
|
|
|
data.fixingUp = false;
|
|
|
|
// -ve velocity means list is moving up
|
|
|
|
if (velocity > 0) {
|
2011-05-04 07:53:51 +00:00
|
|
|
maxDistance = qAbs(minExtent - data.move.value());
|
2011-04-27 12:13:26 +00:00
|
|
|
data.flickTarget = minExtent;
|
|
|
|
} else {
|
2011-05-04 07:53:51 +00:00
|
|
|
maxDistance = qAbs(maxExtent - data.move.value());
|
2011-04-27 12:13:26 +00:00
|
|
|
data.flickTarget = maxExtent;
|
|
|
|
}
|
|
|
|
if (maxDistance > 0) {
|
|
|
|
qreal v = velocity;
|
|
|
|
if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
|
|
|
|
if (v < 0)
|
|
|
|
v = -maxVelocity;
|
|
|
|
else
|
|
|
|
v = maxVelocity;
|
|
|
|
}
|
|
|
|
timeline.reset(data.move);
|
2011-10-14 08:51:42 +00:00
|
|
|
if (boundsBehavior == QQuickFlickable::DragAndOvershootBounds)
|
2011-05-04 07:53:51 +00:00
|
|
|
timeline.accel(data.move, v, deceleration);
|
|
|
|
else
|
|
|
|
timeline.accel(data.move, v, deceleration, maxDistance);
|
2011-04-27 12:13:26 +00:00
|
|
|
timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!hData.flicking && q->xflick()) {
|
|
|
|
hData.flicking = true;
|
2011-04-27 12:13:26 +00:00
|
|
|
emit q->flickingChanged();
|
|
|
|
emit q->flickingHorizontallyChanged();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!vData.flicking)
|
2011-04-27 12:13:26 +00:00
|
|
|
emit q->flickStarted();
|
|
|
|
}
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!vData.flicking && q->yflick()) {
|
|
|
|
vData.flicking = true;
|
2011-04-27 12:13:26 +00:00
|
|
|
emit q->flickingChanged();
|
|
|
|
emit q->flickingVerticallyChanged();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!hData.flicking)
|
2011-04-27 12:13:26 +00:00
|
|
|
emit q->flickStarted();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
timeline.reset(data.move);
|
|
|
|
fixup(data, minExtent, maxExtent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::fixupY_callback(void *data)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
((QQuickFlickablePrivate *)data)->fixupY();
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::fixupX_callback(void *data)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
((QQuickFlickablePrivate *)data)->fixupX();
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::fixupX()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
fixup(hData, q->minXExtent(), q->maxXExtent());
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::fixupY()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
fixup(vData, q->minYExtent(), q->maxYExtent());
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
if (data.move.value() > minExtent || maxExtent > minExtent) {
|
|
|
|
timeline.reset(data.move);
|
|
|
|
if (data.move.value() != minExtent) {
|
|
|
|
switch (fixupMode) {
|
|
|
|
case Immediate:
|
|
|
|
timeline.set(data.move, minExtent);
|
|
|
|
break;
|
|
|
|
case ExtentChanged:
|
|
|
|
// The target has changed. Don't start from the beginning; just complete the
|
|
|
|
// second half of the animation using the new extent.
|
|
|
|
timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
|
|
|
|
data.fixingUp = true;
|
|
|
|
break;
|
|
|
|
default: {
|
|
|
|
qreal dist = minExtent - data.move;
|
|
|
|
timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
|
|
|
|
timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
|
|
|
|
data.fixingUp = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (data.move.value() < maxExtent) {
|
|
|
|
timeline.reset(data.move);
|
|
|
|
switch (fixupMode) {
|
|
|
|
case Immediate:
|
|
|
|
timeline.set(data.move, maxExtent);
|
|
|
|
break;
|
|
|
|
case ExtentChanged:
|
|
|
|
// The target has changed. Don't start from the beginning; just complete the
|
|
|
|
// second half of the animation using the new extent.
|
|
|
|
timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
|
|
|
|
data.fixingUp = true;
|
|
|
|
break;
|
|
|
|
default: {
|
|
|
|
qreal dist = maxExtent - data.move;
|
|
|
|
timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
|
|
|
|
timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
|
|
|
|
data.fixingUp = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-05-04 07:53:51 +00:00
|
|
|
data.inOvershoot = false;
|
2011-04-27 12:13:26 +00:00
|
|
|
fixupMode = Normal;
|
|
|
|
vTime = timeline.time();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::updateBeginningEnd()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
bool atBoundaryChange = false;
|
|
|
|
|
|
|
|
// Vertical
|
|
|
|
const int maxyextent = int(-q->maxYExtent());
|
|
|
|
const qreal ypos = -vData.move.value();
|
|
|
|
bool atBeginning = (ypos <= -q->minYExtent());
|
|
|
|
bool atEnd = (maxyextent <= ypos);
|
|
|
|
|
|
|
|
if (atBeginning != vData.atBeginning) {
|
|
|
|
vData.atBeginning = atBeginning;
|
|
|
|
atBoundaryChange = true;
|
|
|
|
}
|
|
|
|
if (atEnd != vData.atEnd) {
|
|
|
|
vData.atEnd = atEnd;
|
|
|
|
atBoundaryChange = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Horizontal
|
|
|
|
const int maxxextent = int(-q->maxXExtent());
|
|
|
|
const qreal xpos = -hData.move.value();
|
|
|
|
atBeginning = (xpos <= -q->minXExtent());
|
|
|
|
atEnd = (maxxextent <= xpos);
|
|
|
|
|
|
|
|
if (atBeginning != hData.atBeginning) {
|
|
|
|
hData.atBeginning = atBeginning;
|
|
|
|
atBoundaryChange = true;
|
|
|
|
}
|
|
|
|
if (atEnd != hData.atEnd) {
|
|
|
|
hData.atEnd = atEnd;
|
|
|
|
atBoundaryChange = true;
|
|
|
|
}
|
|
|
|
|
2011-09-23 06:13:51 +00:00
|
|
|
if (vData.extentsChanged) {
|
|
|
|
vData.extentsChanged = false;
|
|
|
|
emit q->yOriginChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hData.extentsChanged) {
|
|
|
|
hData.extentsChanged = false;
|
|
|
|
emit q->xOriginChanged();
|
|
|
|
}
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
if (atBoundaryChange)
|
|
|
|
emit q->isAtBoundaryChanged();
|
|
|
|
|
|
|
|
if (visibleArea)
|
|
|
|
visibleArea->updateVisible();
|
|
|
|
}
|
|
|
|
|
2011-07-28 00:49:37 +00:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
2011-10-14 08:51:42 +00:00
|
|
|
\qmlclass Flickable QQuickFlickable
|
2011-08-08 08:03:31 +00:00
|
|
|
\inqmlmodule QtQuick 2
|
|
|
|
\ingroup qml-basic-interaction-elements
|
|
|
|
|
|
|
|
\brief The Flickable item provides a surface that can be "flicked".
|
|
|
|
\inherits Item
|
|
|
|
|
|
|
|
The Flickable item places its children on a surface that can be dragged
|
|
|
|
and flicked, causing the view onto the child items to scroll. This
|
|
|
|
behavior forms the basis of Items that are designed to show large numbers
|
|
|
|
of child items, such as \l ListView and \l GridView.
|
|
|
|
|
|
|
|
In traditional user interfaces, views can be scrolled using standard
|
|
|
|
controls, such as scroll bars and arrow buttons. In some situations, it
|
|
|
|
is also possible to drag the view directly by pressing and holding a
|
|
|
|
mouse button while moving the cursor. In touch-based user interfaces,
|
|
|
|
this dragging action is often complemented with a flicking action, where
|
|
|
|
scrolling continues after the user has stopped touching the view.
|
|
|
|
|
|
|
|
Flickable does not automatically clip its contents. If it is not used as
|
|
|
|
a full-screen item, you should consider setting the \l{Item::}{clip} property
|
|
|
|
to true.
|
|
|
|
|
|
|
|
\section1 Example Usage
|
|
|
|
|
|
|
|
\div {class="float-right"}
|
|
|
|
\inlineimage flickable.gif
|
|
|
|
\enddiv
|
|
|
|
|
|
|
|
The following example shows a small view onto a large image in which the
|
|
|
|
user can drag or flick the image in order to view different parts of it.
|
|
|
|
|
|
|
|
\snippet doc/src/snippets/declarative/flickable.qml document
|
|
|
|
|
|
|
|
\clearfloat
|
|
|
|
|
|
|
|
Items declared as children of a Flickable are automatically parented to the
|
|
|
|
Flickable's \l contentItem. This should be taken into account when
|
|
|
|
operating on the children of the Flickable; it is usually the children of
|
|
|
|
\c contentItem that are relevant. For example, the bound of Items added
|
|
|
|
to the Flickable will be available by \c contentItem.childrenRect
|
|
|
|
|
|
|
|
\section1 Limitations
|
|
|
|
|
|
|
|
\note Due to an implementation detail, items placed inside a Flickable cannot anchor to it by
|
|
|
|
\c id. Use \c parent instead.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\qmlsignal QtQuick2::Flickable::onMovementStarted()
|
|
|
|
|
|
|
|
This handler is called when the view begins moving due to user
|
|
|
|
interaction.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\qmlsignal QtQuick2::Flickable::onMovementEnded()
|
|
|
|
|
|
|
|
This handler is called when the view stops moving due to user
|
|
|
|
interaction. If a flick was generated, this handler will
|
|
|
|
be triggered once the flick stops. If a flick was not
|
|
|
|
generated, the handler will be triggered when the
|
|
|
|
user stops dragging - i.e. a mouse or touch release.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\qmlsignal QtQuick2::Flickable::onFlickStarted()
|
|
|
|
|
|
|
|
This handler is called when the view is flicked. A flick
|
|
|
|
starts from the point that the mouse or touch is released,
|
|
|
|
while still in motion.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\qmlsignal QtQuick2::Flickable::onFlickEnded()
|
|
|
|
|
|
|
|
This handler is called when the view stops moving due to a flick.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\qmlproperty real QtQuick2::Flickable::visibleArea.xPosition
|
|
|
|
\qmlproperty real QtQuick2::Flickable::visibleArea.widthRatio
|
|
|
|
\qmlproperty real QtQuick2::Flickable::visibleArea.yPosition
|
|
|
|
\qmlproperty real QtQuick2::Flickable::visibleArea.heightRatio
|
|
|
|
|
|
|
|
These properties describe the position and size of the currently viewed area.
|
|
|
|
The size is defined as the percentage of the full view currently visible,
|
|
|
|
scaled to 0.0 - 1.0. The page position is usually in the range 0.0 (beginning) to
|
|
|
|
1.0 minus size ratio (end), i.e. \c yPosition is in the range 0.0 to 1.0-\c heightRatio.
|
|
|
|
However, it is possible for the contents to be dragged outside of the normal
|
|
|
|
range, resulting in the page positions also being outside the normal range.
|
|
|
|
|
|
|
|
These properties are typically used to draw a scrollbar. For example:
|
|
|
|
|
|
|
|
\snippet doc/src/snippets/declarative/flickableScrollbar.qml 0
|
|
|
|
\dots 8
|
|
|
|
\snippet doc/src/snippets/declarative/flickableScrollbar.qml 1
|
|
|
|
|
|
|
|
\sa {declarative/ui-components/scrollbar}{scrollbar example}
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickFlickable::QQuickFlickable(QQuickItem *parent)
|
|
|
|
: QQuickItem(*(new QQuickFlickablePrivate), parent)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
d->init();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickFlickable::QQuickFlickable(QQuickFlickablePrivate &dd, QQuickItem *parent)
|
|
|
|
: QQuickItem(dd, parent)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
d->init();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickFlickable::~QQuickFlickable()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty real QtQuick2::Flickable::contentX
|
|
|
|
\qmlproperty real QtQuick2::Flickable::contentY
|
|
|
|
|
|
|
|
These properties hold the surface coordinate currently at the top-left
|
|
|
|
corner of the Flickable. For example, if you flick an image up 100 pixels,
|
|
|
|
\c contentY will be 100.
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::contentX() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return -d->contentItem->x();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setContentX(qreal pos)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
d->hData.explicitValue = true;
|
2011-04-27 12:13:26 +00:00
|
|
|
d->timeline.reset(d->hData.move);
|
|
|
|
d->vTime = d->timeline.time();
|
|
|
|
movementXEnding();
|
2012-01-06 06:14:53 +00:00
|
|
|
if (-pos != d->hData.move.value())
|
2011-04-27 12:13:26 +00:00
|
|
|
d->hData.move.setValue(-pos);
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::contentY() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return -d->contentItem->y();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setContentY(qreal pos)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
d->vData.explicitValue = true;
|
2011-04-27 12:13:26 +00:00
|
|
|
d->timeline.reset(d->vData.move);
|
|
|
|
d->vTime = d->timeline.time();
|
|
|
|
movementYEnding();
|
2012-01-06 06:14:53 +00:00
|
|
|
if (-pos != d->vData.move.value())
|
2011-04-27 12:13:26 +00:00
|
|
|
d->vData.move.setValue(-pos);
|
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty bool QtQuick2::Flickable::interactive
|
|
|
|
|
|
|
|
This property describes whether the user can interact with the Flickable.
|
|
|
|
A user cannot drag or flick a Flickable that is not interactive.
|
|
|
|
|
|
|
|
By default, this property is true.
|
|
|
|
|
|
|
|
This property is useful for temporarily disabling flicking. This allows
|
|
|
|
special interaction with Flickable's children; for example, you might want
|
|
|
|
to freeze a flickable map while scrolling through a pop-up dialog that
|
|
|
|
is a child of the Flickable.
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isInteractive() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->interactive;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setInteractive(bool interactive)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (interactive != d->interactive) {
|
|
|
|
d->interactive = interactive;
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!interactive && (d->hData.flicking || d->vData.flicking)) {
|
2011-04-27 12:13:26 +00:00
|
|
|
d->timeline.clear();
|
|
|
|
d->vTime = d->timeline.time();
|
2011-09-26 03:13:02 +00:00
|
|
|
d->hData.flicking = false;
|
|
|
|
d->vData.flicking = false;
|
2011-04-27 12:13:26 +00:00
|
|
|
emit flickingChanged();
|
|
|
|
emit flickingHorizontallyChanged();
|
|
|
|
emit flickingVerticallyChanged();
|
|
|
|
emit flickEnded();
|
|
|
|
}
|
|
|
|
emit interactiveChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty real QtQuick2::Flickable::horizontalVelocity
|
|
|
|
\qmlproperty real QtQuick2::Flickable::verticalVelocity
|
|
|
|
|
|
|
|
The instantaneous velocity of movement along the x and y axes, in pixels/sec.
|
|
|
|
|
|
|
|
The reported velocity is smoothed to avoid erratic output.
|
2012-01-30 23:12:13 +00:00
|
|
|
|
|
|
|
Note that for views with a large content size (more than 10 times the view size),
|
|
|
|
the velocity of the flick may exceed the velocity of the touch in the case
|
|
|
|
of multiple quick consecutive flicks. This allows the user to flick faster
|
|
|
|
through large content.
|
2011-08-08 08:03:31 +00:00
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::horizontalVelocity() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->hData.smoothVelocity.value();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::verticalVelocity() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->vData.smoothVelocity.value();
|
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty bool QtQuick2::Flickable::atXBeginning
|
|
|
|
\qmlproperty bool QtQuick2::Flickable::atXEnd
|
|
|
|
\qmlproperty bool QtQuick2::Flickable::atYBeginning
|
|
|
|
\qmlproperty bool QtQuick2::Flickable::atYEnd
|
|
|
|
|
|
|
|
These properties are true if the flickable view is positioned at the beginning,
|
2011-11-04 05:32:58 +00:00
|
|
|
or end respectively.
|
2011-08-08 08:03:31 +00:00
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isAtXEnd() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->hData.atEnd;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isAtXBeginning() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->hData.atBeginning;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isAtYEnd() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->vData.atEnd;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isAtYBeginning() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->vData.atBeginning;
|
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty Item QtQuick2::Flickable::contentItem
|
|
|
|
|
|
|
|
The internal item that contains the Items to be moved in the Flickable.
|
|
|
|
|
|
|
|
Items declared as children of a Flickable are automatically parented to the Flickable's contentItem.
|
|
|
|
|
|
|
|
Items created dynamically need to be explicitly parented to the \e contentItem:
|
|
|
|
\code
|
|
|
|
Flickable {
|
|
|
|
id: myFlickable
|
|
|
|
function addItem(file) {
|
|
|
|
var component = Qt.createComponent(file)
|
|
|
|
component.createObject(myFlickable.contentItem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
\endcode
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickItem *QQuickFlickable::contentItem()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->contentItem;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickFlickableVisibleArea *QQuickFlickable::visibleArea()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (!d->visibleArea)
|
2011-10-14 08:51:42 +00:00
|
|
|
d->visibleArea = new QQuickFlickableVisibleArea(this);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->visibleArea;
|
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty enumeration QtQuick2::Flickable::flickableDirection
|
|
|
|
|
|
|
|
This property determines which directions the view can be flicked.
|
|
|
|
|
|
|
|
\list
|
|
|
|
\o Flickable.AutoFlickDirection (default) - allows flicking vertically if the
|
|
|
|
\e contentHeight is not equal to the \e height of the Flickable.
|
|
|
|
Allows flicking horizontally if the \e contentWidth is not equal
|
|
|
|
to the \e width of the Flickable.
|
|
|
|
\o Flickable.HorizontalFlick - allows flicking horizontally.
|
|
|
|
\o Flickable.VerticalFlick - allows flicking vertically.
|
|
|
|
\o Flickable.HorizontalAndVerticalFlick - allows flicking in both directions.
|
|
|
|
\endlist
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickFlickable::FlickableDirection QQuickFlickable::flickableDirection() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->flickableDirection;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setFlickableDirection(FlickableDirection direction)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (direction != d->flickableDirection) {
|
|
|
|
d->flickableDirection = direction;
|
|
|
|
emit flickableDirectionChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::pixelAligned() const
|
2011-09-09 06:48:03 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-09 06:48:03 +00:00
|
|
|
return d->pixelAligned;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setPixelAligned(bool align)
|
2011-09-09 06:48:03 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-09-09 06:48:03 +00:00
|
|
|
if (align != d->pixelAligned) {
|
|
|
|
d->pixelAligned = align;
|
|
|
|
emit pixelAlignedChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-29 14:24:27 +00:00
|
|
|
qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event)
|
|
|
|
{
|
|
|
|
if (0 != event->timestamp() && QQuickItemPrivate::consistentTime == -1)
|
|
|
|
return event->timestamp();
|
|
|
|
|
|
|
|
return QQuickItemPrivate::elapsed(timer);
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::handleMousePressEvent(QMouseEvent *event)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-11-29 14:24:27 +00:00
|
|
|
QQuickItemPrivate::start(timer);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (interactive && timeline.isActive()
|
|
|
|
&& (qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity
|
|
|
|
|| qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity)) {
|
|
|
|
stealMouse = true; // If we've been flicked then steal the click.
|
2012-01-30 23:12:13 +00:00
|
|
|
int flickTime = timeline.time();
|
|
|
|
if (flickTime > 600) {
|
|
|
|
// too long between flicks - cancel boost
|
|
|
|
hData.continuousFlickVelocity = 0;
|
|
|
|
vData.continuousFlickVelocity = 0;
|
|
|
|
flickBoost = 1.0;
|
|
|
|
} else {
|
|
|
|
hData.continuousFlickVelocity = -hData.smoothVelocity.value();
|
|
|
|
vData.continuousFlickVelocity = -vData.smoothVelocity.value();
|
|
|
|
if (flickTime > 300) // slower flicking - reduce boost
|
|
|
|
flickBoost = qMax(1.0, flickBoost - 0.5);
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
} else {
|
|
|
|
stealMouse = false;
|
2012-01-30 23:12:13 +00:00
|
|
|
hData.continuousFlickVelocity = 0;
|
|
|
|
vData.continuousFlickVelocity = 0;
|
|
|
|
flickBoost = 1.0;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
q->setKeepMouseGrab(stealMouse);
|
|
|
|
pressed = true;
|
|
|
|
timeline.clear();
|
2011-05-04 07:53:51 +00:00
|
|
|
hData.reset();
|
|
|
|
vData.reset();
|
2011-04-27 12:13:26 +00:00
|
|
|
hData.dragMinBound = q->minXExtent();
|
|
|
|
vData.dragMinBound = q->minYExtent();
|
|
|
|
hData.dragMaxBound = q->maxXExtent();
|
|
|
|
vData.dragMaxBound = q->maxYExtent();
|
2011-05-04 07:53:51 +00:00
|
|
|
fixupMode = Normal;
|
2011-11-25 05:22:09 +00:00
|
|
|
lastPos = QPointF();
|
2011-08-30 14:48:57 +00:00
|
|
|
pressPos = event->localPos();
|
2011-04-27 12:13:26 +00:00
|
|
|
hData.pressPos = hData.move.value();
|
|
|
|
vData.pressPos = vData.move.value();
|
2011-09-26 03:13:02 +00:00
|
|
|
hData.flicking = false;
|
|
|
|
vData.flicking = false;
|
2012-01-30 23:12:13 +00:00
|
|
|
lastPosTime = lastPressTime = computeCurrentTime(event);
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickItemPrivate::start(velocityTime);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-11-29 14:24:27 +00:00
|
|
|
if (!interactive || lastPosTime == -1)
|
2011-04-27 12:13:26 +00:00
|
|
|
return;
|
|
|
|
bool rejectY = false;
|
|
|
|
bool rejectX = false;
|
|
|
|
|
|
|
|
bool stealY = stealMouse;
|
|
|
|
bool stealX = stealMouse;
|
|
|
|
|
2011-11-29 14:24:27 +00:00
|
|
|
qint64 elapsed = computeCurrentTime(event) - lastPressTime;
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
if (q->yflick()) {
|
2011-11-25 05:22:09 +00:00
|
|
|
qreal dy = event->localPos().y() - pressPos.y();
|
2011-11-29 14:24:27 +00:00
|
|
|
if (qAbs(dy) > qApp->styleHints()->startDragDistance() || elapsed > 200) {
|
2011-04-27 12:13:26 +00:00
|
|
|
if (!vMoved)
|
|
|
|
vData.dragStartOffset = dy;
|
|
|
|
qreal newY = dy + vData.pressPos - vData.dragStartOffset;
|
|
|
|
const qreal minY = vData.dragMinBound;
|
|
|
|
const qreal maxY = vData.dragMaxBound;
|
|
|
|
if (newY > minY)
|
|
|
|
newY = minY + (newY - minY) / 2;
|
|
|
|
if (newY < maxY && maxY - minY <= 0)
|
|
|
|
newY = maxY + (newY - maxY) / 2;
|
2011-10-14 08:51:42 +00:00
|
|
|
if (boundsBehavior == QQuickFlickable::StopAtBounds && (newY > minY || newY < maxY)) {
|
2011-04-27 12:13:26 +00:00
|
|
|
rejectY = true;
|
|
|
|
if (newY < maxY) {
|
|
|
|
newY = maxY;
|
|
|
|
rejectY = false;
|
|
|
|
}
|
|
|
|
if (newY > minY) {
|
|
|
|
newY = minY;
|
|
|
|
rejectY = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!rejectY && stealMouse) {
|
|
|
|
vData.move.setValue(qRound(newY));
|
|
|
|
vMoved = true;
|
|
|
|
}
|
2011-08-30 11:17:00 +00:00
|
|
|
if (qAbs(dy) > qApp->styleHints()->startDragDistance())
|
2011-04-27 12:13:26 +00:00
|
|
|
stealY = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (q->xflick()) {
|
2011-11-25 05:22:09 +00:00
|
|
|
qreal dx = event->localPos().x() - pressPos.x();
|
2011-11-29 14:24:27 +00:00
|
|
|
if (qAbs(dx) > qApp->styleHints()->startDragDistance() || elapsed > 200) {
|
2011-04-27 12:13:26 +00:00
|
|
|
if (!hMoved)
|
|
|
|
hData.dragStartOffset = dx;
|
|
|
|
qreal newX = dx + hData.pressPos - hData.dragStartOffset;
|
|
|
|
const qreal minX = hData.dragMinBound;
|
|
|
|
const qreal maxX = hData.dragMaxBound;
|
|
|
|
if (newX > minX)
|
|
|
|
newX = minX + (newX - minX) / 2;
|
|
|
|
if (newX < maxX && maxX - minX <= 0)
|
|
|
|
newX = maxX + (newX - maxX) / 2;
|
2011-10-14 08:51:42 +00:00
|
|
|
if (boundsBehavior == QQuickFlickable::StopAtBounds && (newX > minX || newX < maxX)) {
|
2011-04-27 12:13:26 +00:00
|
|
|
rejectX = true;
|
|
|
|
if (newX < maxX) {
|
|
|
|
newX = maxX;
|
|
|
|
rejectX = false;
|
|
|
|
}
|
|
|
|
if (newX > minX) {
|
|
|
|
newX = minX;
|
|
|
|
rejectX = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!rejectX && stealMouse) {
|
|
|
|
hData.move.setValue(qRound(newX));
|
|
|
|
hMoved = true;
|
|
|
|
}
|
|
|
|
|
2011-08-30 11:17:00 +00:00
|
|
|
if (qAbs(dx) > qApp->styleHints()->startDragDistance())
|
2011-04-27 12:13:26 +00:00
|
|
|
stealX = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stealMouse = stealX || stealY;
|
|
|
|
if (stealMouse)
|
|
|
|
q->setKeepMouseGrab(true);
|
|
|
|
|
2011-05-04 07:53:51 +00:00
|
|
|
if (rejectY) {
|
|
|
|
vData.velocityBuffer.clear();
|
|
|
|
vData.velocity = 0;
|
|
|
|
}
|
|
|
|
if (rejectX) {
|
|
|
|
hData.velocityBuffer.clear();
|
|
|
|
hData.velocity = 0;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hMoved || vMoved) {
|
2011-07-28 00:49:37 +00:00
|
|
|
draggingStarting();
|
2011-04-27 12:13:26 +00:00
|
|
|
q->movementStarting();
|
|
|
|
}
|
|
|
|
|
2011-05-04 07:53:51 +00:00
|
|
|
if (!lastPos.isNull()) {
|
2011-11-29 14:24:27 +00:00
|
|
|
qint64 currentTimestamp = computeCurrentTime(event);
|
|
|
|
qreal elapsed = qreal(currentTimestamp - lastPosTime) / 1000.;
|
2011-05-04 07:53:51 +00:00
|
|
|
if (elapsed <= 0)
|
|
|
|
return;
|
2011-11-29 14:24:27 +00:00
|
|
|
lastPosTime = currentTimestamp;
|
2011-08-30 14:48:57 +00:00
|
|
|
qreal dy = event->localPos().y()-lastPos.y();
|
2011-05-04 07:53:51 +00:00
|
|
|
if (q->yflick() && !rejectY)
|
|
|
|
vData.addVelocitySample(dy/elapsed, maxVelocity);
|
2011-08-30 14:48:57 +00:00
|
|
|
qreal dx = event->localPos().x()-lastPos.x();
|
2011-05-04 07:53:51 +00:00
|
|
|
if (q->xflick() && !rejectX)
|
|
|
|
hData.addVelocitySample(dx/elapsed, maxVelocity);
|
|
|
|
}
|
|
|
|
|
2011-08-30 14:48:57 +00:00
|
|
|
lastPos = event->localPos();
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
stealMouse = false;
|
|
|
|
q->setKeepMouseGrab(false);
|
|
|
|
pressed = false;
|
|
|
|
|
2011-05-04 07:53:51 +00:00
|
|
|
// if we drag then pause before release we should not cause a flick.
|
2011-11-29 14:24:27 +00:00
|
|
|
qint64 elapsed = computeCurrentTime(event) - lastPosTime;
|
2011-10-17 11:03:58 +00:00
|
|
|
|
2011-09-26 03:13:02 +00:00
|
|
|
vData.updateVelocity();
|
|
|
|
hData.updateVelocity();
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2011-07-28 00:49:37 +00:00
|
|
|
draggingEnding();
|
|
|
|
|
2011-11-29 14:24:27 +00:00
|
|
|
if (lastPosTime == -1)
|
2011-07-28 00:49:37 +00:00
|
|
|
return;
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
vTime = timeline.time();
|
2011-05-04 07:53:51 +00:00
|
|
|
|
2012-01-30 23:12:13 +00:00
|
|
|
bool canBoost = false;
|
|
|
|
|
|
|
|
qreal vVelocity = elapsed < 100 ? vData.velocity : 0;
|
|
|
|
if (vData.atBeginning || vData.atEnd) {
|
|
|
|
vVelocity /= 2;
|
|
|
|
} else if (vData.continuousFlickVelocity != 0.0
|
|
|
|
&& vData.viewSize/q->height() > QML_FLICK_MULTIFLICK_RATIO
|
|
|
|
&& ((vVelocity > 0) == (vData.continuousFlickVelocity > 0))
|
|
|
|
&& qAbs(vVelocity) > QML_FLICK_MULTIFLICK_THRESHOLD) {
|
|
|
|
// accelerate flick for large view flicked quickly
|
|
|
|
canBoost = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal hVelocity = elapsed < 100 ? hData.velocity : 0;
|
|
|
|
if (hData.atBeginning || hData.atEnd) {
|
|
|
|
hVelocity /= 2;
|
|
|
|
} else if (hData.continuousFlickVelocity != 0.0
|
|
|
|
&& hData.viewSize/q->width() > QML_FLICK_MULTIFLICK_RATIO
|
|
|
|
&& ((hVelocity > 0) == (hData.continuousFlickVelocity > 0))
|
|
|
|
&& qAbs(hVelocity) > QML_FLICK_MULTIFLICK_THRESHOLD) {
|
|
|
|
// accelerate flick for large view flicked quickly
|
|
|
|
canBoost = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
flickBoost = canBoost ? qBound(1.0, flickBoost+0.25, QML_FLICK_MULTIFLICK_MAXBOOST) : 1.0;
|
|
|
|
|
|
|
|
vVelocity *= flickBoost;
|
|
|
|
if (q->yflick() && qAbs(vVelocity) > MinimumFlickVelocity && qAbs(event->localPos().y() - pressPos.y()) > FlickThreshold) {
|
2011-09-13 02:50:48 +00:00
|
|
|
velocityTimeline.reset(vData.smoothVelocity);
|
2012-01-30 23:12:13 +00:00
|
|
|
vData.smoothVelocity.setValue(-vVelocity);
|
|
|
|
flickY(vVelocity);
|
2011-09-13 02:50:48 +00:00
|
|
|
} else {
|
2011-04-27 12:13:26 +00:00
|
|
|
fixupY();
|
2011-09-13 02:50:48 +00:00
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2012-01-30 23:12:13 +00:00
|
|
|
hVelocity *= flickBoost;
|
|
|
|
if (q->xflick() && qAbs(hVelocity) > MinimumFlickVelocity && qAbs(event->localPos().x() - pressPos.x()) > FlickThreshold) {
|
2011-09-13 02:50:48 +00:00
|
|
|
velocityTimeline.reset(hData.smoothVelocity);
|
2012-01-30 23:12:13 +00:00
|
|
|
hData.smoothVelocity.setValue(-hVelocity);
|
|
|
|
flickX(hVelocity);
|
2011-09-13 02:50:48 +00:00
|
|
|
} else {
|
2011-04-27 12:13:26 +00:00
|
|
|
fixupX();
|
2011-09-13 02:50:48 +00:00
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
if (!timeline.isActive())
|
|
|
|
q->movementEnding();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::mousePressEvent(QMouseEvent *event)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (d->interactive) {
|
|
|
|
if (!d->pressed)
|
|
|
|
d->handleMousePressEvent(event);
|
|
|
|
event->accept();
|
|
|
|
} else {
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickItem::mousePressEvent(event);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::mouseMoveEvent(QMouseEvent *event)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (d->interactive) {
|
|
|
|
d->handleMouseMoveEvent(event);
|
|
|
|
event->accept();
|
|
|
|
} else {
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickItem::mouseMoveEvent(event);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (d->interactive) {
|
|
|
|
d->clearDelayedPress();
|
|
|
|
d->handleMouseReleaseEvent(event);
|
|
|
|
event->accept();
|
|
|
|
ungrabMouse();
|
|
|
|
} else {
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickItem::mouseReleaseEvent(event);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::wheelEvent(QWheelEvent *event)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (!d->interactive) {
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickItem::wheelEvent(event);
|
2011-04-27 12:13:26 +00:00
|
|
|
} else if (yflick() && event->orientation() == Qt::Vertical) {
|
2011-05-04 07:53:51 +00:00
|
|
|
bool valid = false;
|
|
|
|
if (event->delta() > 0 && contentY() > -minYExtent()) {
|
|
|
|
d->vData.velocity = qMax(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(d->maxVelocity/4));
|
|
|
|
valid = true;
|
|
|
|
} else if (event->delta() < 0 && contentY() < -maxYExtent()) {
|
|
|
|
d->vData.velocity = qMin(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
|
|
|
|
valid = true;
|
|
|
|
}
|
|
|
|
if (valid) {
|
2011-09-26 03:13:02 +00:00
|
|
|
d->vData.flicking = false;
|
2011-05-04 07:53:51 +00:00
|
|
|
d->flickY(d->vData.velocity);
|
2011-09-26 03:13:02 +00:00
|
|
|
if (d->vData.flicking) {
|
2011-05-04 07:53:51 +00:00
|
|
|
d->vMoved = true;
|
|
|
|
movementStarting();
|
|
|
|
}
|
|
|
|
event->accept();
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
} else if (xflick() && event->orientation() == Qt::Horizontal) {
|
2011-05-04 07:53:51 +00:00
|
|
|
bool valid = false;
|
|
|
|
if (event->delta() > 0 && contentX() > -minXExtent()) {
|
|
|
|
d->hData.velocity = qMax(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(d->maxVelocity/4));
|
|
|
|
valid = true;
|
|
|
|
} else if (event->delta() < 0 && contentX() < -maxXExtent()) {
|
|
|
|
d->hData.velocity = qMin(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
|
|
|
|
valid = true;
|
|
|
|
}
|
|
|
|
if (valid) {
|
2011-09-26 03:13:02 +00:00
|
|
|
d->hData.flicking = false;
|
2011-05-04 07:53:51 +00:00
|
|
|
d->flickX(d->hData.velocity);
|
2011-09-26 03:13:02 +00:00
|
|
|
if (d->hData.flicking) {
|
2011-05-04 07:53:51 +00:00
|
|
|
d->hMoved = true;
|
|
|
|
movementStarting();
|
|
|
|
}
|
|
|
|
event->accept();
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
} else {
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickItem::wheelEvent(event);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickablePrivate::isOutermostPressDelay() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(const QQuickFlickable);
|
|
|
|
QQuickItem *item = q->parentItem();
|
2011-04-27 12:13:26 +00:00
|
|
|
while (item) {
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickFlickable *flick = qobject_cast<QQuickFlickable*>(item);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (flick && flick->pressDelay() > 0 && flick->isInteractive())
|
|
|
|
return false;
|
|
|
|
item = item->parentItem();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::captureDelayedPress(QMouseEvent *event)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (!q->canvas() || pressDelay <= 0)
|
|
|
|
return;
|
|
|
|
if (!isOutermostPressDelay())
|
|
|
|
return;
|
|
|
|
delayedPressTarget = q->canvas()->mouseGrabberItem();
|
2011-08-30 14:48:57 +00:00
|
|
|
delayedPressEvent = new QMouseEvent(*event);
|
2011-04-27 12:13:26 +00:00
|
|
|
delayedPressEvent->setAccepted(false);
|
|
|
|
delayedPressTimer.start(pressDelay, q);
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::clearDelayedPress()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
if (delayedPressEvent) {
|
|
|
|
delayedPressTimer.stop();
|
|
|
|
delete delayedPressEvent;
|
|
|
|
delayedPressEvent = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-09 06:48:03 +00:00
|
|
|
//XXX pixelAligned ignores the global position of the Flickable, i.e. assumes Flickable itself is pixel aligned.
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::setViewportX(qreal x)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-09-09 06:48:03 +00:00
|
|
|
contentItem->setX(pixelAligned ? qRound(x) : x);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::setViewportY(qreal y)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-09-09 06:48:03 +00:00
|
|
|
contentItem->setY(pixelAligned ? qRound(y) : y);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::timerEvent(QTimerEvent *event)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (event->timerId() == d->delayedPressTimer.timerId()) {
|
|
|
|
d->delayedPressTimer.stop();
|
|
|
|
if (d->delayedPressEvent) {
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickItem *grabber = canvas() ? canvas()->mouseGrabberItem() : 0;
|
2011-04-27 12:13:26 +00:00
|
|
|
if (!grabber || grabber != this) {
|
|
|
|
// We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
|
|
|
|
// so we reset the grabber
|
|
|
|
if (canvas()->mouseGrabberItem() == d->delayedPressTarget)
|
|
|
|
d->delayedPressTarget->ungrabMouse();
|
|
|
|
// Use the event handler that will take care of finding the proper item to propagate the event
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickCanvasPrivate::get(canvas())->deliverMouseEvent(d->delayedPressEvent);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
delete d->delayedPressEvent;
|
|
|
|
d->delayedPressEvent = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::minYExtent() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
return d->vData.startMargin;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::minXExtent() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
return d->hData.startMargin;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* returns -ve */
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::maxXExtent() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
return width() - vWidth() - d->hData.endMargin;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
/* returns -ve */
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::maxYExtent() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
return height() - vHeight() - d->vData.endMargin;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::componentComplete()
|
2011-09-23 06:13:51 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
|
|
|
QQuickItem::componentComplete();
|
2011-09-23 06:13:51 +00:00
|
|
|
if (!d->hData.explicitValue && d->hData.startMargin != 0.)
|
|
|
|
setContentX(-minXExtent());
|
|
|
|
if (!d->vData.explicitValue && d->vData.startMargin != 0.)
|
|
|
|
setContentY(-minYExtent());
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::viewportMoved()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
qreal prevX = d->lastFlickablePosition.x();
|
|
|
|
qreal prevY = d->lastFlickablePosition.y();
|
|
|
|
if (d->pressed || d->calcVelocity) {
|
2011-10-14 08:51:42 +00:00
|
|
|
int elapsed = QQuickItemPrivate::restart(d->velocityTime);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (elapsed > 0) {
|
|
|
|
qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / elapsed;
|
2011-09-13 02:50:48 +00:00
|
|
|
if (qAbs(horizontalVelocity) > 0) {
|
|
|
|
d->velocityTimeline.reset(d->hData.smoothVelocity);
|
2011-12-01 01:48:59 +00:00
|
|
|
if (d->calcVelocity)
|
|
|
|
d->velocityTimeline.set(d->hData.smoothVelocity, horizontalVelocity);
|
|
|
|
else
|
|
|
|
d->velocityTimeline.move(d->hData.smoothVelocity, horizontalVelocity, d->reportedVelocitySmoothing);
|
2011-09-13 02:50:48 +00:00
|
|
|
d->velocityTimeline.move(d->hData.smoothVelocity, 0, d->reportedVelocitySmoothing);
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / elapsed;
|
2011-09-13 02:50:48 +00:00
|
|
|
if (qAbs(verticalVelocity) > 0) {
|
|
|
|
d->velocityTimeline.reset(d->vData.smoothVelocity);
|
2011-12-01 01:48:59 +00:00
|
|
|
if (d->calcVelocity)
|
|
|
|
d->velocityTimeline.set(d->vData.smoothVelocity, verticalVelocity);
|
|
|
|
else
|
|
|
|
d->velocityTimeline.move(d->vData.smoothVelocity, verticalVelocity, d->reportedVelocitySmoothing);
|
2011-09-13 02:50:48 +00:00
|
|
|
d->velocityTimeline.move(d->vData.smoothVelocity, 0, d->reportedVelocitySmoothing);
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (d->timeline.time() > d->vTime) {
|
2011-09-13 02:50:48 +00:00
|
|
|
d->velocityTimeline.clear();
|
2011-04-27 12:13:26 +00:00
|
|
|
qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
|
|
|
|
qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
|
|
|
|
d->hData.smoothVelocity.setValue(horizontalVelocity);
|
|
|
|
d->vData.smoothVelocity.setValue(verticalVelocity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->vData.inOvershoot && !d->vData.fixingUp && d->vData.flicking
|
2011-05-04 07:53:51 +00:00
|
|
|
&& (d->vData.move.value() > minYExtent() || d->vData.move.value() < maxYExtent())
|
|
|
|
&& qAbs(d->vData.smoothVelocity.value()) > 100) {
|
|
|
|
// Increase deceleration if we've passed a bound
|
|
|
|
d->vData.inOvershoot = true;
|
|
|
|
qreal maxDistance = d->overShootDistance(height());
|
|
|
|
d->timeline.reset(d->vData.move);
|
|
|
|
d->timeline.accel(d->vData.move, -d->vData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
|
|
|
|
d->timeline.callback(QDeclarativeTimeLineCallback(&d->vData.move, d->fixupY_callback, d));
|
|
|
|
}
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->hData.inOvershoot && !d->hData.fixingUp && d->hData.flicking
|
2011-05-04 07:53:51 +00:00
|
|
|
&& (d->hData.move.value() > minXExtent() || d->hData.move.value() < maxXExtent())
|
|
|
|
&& qAbs(d->hData.smoothVelocity.value()) > 100) {
|
|
|
|
// Increase deceleration if we've passed a bound
|
|
|
|
d->hData.inOvershoot = true;
|
|
|
|
qreal maxDistance = d->overShootDistance(width());
|
|
|
|
d->timeline.reset(d->hData.move);
|
|
|
|
d->timeline.accel(d->hData.move, -d->hData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
|
|
|
|
d->timeline.callback(QDeclarativeTimeLineCallback(&d->hData.move, d->fixupX_callback, d));
|
|
|
|
}
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
d->lastFlickablePosition = QPointF(d->hData.move.value(), d->vData.move.value());
|
|
|
|
|
|
|
|
d->vTime = d->timeline.time();
|
|
|
|
d->updateBeginningEnd();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::geometryChanged(const QRectF &newGeometry,
|
2011-04-27 12:13:26 +00:00
|
|
|
const QRectF &oldGeometry)
|
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
|
|
|
QQuickItem::geometryChanged(newGeometry, oldGeometry);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
bool changed = false;
|
|
|
|
if (newGeometry.width() != oldGeometry.width()) {
|
|
|
|
if (xflick())
|
|
|
|
changed = true;
|
|
|
|
if (d->hData.viewSize < 0) {
|
|
|
|
d->contentItem->setWidth(width());
|
|
|
|
emit contentWidthChanged();
|
|
|
|
}
|
|
|
|
// Make sure that we're entirely in view.
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->pressed && !d->hData.moving && !d->vData.moving) {
|
2011-10-14 08:51:42 +00:00
|
|
|
d->fixupMode = QQuickFlickablePrivate::Immediate;
|
2011-04-27 12:13:26 +00:00
|
|
|
d->fixupX();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (newGeometry.height() != oldGeometry.height()) {
|
|
|
|
if (yflick())
|
|
|
|
changed = true;
|
|
|
|
if (d->vData.viewSize < 0) {
|
|
|
|
d->contentItem->setHeight(height());
|
|
|
|
emit contentHeightChanged();
|
|
|
|
}
|
|
|
|
// Make sure that we're entirely in view.
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->pressed && !d->hData.moving && !d->vData.moving) {
|
2011-10-14 08:51:42 +00:00
|
|
|
d->fixupMode = QQuickFlickablePrivate::Immediate;
|
2011-04-27 12:13:26 +00:00
|
|
|
d->fixupY();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changed)
|
|
|
|
d->updateBeginningEnd();
|
|
|
|
}
|
|
|
|
|
2012-01-27 11:05:00 +00:00
|
|
|
/*!
|
|
|
|
\qmlmethod QtQuick2::Flickable::flick(qreal xVelocity, qreal yVelocity)
|
|
|
|
|
|
|
|
Flicks the content with \a xVelocity horizontally and \a yVelocity vertically in pixels/sec.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity)
|
|
|
|
{
|
|
|
|
Q_D(QQuickFlickable);
|
|
|
|
d->flickX(xVelocity);
|
|
|
|
d->flickY(yVelocity);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\qmlmethod QtQuick2::Flickable::cancelFlick()
|
|
|
|
|
|
|
|
Cancels the current flick animation.
|
|
|
|
*/
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::cancelFlick()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
d->timeline.reset(d->hData.move);
|
|
|
|
d->timeline.reset(d->vData.move);
|
|
|
|
movementEnding();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::data_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickItem *i = qobject_cast<QQuickItem *>(o);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (i) {
|
2011-10-14 08:51:42 +00:00
|
|
|
i->setParentItem(static_cast<QQuickFlickablePrivate*>(prop->data)->contentItem);
|
2011-04-27 12:13:26 +00:00
|
|
|
} else {
|
|
|
|
o->setParent(prop->object); // XXX todo - do we want this?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
int QQuickFlickablePrivate::data_count(QDeclarativeListProperty<QObject> *)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
// XXX todo
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
QObject *QQuickFlickablePrivate::data_at(QDeclarativeListProperty<QObject> *, int)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
// XXX todo
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::data_clear(QDeclarativeListProperty<QObject> *)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
// XXX todo
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
QDeclarativeListProperty<QObject> QQuickFlickable::flickableData()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
|
|
|
return QDeclarativeListProperty<QObject>(this, (void *)d, QQuickFlickablePrivate::data_append,
|
|
|
|
QQuickFlickablePrivate::data_count,
|
|
|
|
QQuickFlickablePrivate::data_at,
|
|
|
|
QQuickFlickablePrivate::data_clear);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
QDeclarativeListProperty<QQuickItem> QQuickFlickable::flickableChildren()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
|
|
|
return QQuickItemPrivate::get(d->contentItem)->children();
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty enumeration QtQuick2::Flickable::boundsBehavior
|
|
|
|
This property holds whether the surface may be dragged
|
2011-11-04 05:32:58 +00:00
|
|
|
beyond the Flickable's boundaries, or overshoot the
|
2011-08-08 08:03:31 +00:00
|
|
|
Flickable's boundaries when flicked.
|
|
|
|
|
|
|
|
This enables the feeling that the edges of the view are soft,
|
|
|
|
rather than a hard physical boundary.
|
|
|
|
|
|
|
|
The \c boundsBehavior can be one of:
|
|
|
|
|
|
|
|
\list
|
|
|
|
\o Flickable.StopAtBounds - the contents can not be dragged beyond the boundary
|
|
|
|
of the flickable, and flicks will not overshoot.
|
|
|
|
\o Flickable.DragOverBounds - the contents can be dragged beyond the boundary
|
|
|
|
of the Flickable, but flicks will not overshoot.
|
|
|
|
\o Flickable.DragAndOvershootBounds (default) - the contents can be dragged
|
|
|
|
beyond the boundary of the Flickable, and can overshoot the
|
|
|
|
boundary when flicked.
|
|
|
|
\endlist
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickFlickable::BoundsBehavior QQuickFlickable::boundsBehavior() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->boundsBehavior;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setBoundsBehavior(BoundsBehavior b)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (b == d->boundsBehavior)
|
|
|
|
return;
|
|
|
|
d->boundsBehavior = b;
|
|
|
|
emit boundsBehaviorChanged();
|
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty real QtQuick2::Flickable::contentWidth
|
|
|
|
\qmlproperty real QtQuick2::Flickable::contentHeight
|
|
|
|
|
|
|
|
The dimensions of the content (the surface controlled by Flickable).
|
|
|
|
This should typically be set to the combined size of the items placed in the
|
|
|
|
Flickable.
|
|
|
|
|
|
|
|
The following snippet shows how these properties are used to display
|
|
|
|
an image that is larger than the Flickable item itself:
|
|
|
|
|
|
|
|
\snippet doc/src/snippets/declarative/flickable.qml document
|
|
|
|
|
|
|
|
In some cases, the the content dimensions can be automatically set
|
|
|
|
using the \l {Item::childrenRect.width}{childrenRect.width}
|
|
|
|
and \l {Item::childrenRect.height}{childrenRect.height} properties.
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::contentWidth() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->hData.viewSize;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setContentWidth(qreal w)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (d->hData.viewSize == w)
|
|
|
|
return;
|
|
|
|
d->hData.viewSize = w;
|
|
|
|
if (w < 0)
|
|
|
|
d->contentItem->setWidth(width());
|
|
|
|
else
|
|
|
|
d->contentItem->setWidth(w);
|
2011-09-23 06:13:51 +00:00
|
|
|
d->hData.markExtentsDirty();
|
2011-04-27 12:13:26 +00:00
|
|
|
// Make sure that we're entirely in view.
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->pressed && !d->hData.moving && !d->vData.moving) {
|
2011-10-14 08:51:42 +00:00
|
|
|
d->fixupMode = QQuickFlickablePrivate::Immediate;
|
2011-04-27 12:13:26 +00:00
|
|
|
d->fixupX();
|
|
|
|
} else if (!d->pressed && d->hData.fixingUp) {
|
2011-10-14 08:51:42 +00:00
|
|
|
d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
|
2011-04-27 12:13:26 +00:00
|
|
|
d->fixupX();
|
|
|
|
}
|
|
|
|
emit contentWidthChanged();
|
|
|
|
d->updateBeginningEnd();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::contentHeight() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->vData.viewSize;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setContentHeight(qreal h)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (d->vData.viewSize == h)
|
|
|
|
return;
|
|
|
|
d->vData.viewSize = h;
|
|
|
|
if (h < 0)
|
|
|
|
d->contentItem->setHeight(height());
|
|
|
|
else
|
|
|
|
d->contentItem->setHeight(h);
|
2011-09-23 06:13:51 +00:00
|
|
|
d->vData.markExtentsDirty();
|
2011-04-27 12:13:26 +00:00
|
|
|
// Make sure that we're entirely in view.
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->pressed && !d->hData.moving && !d->vData.moving) {
|
2011-10-14 08:51:42 +00:00
|
|
|
d->fixupMode = QQuickFlickablePrivate::Immediate;
|
2011-04-27 12:13:26 +00:00
|
|
|
d->fixupY();
|
|
|
|
} else if (!d->pressed && d->vData.fixingUp) {
|
2011-10-14 08:51:42 +00:00
|
|
|
d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
|
2011-04-27 12:13:26 +00:00
|
|
|
d->fixupY();
|
|
|
|
}
|
|
|
|
emit contentHeightChanged();
|
|
|
|
d->updateBeginningEnd();
|
|
|
|
}
|
|
|
|
|
2011-09-23 06:13:51 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty real QtQuick2::Flickable::topMargin
|
|
|
|
\qmlproperty real QtQuick2::Flickable::leftMargin
|
|
|
|
\qmlproperty real QtQuick2::Flickable::bottomMargin
|
|
|
|
\qmlproperty real QtQuick2::Flickable::rightMargin
|
|
|
|
|
|
|
|
These properties hold the margins around the content. This space is reserved
|
|
|
|
in addition to the contentWidth and contentHeight.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::topMargin() const
|
2011-09-23 06:13:51 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
return d->vData.startMargin;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setTopMargin(qreal m)
|
2011-09-23 06:13:51 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
if (d->vData.startMargin == m)
|
|
|
|
return;
|
|
|
|
d->vData.startMargin = m;
|
|
|
|
d->vData.markExtentsDirty();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->pressed && !d->hData.moving && !d->vData.moving) {
|
2011-10-14 08:51:42 +00:00
|
|
|
d->fixupMode = QQuickFlickablePrivate::Immediate;
|
2011-09-23 06:13:51 +00:00
|
|
|
d->fixupY();
|
|
|
|
}
|
|
|
|
emit topMarginChanged();
|
|
|
|
d->updateBeginningEnd();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::bottomMargin() const
|
2011-09-23 06:13:51 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
return d->vData.endMargin;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setBottomMargin(qreal m)
|
2011-09-23 06:13:51 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
if (d->vData.endMargin == m)
|
|
|
|
return;
|
|
|
|
d->vData.endMargin = m;
|
|
|
|
d->vData.markExtentsDirty();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->pressed && !d->hData.moving && !d->vData.moving) {
|
2011-10-14 08:51:42 +00:00
|
|
|
d->fixupMode = QQuickFlickablePrivate::Immediate;
|
2011-09-23 06:13:51 +00:00
|
|
|
d->fixupY();
|
|
|
|
}
|
|
|
|
emit bottomMarginChanged();
|
|
|
|
d->updateBeginningEnd();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::leftMargin() const
|
2011-09-23 06:13:51 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
return d->hData.startMargin;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setLeftMargin(qreal m)
|
2011-09-23 06:13:51 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
if (d->hData.startMargin == m)
|
|
|
|
return;
|
|
|
|
d->hData.startMargin = m;
|
|
|
|
d->hData.markExtentsDirty();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->pressed && !d->hData.moving && !d->vData.moving) {
|
2011-10-14 08:51:42 +00:00
|
|
|
d->fixupMode = QQuickFlickablePrivate::Immediate;
|
2011-09-23 06:13:51 +00:00
|
|
|
d->fixupX();
|
|
|
|
}
|
|
|
|
emit leftMarginChanged();
|
|
|
|
d->updateBeginningEnd();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::rightMargin() const
|
2011-09-23 06:13:51 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
return d->hData.endMargin;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setRightMargin(qreal m)
|
2011-09-23 06:13:51 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
if (d->hData.endMargin == m)
|
|
|
|
return;
|
|
|
|
d->hData.endMargin = m;
|
|
|
|
d->hData.markExtentsDirty();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->pressed && !d->hData.moving && !d->vData.moving) {
|
2011-10-14 08:51:42 +00:00
|
|
|
d->fixupMode = QQuickFlickablePrivate::Immediate;
|
2011-09-23 06:13:51 +00:00
|
|
|
d->fixupX();
|
|
|
|
}
|
|
|
|
emit rightMarginChanged();
|
|
|
|
d->updateBeginningEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\qmlproperty real QtQuick2::Flickable::xOrigin
|
|
|
|
\qmlproperty real QtQuick2::Flickable::yOrigin
|
|
|
|
|
|
|
|
These properties hold the origin of the content. This is usually (0,0), however
|
|
|
|
ListView and GridView may have an arbitrary origin due to delegate size variation,
|
|
|
|
or item insertion/removal outside the visible region.
|
|
|
|
*/
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::yOrigin() const
|
2011-09-23 06:13:51 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
return -minYExtent() + d->vData.startMargin;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::xOrigin() const
|
2011-09-23 06:13:51 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-23 06:13:51 +00:00
|
|
|
return -minXExtent() + d->hData.startMargin;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlmethod QtQuick2::Flickable::resizeContent(real width, real height, QPointF center)
|
|
|
|
|
|
|
|
Resizes the content to \a width x \a height about \a center.
|
|
|
|
|
|
|
|
This does not scale the contents of the Flickable - it only resizes the \l contentWidth
|
|
|
|
and \l contentHeight.
|
|
|
|
|
|
|
|
Resizing the content may result in the content being positioned outside
|
|
|
|
the bounds of the Flickable. Calling \l returnToBounds() will
|
|
|
|
move the content back within legal bounds.
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::resizeContent(qreal w, qreal h, QPointF center)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (w != d->hData.viewSize) {
|
|
|
|
qreal oldSize = d->hData.viewSize;
|
2011-05-04 07:53:51 +00:00
|
|
|
d->hData.viewSize = w;
|
|
|
|
d->contentItem->setWidth(w);
|
|
|
|
emit contentWidthChanged();
|
2011-04-27 12:13:26 +00:00
|
|
|
if (center.x() != 0) {
|
|
|
|
qreal pos = center.x() * w / oldSize;
|
|
|
|
setContentX(contentX() + pos - center.x());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (h != d->vData.viewSize) {
|
|
|
|
qreal oldSize = d->vData.viewSize;
|
2011-05-04 07:53:51 +00:00
|
|
|
d->vData.viewSize = h;
|
|
|
|
d->contentItem->setHeight(h);
|
|
|
|
emit contentHeightChanged();
|
2011-04-27 12:13:26 +00:00
|
|
|
if (center.y() != 0) {
|
|
|
|
qreal pos = center.y() * h / oldSize;
|
|
|
|
setContentY(contentY() + pos - center.y());
|
|
|
|
}
|
|
|
|
}
|
2011-05-04 07:53:51 +00:00
|
|
|
d->updateBeginningEnd();
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlmethod QtQuick2::Flickable::returnToBounds()
|
|
|
|
|
|
|
|
Ensures the content is within legal bounds.
|
|
|
|
|
|
|
|
This may be called to ensure that the content is within legal bounds
|
|
|
|
after manually positioning the content.
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::returnToBounds()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
d->fixupX();
|
|
|
|
d->fixupY();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::vWidth() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (d->hData.viewSize < 0)
|
|
|
|
return width();
|
|
|
|
else
|
|
|
|
return d->hData.viewSize;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::vHeight() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (d->vData.viewSize < 0)
|
|
|
|
return height();
|
|
|
|
else
|
|
|
|
return d->vData.viewSize;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::xflick() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
|
|
|
if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
|
2011-04-27 12:13:26 +00:00
|
|
|
return vWidth() != width();
|
2011-10-14 08:51:42 +00:00
|
|
|
return d->flickableDirection & QQuickFlickable::HorizontalFlick;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::yflick() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
|
|
|
if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
|
2011-04-27 12:13:26 +00:00
|
|
|
return vHeight() != height();
|
2011-10-14 08:51:42 +00:00
|
|
|
return d->flickableDirection & QQuickFlickable::VerticalFlick;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::mouseUngrabEvent()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (d->pressed) {
|
|
|
|
// if our mouse grab has been removed (probably by another Flickable),
|
|
|
|
// fix our state
|
|
|
|
d->pressed = false;
|
2011-07-28 00:49:37 +00:00
|
|
|
d->draggingEnding();
|
2011-04-27 12:13:26 +00:00
|
|
|
d->stealMouse = false;
|
|
|
|
setKeepMouseGrab(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::sendMouseEvent(QMouseEvent *event)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickCanvas *c = canvas();
|
|
|
|
QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
|
2011-05-04 07:53:51 +00:00
|
|
|
bool disabledItem = grabber && !grabber->isEnabled();
|
2011-04-27 12:13:26 +00:00
|
|
|
bool stealThisEvent = d->stealMouse;
|
2011-08-30 14:48:57 +00:00
|
|
|
if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
|
|
|
|
QMouseEvent mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(),
|
|
|
|
event->button(), event->buttons(), event->modifiers());
|
|
|
|
|
2011-11-29 14:24:27 +00:00
|
|
|
mouseEvent.setTimestamp(event->timestamp());
|
2011-04-27 12:13:26 +00:00
|
|
|
mouseEvent.setAccepted(false);
|
|
|
|
|
2011-10-17 11:03:58 +00:00
|
|
|
switch (mouseEvent.type()) {
|
2011-08-30 14:48:57 +00:00
|
|
|
case QEvent::MouseMove:
|
2011-04-27 12:13:26 +00:00
|
|
|
d->handleMouseMoveEvent(&mouseEvent);
|
|
|
|
break;
|
2011-08-30 14:48:57 +00:00
|
|
|
case QEvent::MouseButtonPress:
|
2011-04-27 12:13:26 +00:00
|
|
|
if (d->pressed) // we are already pressed - this is a delayed replay
|
|
|
|
return false;
|
|
|
|
|
|
|
|
d->handleMousePressEvent(&mouseEvent);
|
|
|
|
d->captureDelayedPress(event);
|
|
|
|
stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
|
|
|
|
break;
|
2011-08-30 14:48:57 +00:00
|
|
|
case QEvent::MouseButtonRelease:
|
2011-04-27 12:13:26 +00:00
|
|
|
if (d->delayedPressEvent) {
|
|
|
|
// We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
|
|
|
|
// so we reset the grabber
|
|
|
|
if (c->mouseGrabberItem() == d->delayedPressTarget)
|
|
|
|
d->delayedPressTarget->ungrabMouse();
|
|
|
|
//Use the event handler that will take care of finding the proper item to propagate the event
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickCanvasPrivate::get(canvas())->deliverMouseEvent(d->delayedPressEvent);
|
2011-04-27 12:13:26 +00:00
|
|
|
d->clearDelayedPress();
|
|
|
|
// We send the release
|
|
|
|
canvas()->sendEvent(c->mouseGrabberItem(), event);
|
|
|
|
// And the event has been consumed
|
|
|
|
d->stealMouse = false;
|
|
|
|
d->pressed = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
d->handleMouseReleaseEvent(&mouseEvent);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2011-10-14 08:51:42 +00:00
|
|
|
grabber = qobject_cast<QQuickItem*>(c->mouseGrabberItem());
|
2011-05-04 07:53:51 +00:00
|
|
|
if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || disabledItem) {
|
2011-04-27 12:13:26 +00:00
|
|
|
d->clearDelayedPress();
|
|
|
|
grabMouse();
|
|
|
|
}
|
|
|
|
|
2011-05-04 07:53:51 +00:00
|
|
|
return stealThisEvent || d->delayedPressEvent || disabledItem;
|
2011-11-29 14:24:27 +00:00
|
|
|
} else if (d->lastPosTime != -1) {
|
|
|
|
d->lastPosTime = -1;
|
2011-08-01 05:49:33 +00:00
|
|
|
returnToBounds();
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
2011-08-30 14:48:57 +00:00
|
|
|
if (event->type() == QEvent::MouseButtonRelease) {
|
2011-11-29 14:24:27 +00:00
|
|
|
d->lastPosTime = -1;
|
2011-04-27 12:13:26 +00:00
|
|
|
d->clearDelayedPress();
|
|
|
|
d->stealMouse = false;
|
|
|
|
d->pressed = false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-07-28 23:29:04 +00:00
|
|
|
if (!isVisible() || !d->interactive || !isEnabled())
|
2011-10-14 08:51:42 +00:00
|
|
|
return QQuickItem::childMouseEventFilter(i, e);
|
2011-04-27 12:13:26 +00:00
|
|
|
switch (e->type()) {
|
2011-08-30 14:48:57 +00:00
|
|
|
case QEvent::MouseButtonPress:
|
|
|
|
case QEvent::MouseMove:
|
|
|
|
case QEvent::MouseButtonRelease:
|
|
|
|
return sendMouseEvent(static_cast<QMouseEvent *>(e));
|
2011-04-27 12:13:26 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
return QQuickItem::childMouseEventFilter(i, e);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty real QtQuick2::Flickable::maximumFlickVelocity
|
|
|
|
This property holds the maximum velocity that the user can flick the view in pixels/second.
|
|
|
|
|
|
|
|
The default value is platform dependent.
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::maximumFlickVelocity() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->maxVelocity;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setMaximumFlickVelocity(qreal v)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (v == d->maxVelocity)
|
|
|
|
return;
|
|
|
|
d->maxVelocity = v;
|
|
|
|
emit maximumFlickVelocityChanged();
|
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty real QtQuick2::Flickable::flickDeceleration
|
|
|
|
This property holds the rate at which a flick will decelerate.
|
|
|
|
|
|
|
|
The default value is platform dependent.
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
qreal QQuickFlickable::flickDeceleration() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->deceleration;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setFlickDeceleration(qreal deceleration)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (deceleration == d->deceleration)
|
|
|
|
return;
|
|
|
|
d->deceleration = deceleration;
|
|
|
|
emit flickDecelerationChanged();
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isFlicking() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-26 03:13:02 +00:00
|
|
|
return d->hData.flicking || d->vData.flicking;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty bool QtQuick2::Flickable::flicking
|
|
|
|
\qmlproperty bool QtQuick2::Flickable::flickingHorizontally
|
|
|
|
\qmlproperty bool QtQuick2::Flickable::flickingVertically
|
|
|
|
|
|
|
|
These properties describe whether the view is currently moving horizontally,
|
|
|
|
vertically or in either direction, due to the user flicking the view.
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isFlickingHorizontally() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-26 03:13:02 +00:00
|
|
|
return d->hData.flicking;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isFlickingVertically() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-26 03:13:02 +00:00
|
|
|
return d->vData.flicking;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-07-28 00:49:37 +00:00
|
|
|
/*!
|
|
|
|
\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.
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isDragging() const
|
2011-07-28 00:49:37 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-07-28 00:49:37 +00:00
|
|
|
return d->hData.dragging || d->vData.dragging;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isDraggingHorizontally() const
|
2011-07-28 00:49:37 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-07-28 00:49:37 +00:00
|
|
|
return d->hData.dragging;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isDraggingVertically() const
|
2011-07-28 00:49:37 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-07-28 00:49:37 +00:00
|
|
|
return d->vData.dragging;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::draggingStarting()
|
2011-07-28 00:49:37 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-07-28 00:49:37 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::draggingEnding()
|
2011-07-28 00:49:37 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-07-28 00:49:37 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty int QtQuick2::Flickable::pressDelay
|
|
|
|
|
|
|
|
This property holds the time to delay (ms) delivering a press to
|
|
|
|
children of the Flickable. This can be useful where reacting
|
|
|
|
to a press before a flicking action has undesirable effects.
|
|
|
|
|
|
|
|
If the flickable is dragged/flicked before the delay times out
|
|
|
|
the press event will not be delivered. If the button is released
|
|
|
|
within the timeout, both the press and release will be delivered.
|
|
|
|
|
|
|
|
Note that for nested Flickables with pressDelay set, the pressDelay of
|
|
|
|
inner Flickables is overridden by the outermost Flickable.
|
|
|
|
*/
|
2011-10-14 08:51:42 +00:00
|
|
|
int QQuickFlickable::pressDelay() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
return d->pressDelay;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::setPressDelay(int delay)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (d->pressDelay == delay)
|
|
|
|
return;
|
|
|
|
d->pressDelay = delay;
|
|
|
|
emit pressDelayChanged();
|
|
|
|
}
|
|
|
|
|
2011-08-08 08:03:31 +00:00
|
|
|
/*!
|
|
|
|
\qmlproperty bool QtQuick2::Flickable::moving
|
|
|
|
\qmlproperty bool QtQuick2::Flickable::movingHorizontally
|
|
|
|
\qmlproperty bool QtQuick2::Flickable::movingVertically
|
|
|
|
|
|
|
|
These properties describe whether the view is currently moving horizontally,
|
|
|
|
vertically or in either direction, due to the user either dragging or
|
|
|
|
flicking the view.
|
|
|
|
*/
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isMoving() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-26 03:13:02 +00:00
|
|
|
return d->hData.moving || d->vData.moving;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isMovingHorizontally() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-26 03:13:02 +00:00
|
|
|
return d->hData.moving;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
bool QQuickFlickable::isMovingVertically() const
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(const QQuickFlickable);
|
2011-09-26 03:13:02 +00:00
|
|
|
return d->vData.moving;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::movementStarting()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-09-26 03:13:02 +00:00
|
|
|
if (d->hMoved && !d->hData.moving) {
|
|
|
|
d->hData.moving = true;
|
2011-04-27 12:13:26 +00:00
|
|
|
emit movingChanged();
|
|
|
|
emit movingHorizontallyChanged();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->vData.moving)
|
2011-04-27 12:13:26 +00:00
|
|
|
emit movementStarted();
|
|
|
|
}
|
2011-09-26 03:13:02 +00:00
|
|
|
else if (d->vMoved && !d->vData.moving) {
|
|
|
|
d->vData.moving = true;
|
2011-04-27 12:13:26 +00:00
|
|
|
emit movingChanged();
|
|
|
|
emit movingVerticallyChanged();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->hData.moving)
|
2011-04-27 12:13:26 +00:00
|
|
|
emit movementStarted();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::movementEnding()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
movementXEnding();
|
|
|
|
movementYEnding();
|
|
|
|
d->hData.smoothVelocity.setValue(0);
|
|
|
|
d->vData.smoothVelocity.setValue(0);
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::movementXEnding()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-09-26 03:13:02 +00:00
|
|
|
if (d->hData.flicking) {
|
|
|
|
d->hData.flicking = false;
|
2011-04-27 12:13:26 +00:00
|
|
|
emit flickingChanged();
|
|
|
|
emit flickingHorizontallyChanged();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->vData.flicking)
|
2011-04-27 12:13:26 +00:00
|
|
|
emit flickEnded();
|
|
|
|
}
|
|
|
|
if (!d->pressed && !d->stealMouse) {
|
2011-09-26 03:13:02 +00:00
|
|
|
if (d->hData.moving) {
|
|
|
|
d->hData.moving = false;
|
2011-04-27 12:13:26 +00:00
|
|
|
d->hMoved = false;
|
|
|
|
emit movingChanged();
|
|
|
|
emit movingHorizontallyChanged();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->vData.moving)
|
2011-04-27 12:13:26 +00:00
|
|
|
emit movementEnded();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
d->hData.fixingUp = false;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickable::movementYEnding()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_D(QQuickFlickable);
|
2011-09-26 03:13:02 +00:00
|
|
|
if (d->vData.flicking) {
|
|
|
|
d->vData.flicking = false;
|
2011-04-27 12:13:26 +00:00
|
|
|
emit flickingChanged();
|
|
|
|
emit flickingVerticallyChanged();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->hData.flicking)
|
2011-04-27 12:13:26 +00:00
|
|
|
emit flickEnded();
|
|
|
|
}
|
|
|
|
if (!d->pressed && !d->stealMouse) {
|
2011-09-26 03:13:02 +00:00
|
|
|
if (d->vData.moving) {
|
|
|
|
d->vData.moving = false;
|
2011-04-27 12:13:26 +00:00
|
|
|
d->vMoved = false;
|
|
|
|
emit movingChanged();
|
|
|
|
emit movingVerticallyChanged();
|
2011-09-26 03:13:02 +00:00
|
|
|
if (!d->hData.moving)
|
2011-04-27 12:13:26 +00:00
|
|
|
emit movementEnded();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
d->vData.fixingUp = false;
|
|
|
|
}
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
void QQuickFlickablePrivate::updateVelocity()
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_Q(QQuickFlickable);
|
2011-04-27 12:13:26 +00:00
|
|
|
emit q->horizontalVelocityChanged();
|
|
|
|
emit q->verticalVelocityChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
QT_END_NAMESPACE
|