1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "QtQuick1/private/qdeclarativeflickable_p.h"
43 #include "QtQuick1/private/qdeclarativeflickable_p_p.h"
44 #include <QtDeclarative/qdeclarativeinfo.h>
45 #include <QGraphicsSceneMouseEvent>
48 #include "qplatformdefs.h"
54 // The maximum number of pixels a flick can overshoot
55 #ifndef QML_FLICK_OVERSHOOT
56 #define QML_FLICK_OVERSHOOT 200
59 // The number of samples to use in calculating the velocity of a flick
60 #ifndef QML_FLICK_SAMPLEBUFFER
61 #define QML_FLICK_SAMPLEBUFFER 3
64 // The number of samples to discard when calculating the flick velocity.
65 // Touch panels often produce inaccurate results as the finger is lifted.
66 #ifndef QML_FLICK_DISCARDSAMPLES
67 #define QML_FLICK_DISCARDSAMPLES 1
70 // The default maximum velocity of a flick.
71 #ifndef QML_FLICK_DEFAULTMAXVELOCITY
72 #define QML_FLICK_DEFAULTMAXVELOCITY 2500
75 // The default deceleration of a flick.
76 #ifndef QML_FLICK_DEFAULTDECELERATION
77 #define QML_FLICK_DEFAULTDECELERATION 1750
80 // How much faster to decelerate when overshooting
81 #ifndef QML_FLICK_OVERSHOOTFRICTION
82 #define QML_FLICK_OVERSHOOTFRICTION 8
85 // FlickThreshold determines how far the "mouse" must have moved
86 // before we perform a flick.
87 static const int FlickThreshold = 20;
89 // RetainGrabVelocity is the maxmimum instantaneous velocity that
90 // will ensure the Flickable retains the grab on consecutive flicks.
91 static const int RetainGrabVelocity = 15;
93 QDeclarative1FlickableVisibleArea::QDeclarative1FlickableVisibleArea(QDeclarative1Flickable *parent)
94 : QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
95 , m_yPosition(0.), m_heightRatio(0.)
99 qreal QDeclarative1FlickableVisibleArea::widthRatio() const
104 qreal QDeclarative1FlickableVisibleArea::xPosition() const
109 qreal QDeclarative1FlickableVisibleArea::heightRatio() const
111 return m_heightRatio;
114 qreal QDeclarative1FlickableVisibleArea::yPosition() const
119 void QDeclarative1FlickableVisibleArea::updateVisible()
121 QDeclarative1FlickablePrivate *p = static_cast<QDeclarative1FlickablePrivate *>(QGraphicsItemPrivate::get(flickable));
123 bool changeX = false;
124 bool changeY = false;
125 bool changeWidth = false;
126 bool changeHeight = false;
129 const qreal viewheight = flickable->height();
130 const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent();
131 qreal pagePos = (-p->vData.move.value() + flickable->minYExtent()) / (maxyextent + viewheight);
132 qreal pageSize = viewheight / (maxyextent + viewheight);
134 if (pageSize != m_heightRatio) {
135 m_heightRatio = pageSize;
138 if (pagePos != m_yPosition) {
139 m_yPosition = pagePos;
144 const qreal viewwidth = flickable->width();
145 const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
146 pagePos = (-p->hData.move.value() + flickable->minXExtent()) / (maxxextent + viewwidth);
147 pageSize = viewwidth / (maxxextent + viewwidth);
149 if (pageSize != m_widthRatio) {
150 m_widthRatio = pageSize;
153 if (pagePos != m_xPosition) {
154 m_xPosition = pagePos;
159 emit xPositionChanged(m_xPosition);
161 emit yPositionChanged(m_yPosition);
163 emit widthRatioChanged(m_widthRatio);
165 emit heightRatioChanged(m_heightRatio);
169 QDeclarative1FlickablePrivate::QDeclarative1FlickablePrivate()
170 : contentItem(new QDeclarativeItem)
171 , hData(this, &QDeclarative1FlickablePrivate::setRoundedViewportX)
172 , vData(this, &QDeclarative1FlickablePrivate::setRoundedViewportY)
173 , flickingHorizontally(false), flickingVertically(false)
174 , hMoved(false), vMoved(false)
175 , movingHorizontally(false), movingVertically(false)
176 , stealMouse(false), pressed(false), interactive(true), calcVelocity(false)
177 , deceleration(QML_FLICK_DEFAULTDECELERATION)
178 , maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100)
179 , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(400)
180 , fixupMode(Normal), vTime(0), visibleArea(0)
181 , flickableDirection(QDeclarative1Flickable::AutoFlickDirection)
182 , boundsBehavior(QDeclarative1Flickable::DragAndOvershootBounds)
186 void QDeclarative1FlickablePrivate::init()
188 Q_Q(QDeclarative1Flickable);
189 QDeclarative_setParent_noEvent(contentItem, q);
190 contentItem->setParentItem(q);
191 static int timelineUpdatedIdx = -1;
192 static int timelineCompletedIdx = -1;
193 static int flickableTickedIdx = -1;
194 static int flickableMovementEndingIdx = -1;
195 if (timelineUpdatedIdx == -1) {
196 timelineUpdatedIdx = QDeclarative1TimeLine::staticMetaObject.indexOfSignal("updated()");
197 timelineCompletedIdx = QDeclarative1TimeLine::staticMetaObject.indexOfSignal("completed()");
198 flickableTickedIdx = QDeclarative1Flickable::staticMetaObject.indexOfSlot("ticked()");
199 flickableMovementEndingIdx = QDeclarative1Flickable::staticMetaObject.indexOfSlot("movementEnding()");
201 QMetaObject::connect(&timeline, timelineUpdatedIdx,
202 q, flickableTickedIdx, Qt::DirectConnection);
203 QMetaObject::connect(&timeline, timelineCompletedIdx,
204 q, flickableMovementEndingIdx, Qt::DirectConnection);
205 q->setAcceptedMouseButtons(Qt::LeftButton);
206 q->setFiltersChildEvents(true);
207 QDeclarativeItemPrivate *viewportPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(contentItem));
208 viewportPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
209 lastPosTime.invalidate();
213 Returns the amount to overshoot by given a view size.
214 Will be up to the lesser of 1/3 of the view size or QML_FLICK_OVERSHOOT
216 qreal QDeclarative1FlickablePrivate::overShootDistance(qreal size)
218 if (maxVelocity <= 0)
221 return qMin(qreal(QML_FLICK_OVERSHOOT), size/3);
224 void QDeclarative1FlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity)
228 else if (v < -maxVelocity)
230 velocityBuffer.append(v);
231 if (velocityBuffer.count() > QML_FLICK_SAMPLEBUFFER)
232 velocityBuffer.remove(0);
235 void QDeclarative1FlickablePrivate::AxisData::updateVelocity()
237 if (velocityBuffer.count() > QML_FLICK_DISCARDSAMPLES) {
239 int count = velocityBuffer.count()-QML_FLICK_DISCARDSAMPLES;
240 for (int i = 0; i < count; ++i) {
241 qreal v = velocityBuffer.at(i);
248 void QDeclarative1FlickablePrivate::itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeom, const QRectF &oldGeom)
250 Q_Q(QDeclarative1Flickable);
251 if (item == contentItem) {
252 if (newGeom.x() != oldGeom.x())
253 emit q->contentXChanged();
254 if (newGeom.y() != oldGeom.y())
255 emit q->contentYChanged();
259 void QDeclarative1FlickablePrivate::flickX(qreal velocity)
261 Q_Q(QDeclarative1Flickable);
262 flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, velocity);
265 void QDeclarative1FlickablePrivate::flickY(qreal velocity)
267 Q_Q(QDeclarative1Flickable);
268 flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, velocity);
271 void QDeclarative1FlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal,
272 QDeclarative1TimeLineCallback::Callback fixupCallback, qreal velocity)
274 Q_Q(QDeclarative1Flickable);
275 qreal maxDistance = -1;
276 data.fixingUp = false;
277 // -ve velocity means list is moving up
279 maxDistance = qAbs(minExtent - data.move.value());
280 data.flickTarget = minExtent;
282 maxDistance = qAbs(maxExtent - data.move.value());
283 data.flickTarget = maxExtent;
285 if (maxDistance > 0) {
287 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
293 timeline.reset(data.move);
294 if (boundsBehavior == QDeclarative1Flickable::DragAndOvershootBounds)
295 timeline.accel(data.move, v, deceleration);
297 timeline.accel(data.move, v, deceleration, maxDistance);
298 timeline.callback(QDeclarative1TimeLineCallback(&data.move, fixupCallback, this));
299 if (!flickingHorizontally && q->xflick()) {
300 flickingHorizontally = true;
301 emit q->flickingChanged();
302 emit q->flickingHorizontallyChanged();
303 if (!flickingVertically)
304 emit q->flickStarted();
306 if (!flickingVertically && q->yflick()) {
307 flickingVertically = true;
308 emit q->flickingChanged();
309 emit q->flickingVerticallyChanged();
310 if (!flickingHorizontally)
311 emit q->flickStarted();
314 timeline.reset(data.move);
315 fixup(data, minExtent, maxExtent);
319 void QDeclarative1FlickablePrivate::fixupY_callback(void *data)
321 ((QDeclarative1FlickablePrivate *)data)->fixupY();
324 void QDeclarative1FlickablePrivate::fixupX_callback(void *data)
326 ((QDeclarative1FlickablePrivate *)data)->fixupX();
329 void QDeclarative1FlickablePrivate::fixupX()
331 Q_Q(QDeclarative1Flickable);
332 fixup(hData, q->minXExtent(), q->maxXExtent());
335 void QDeclarative1FlickablePrivate::fixupY()
337 Q_Q(QDeclarative1Flickable);
338 fixup(vData, q->minYExtent(), q->maxYExtent());
341 void QDeclarative1FlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
343 if (data.move.value() > minExtent || maxExtent > minExtent) {
344 timeline.reset(data.move);
345 if (data.move.value() != minExtent) {
348 timeline.set(data.move, minExtent);
351 // The target has changed. Don't start from the beginning; just complete the
352 // second half of the animation using the new extent.
353 timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
354 data.fixingUp = true;
357 qreal dist = minExtent - data.move;
358 timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
359 timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
360 data.fixingUp = true;
364 } else if (data.move.value() < maxExtent) {
365 timeline.reset(data.move);
368 timeline.set(data.move, maxExtent);
371 // The target has changed. Don't start from the beginning; just complete the
372 // second half of the animation using the new extent.
373 timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
374 data.fixingUp = true;
377 qreal dist = maxExtent - data.move;
378 timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
379 timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
380 data.fixingUp = true;
384 data.inOvershoot = false;
386 vTime = timeline.time();
389 void QDeclarative1FlickablePrivate::updateBeginningEnd()
391 Q_Q(QDeclarative1Flickable);
392 bool atBoundaryChange = false;
395 const int maxyextent = int(-q->maxYExtent());
396 const qreal ypos = -vData.move.value();
397 bool atBeginning = (ypos <= -q->minYExtent());
398 bool atEnd = (maxyextent <= ypos);
400 if (atBeginning != vData.atBeginning) {
401 vData.atBeginning = atBeginning;
402 atBoundaryChange = true;
404 if (atEnd != vData.atEnd) {
406 atBoundaryChange = true;
410 const int maxxextent = int(-q->maxXExtent());
411 const qreal xpos = -hData.move.value();
412 atBeginning = (xpos <= -q->minXExtent());
413 atEnd = (maxxextent <= xpos);
415 if (atBeginning != hData.atBeginning) {
416 hData.atBeginning = atBeginning;
417 atBoundaryChange = true;
419 if (atEnd != hData.atEnd) {
421 atBoundaryChange = true;
424 if (atBoundaryChange)
425 emit q->isAtBoundaryChanged();
428 visibleArea->updateVisible();
432 \qmlclass Flickable QDeclarative1Flickable
433 \inqmlmodule QtQuick 1
435 \ingroup qml-basic-interaction-elements
437 \brief The Flickable item provides a surface that can be "flicked".
440 The Flickable item places its children on a surface that can be dragged
441 and flicked, causing the view onto the child items to scroll. This
442 behavior forms the basis of Items that are designed to show large numbers
443 of child items, such as \l ListView and \l GridView.
445 In traditional user interfaces, views can be scrolled using standard
446 controls, such as scroll bars and arrow buttons. In some situations, it
447 is also possible to drag the view directly by pressing and holding a
448 mouse button while moving the cursor. In touch-based user interfaces,
449 this dragging action is often complemented with a flicking action, where
450 scrolling continues after the user has stopped touching the view.
452 Flickable does not automatically clip its contents. If it is not used as
453 a full-screen item, you should consider setting the \l{Item::}{clip} property
456 \section1 Example Usage
458 \div {class="float-right"}
459 \inlineimage flickable.gif
462 The following example shows a small view onto a large image in which the
463 user can drag or flick the image in order to view different parts of it.
465 \snippet doc/src/snippets/declarative/flickable.qml document
469 Items declared as children of a Flickable are automatically parented to the
470 Flickable's \l contentItem. This should be taken into account when
471 operating on the children of the Flickable; it is usually the children of
472 \c contentItem that are relevant. For example, the bound of Items added
473 to the Flickable will be available by \c contentItem.childrenRect
475 \section1 Limitations
477 \note Due to an implementation detail, items placed inside a Flickable cannot anchor to it by
478 \c id. Use \c parent instead.
482 \qmlsignal QtQuick1::Flickable::onMovementStarted()
484 This handler is called when the view begins moving due to user
489 \qmlsignal QtQuick1::Flickable::onMovementEnded()
491 This handler is called when the view stops moving due to user
492 interaction. If a flick was generated, this handler will
493 be triggered once the flick stops. If a flick was not
494 generated, the handler will be triggered when the
495 user stops dragging - i.e. a mouse or touch release.
499 \qmlsignal QtQuick1::Flickable::onFlickStarted()
501 This handler is called when the view is flicked. A flick
502 starts from the point that the mouse or touch is released,
503 while still in motion.
507 \qmlsignal QtQuick1::Flickable::onFlickEnded()
509 This handler is called when the view stops moving due to a flick.
513 \qmlproperty real QtQuick1::Flickable::visibleArea.xPosition
514 \qmlproperty real QtQuick1::Flickable::visibleArea.widthRatio
515 \qmlproperty real QtQuick1::Flickable::visibleArea.yPosition
516 \qmlproperty real QtQuick1::Flickable::visibleArea.heightRatio
518 These properties describe the position and size of the currently viewed area.
519 The size is defined as the percentage of the full view currently visible,
520 scaled to 0.0 - 1.0. The page position is usually in the range 0.0 (beginning) to
521 1.0 minus size ratio (end), i.e. \c yPosition is in the range 0.0 to 1.0-\c heightRatio.
522 However, it is possible for the contents to be dragged outside of the normal
523 range, resulting in the page positions also being outside the normal range.
525 These properties are typically used to draw a scrollbar. For example:
527 \snippet doc/src/snippets/declarative/flickableScrollbar.qml 0
529 \snippet doc/src/snippets/declarative/flickableScrollbar.qml 1
531 \sa {declarative/ui-components/scrollbar}{scrollbar example}
534 QDeclarative1Flickable::QDeclarative1Flickable(QDeclarativeItem *parent)
535 : QDeclarativeItem(*(new QDeclarative1FlickablePrivate), parent)
537 Q_D(QDeclarative1Flickable);
541 QDeclarative1Flickable::QDeclarative1Flickable(QDeclarative1FlickablePrivate &dd, QDeclarativeItem *parent)
542 : QDeclarativeItem(dd, parent)
544 Q_D(QDeclarative1Flickable);
548 QDeclarative1Flickable::~QDeclarative1Flickable()
553 \qmlproperty real QtQuick1::Flickable::contentX
554 \qmlproperty real QtQuick1::Flickable::contentY
556 These properties hold the surface coordinate currently at the top-left
557 corner of the Flickable. For example, if you flick an image up 100 pixels,
558 \c contentY will be 100.
560 qreal QDeclarative1Flickable::contentX() const
562 Q_D(const QDeclarative1Flickable);
563 return -d->contentItem->x();
566 void QDeclarative1Flickable::setContentX(qreal pos)
568 Q_D(QDeclarative1Flickable);
569 d->timeline.reset(d->hData.move);
570 d->vTime = d->timeline.time();
572 if (-pos != d->hData.move.value()) {
573 d->hData.move.setValue(-pos);
578 qreal QDeclarative1Flickable::contentY() const
580 Q_D(const QDeclarative1Flickable);
581 return -d->contentItem->y();
584 void QDeclarative1Flickable::setContentY(qreal pos)
586 Q_D(QDeclarative1Flickable);
587 d->timeline.reset(d->vData.move);
588 d->vTime = d->timeline.time();
590 if (-pos != d->vData.move.value()) {
591 d->vData.move.setValue(-pos);
597 \qmlproperty bool QtQuick1::Flickable::interactive
599 This property describes whether the user can interact with the Flickable.
600 A user cannot drag or flick a Flickable that is not interactive.
602 By default, this property is true.
604 This property is useful for temporarily disabling flicking. This allows
605 special interaction with Flickable's children; for example, you might want
606 to freeze a flickable map while scrolling through a pop-up dialog that
607 is a child of the Flickable.
609 bool QDeclarative1Flickable::isInteractive() const
611 Q_D(const QDeclarative1Flickable);
612 return d->interactive;
615 void QDeclarative1Flickable::setInteractive(bool interactive)
617 Q_D(QDeclarative1Flickable);
618 if (interactive != d->interactive) {
619 d->interactive = interactive;
620 if (!interactive && (d->flickingHorizontally || d->flickingVertically)) {
622 d->vTime = d->timeline.time();
623 d->flickingHorizontally = false;
624 d->flickingVertically = false;
625 emit flickingChanged();
626 emit flickingHorizontallyChanged();
627 emit flickingVerticallyChanged();
630 emit interactiveChanged();
635 \qmlproperty real QtQuick1::Flickable::horizontalVelocity
636 \qmlproperty real QtQuick1::Flickable::verticalVelocity
638 The instantaneous velocity of movement along the x and y axes, in pixels/sec.
640 The reported velocity is smoothed to avoid erratic output.
642 qreal QDeclarative1Flickable::horizontalVelocity() const
644 Q_D(const QDeclarative1Flickable);
645 return d->hData.smoothVelocity.value();
648 qreal QDeclarative1Flickable::verticalVelocity() const
650 Q_D(const QDeclarative1Flickable);
651 return d->vData.smoothVelocity.value();
655 \qmlproperty bool QtQuick1::Flickable::atXBeginning
656 \qmlproperty bool QtQuick1::Flickable::atXEnd
657 \qmlproperty bool QtQuick1::Flickable::atYBeginning
658 \qmlproperty bool QtQuick1::Flickable::atYEnd
660 These properties are true if the flickable view is positioned at the beginning,
663 bool QDeclarative1Flickable::isAtXEnd() const
665 Q_D(const QDeclarative1Flickable);
666 return d->hData.atEnd;
669 bool QDeclarative1Flickable::isAtXBeginning() const
671 Q_D(const QDeclarative1Flickable);
672 return d->hData.atBeginning;
675 bool QDeclarative1Flickable::isAtYEnd() const
677 Q_D(const QDeclarative1Flickable);
678 return d->vData.atEnd;
681 bool QDeclarative1Flickable::isAtYBeginning() const
683 Q_D(const QDeclarative1Flickable);
684 return d->vData.atBeginning;
687 void QDeclarative1Flickable::ticked()
693 \qmlproperty Item QtQuick1::Flickable::contentItem
695 The internal item that contains the Items to be moved in the Flickable.
697 Items declared as children of a Flickable are automatically parented to the Flickable's contentItem.
699 Items created dynamically need to be explicitly parented to the \e contentItem:
703 function addItem(file) {
704 var component = Qt.createComponent(file)
705 component.createObject(myFlickable.contentItem);
710 QDeclarativeItem *QDeclarative1Flickable::contentItem()
712 Q_D(QDeclarative1Flickable);
713 return d->contentItem;
716 QDeclarative1FlickableVisibleArea *QDeclarative1Flickable::visibleArea()
718 Q_D(QDeclarative1Flickable);
720 d->visibleArea = new QDeclarative1FlickableVisibleArea(this);
721 return d->visibleArea;
725 \qmlproperty enumeration QtQuick1::Flickable::flickableDirection
727 This property determines which directions the view can be flicked.
730 \o Flickable.AutoFlickDirection (default) - allows flicking vertically if the
731 \e contentHeight is not equal to the \e height of the Flickable.
732 Allows flicking horizontally if the \e contentWidth is not equal
733 to the \e width of the Flickable.
734 \o Flickable.HorizontalFlick - allows flicking horizontally.
735 \o Flickable.VerticalFlick - allows flicking vertically.
736 \o Flickable.HorizontalAndVerticalFlick - allows flicking in both directions.
739 QDeclarative1Flickable::FlickableDirection QDeclarative1Flickable::flickableDirection() const
741 Q_D(const QDeclarative1Flickable);
742 return d->flickableDirection;
745 void QDeclarative1Flickable::setFlickableDirection(FlickableDirection direction)
747 Q_D(QDeclarative1Flickable);
748 if (direction != d->flickableDirection) {
749 d->flickableDirection = direction;
750 emit flickableDirectionChanged();
754 void QDeclarative1FlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
756 Q_Q(QDeclarative1Flickable);
757 if (interactive && timeline.isActive()
758 && (qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity || qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity))
759 stealMouse = true; // If we've been flicked then steal the click.
762 q->setKeepMouseGrab(stealMouse);
767 hData.dragMinBound = q->minXExtent();
768 vData.dragMinBound = q->minYExtent();
769 hData.dragMaxBound = q->maxXExtent();
770 vData.dragMaxBound = q->maxYExtent();
773 QDeclarativeItemPrivate::start(lastPosTime);
774 pressPos = event->pos();
775 hData.pressPos = hData.move.value();
776 vData.pressPos = vData.move.value();
777 flickingHorizontally = false;
778 flickingVertically = false;
779 QDeclarativeItemPrivate::start(pressTime);
780 QDeclarativeItemPrivate::start(velocityTime);
783 void QDeclarative1FlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
785 Q_Q(QDeclarative1Flickable);
786 if (!interactive || !lastPosTime.isValid())
788 bool rejectY = false;
789 bool rejectX = false;
791 bool stealY = stealMouse;
792 bool stealX = stealMouse;
795 int dy = int(event->pos().y() - pressPos.y());
796 if (qAbs(dy) > QApplication::startDragDistance() || QDeclarativeItemPrivate::elapsed(pressTime) > 200) {
798 vData.dragStartOffset = dy;
799 qreal newY = dy + vData.pressPos - vData.dragStartOffset;
800 const qreal minY = vData.dragMinBound;
801 const qreal maxY = vData.dragMaxBound;
803 newY = minY + (newY - minY) / 2;
804 if (newY < maxY && maxY - minY <= 0)
805 newY = maxY + (newY - maxY) / 2;
806 if (boundsBehavior == QDeclarative1Flickable::StopAtBounds && (newY > minY || newY < maxY)) {
817 if (!rejectY && stealMouse) {
818 vData.move.setValue(qRound(newY));
821 if (qAbs(dy) > QApplication::startDragDistance())
827 int dx = int(event->pos().x() - pressPos.x());
828 if (qAbs(dx) > QApplication::startDragDistance() || QDeclarativeItemPrivate::elapsed(pressTime) > 200) {
830 hData.dragStartOffset = dx;
831 qreal newX = dx + hData.pressPos - hData.dragStartOffset;
832 const qreal minX = hData.dragMinBound;
833 const qreal maxX = hData.dragMaxBound;
835 newX = minX + (newX - minX) / 2;
836 if (newX < maxX && maxX - minX <= 0)
837 newX = maxX + (newX - maxX) / 2;
838 if (boundsBehavior == QDeclarative1Flickable::StopAtBounds && (newX > minX || newX < maxX)) {
849 if (!rejectX && stealMouse) {
850 hData.move.setValue(qRound(newX));
854 if (qAbs(dx) > QApplication::startDragDistance())
859 stealMouse = stealX || stealY;
861 q->setKeepMouseGrab(true);
864 vData.velocityBuffer.clear();
868 hData.velocityBuffer.clear();
872 if (hMoved || vMoved) {
873 q->movementStarting();
877 if (!lastPos.isNull()) {
878 qreal elapsed = qreal(QDeclarativeItemPrivate::elapsed(lastPosTime)) / 1000.;
881 QDeclarativeItemPrivate::restart(lastPosTime);
882 qreal dy = event->pos().y()-lastPos.y();
883 if (q->yflick() && !rejectY)
884 vData.addVelocitySample(dy/elapsed, maxVelocity);
885 qreal dx = event->pos().x()-lastPos.x();
886 if (q->xflick() && !rejectX)
887 hData.addVelocitySample(dx/elapsed, maxVelocity);
890 lastPos = event->pos();
893 void QDeclarative1FlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
895 Q_Q(QDeclarative1Flickable);
897 q->setKeepMouseGrab(false);
899 if (!lastPosTime.isValid())
902 // if we drag then pause before release we should not cause a flick.
903 if (QDeclarativeItemPrivate::elapsed(lastPosTime) < 100) {
904 vData.updateVelocity();
905 hData.updateVelocity();
907 hData.velocity = 0.0;
908 vData.velocity = 0.0;
911 vTime = timeline.time();
913 qreal velocity = vData.velocity;
914 if (vData.atBeginning || vData.atEnd)
916 if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().y() - pressPos.y()) > FlickThreshold)
921 velocity = hData.velocity;
922 if (hData.atBeginning || hData.atEnd)
924 if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().x() - pressPos.x()) > FlickThreshold)
929 if (!timeline.isActive())
933 void QDeclarative1Flickable::mousePressEvent(QGraphicsSceneMouseEvent *event)
935 Q_D(QDeclarative1Flickable);
936 if (d->interactive) {
938 d->handleMousePressEvent(event);
941 QDeclarativeItem::mousePressEvent(event);
945 void QDeclarative1Flickable::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
947 Q_D(QDeclarative1Flickable);
948 if (d->interactive) {
949 d->handleMouseMoveEvent(event);
952 QDeclarativeItem::mouseMoveEvent(event);
956 void QDeclarative1Flickable::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
958 Q_D(QDeclarative1Flickable);
959 if (d->interactive) {
960 d->clearDelayedPress();
961 d->handleMouseReleaseEvent(event);
965 QDeclarativeItem::mouseReleaseEvent(event);
969 void QDeclarative1Flickable::wheelEvent(QGraphicsSceneWheelEvent *event)
971 Q_D(QDeclarative1Flickable);
972 if (!d->interactive) {
973 QDeclarativeItem::wheelEvent(event);
974 } else if (yflick() && event->orientation() == Qt::Vertical) {
976 if (event->delta() > 0 && contentY() > -minYExtent()) {
977 d->vData.velocity = qMax(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(d->maxVelocity/4));
979 } else if (event->delta() < 0 && contentY() < -maxYExtent()) {
980 d->vData.velocity = qMin(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
984 d->flickingVertically = false;
985 d->flickY(d->vData.velocity);
986 if (d->flickingVertically) {
992 } else if (xflick() && event->orientation() == Qt::Horizontal) {
994 if (event->delta() > 0 && contentX() > -minXExtent()) {
995 d->hData.velocity = qMax(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(d->maxVelocity/4));
997 } else if (event->delta() < 0 && contentX() < -maxXExtent()) {
998 d->hData.velocity = qMin(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
1002 d->flickingHorizontally = false;
1003 d->flickX(d->hData.velocity);
1004 if (d->flickingHorizontally) {
1011 QDeclarativeItem::wheelEvent(event);
1015 bool QDeclarative1FlickablePrivate::isOutermostPressDelay() const
1017 Q_Q(const QDeclarative1Flickable);
1018 QDeclarativeItem *item = q->parentItem();
1020 QDeclarative1Flickable *flick = qobject_cast<QDeclarative1Flickable*>(item);
1021 if (flick && flick->pressDelay() > 0 && flick->isInteractive())
1023 item = item->parentItem();
1029 void QDeclarative1FlickablePrivate::captureDelayedPress(QGraphicsSceneMouseEvent *event)
1031 Q_Q(QDeclarative1Flickable);
1032 if (!q->scene() || pressDelay <= 0)
1034 if (!isOutermostPressDelay())
1036 delayedPressTarget = q->scene()->mouseGrabberItem();
1037 delayedPressEvent = new QGraphicsSceneMouseEvent(event->type());
1038 delayedPressEvent->setAccepted(false);
1039 for (int i = 0x1; i <= 0x10; i <<= 1) {
1040 if (event->buttons() & i) {
1041 Qt::MouseButton button = Qt::MouseButton(i);
1042 delayedPressEvent->setButtonDownPos(button, event->buttonDownPos(button));
1043 delayedPressEvent->setButtonDownScenePos(button, event->buttonDownScenePos(button));
1044 delayedPressEvent->setButtonDownScreenPos(button, event->buttonDownScreenPos(button));
1047 delayedPressEvent->setButtons(event->buttons());
1048 delayedPressEvent->setButton(event->button());
1049 delayedPressEvent->setPos(event->pos());
1050 delayedPressEvent->setScenePos(event->scenePos());
1051 delayedPressEvent->setScreenPos(event->screenPos());
1052 delayedPressEvent->setLastPos(event->lastPos());
1053 delayedPressEvent->setLastScenePos(event->lastScenePos());
1054 delayedPressEvent->setLastScreenPos(event->lastScreenPos());
1055 delayedPressEvent->setModifiers(event->modifiers());
1056 delayedPressTimer.start(pressDelay, q);
1059 void QDeclarative1FlickablePrivate::clearDelayedPress()
1061 if (delayedPressEvent) {
1062 delayedPressTimer.stop();
1063 delete delayedPressEvent;
1064 delayedPressEvent = 0;
1068 void QDeclarative1FlickablePrivate::setRoundedViewportX(qreal x)
1070 contentItem->setX(qRound(x));
1073 void QDeclarative1FlickablePrivate::setRoundedViewportY(qreal y)
1075 contentItem->setY(qRound(y));
1078 void QDeclarative1Flickable::timerEvent(QTimerEvent *event)
1080 Q_D(QDeclarative1Flickable);
1081 if (event->timerId() == d->delayedPressTimer.timerId()) {
1082 d->delayedPressTimer.stop();
1083 if (d->delayedPressEvent) {
1084 QDeclarativeItem *grabber = scene() ? qobject_cast<QDeclarativeItem*>(scene()->mouseGrabberItem()) : 0;
1085 if (!grabber || grabber != this) {
1086 // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
1087 // so we reset the grabber
1088 if (scene()->mouseGrabberItem() == d->delayedPressTarget)
1089 d->delayedPressTarget->ungrabMouse();
1090 //Use the event handler that will take care of finding the proper item to propagate the event
1091 QApplication::postEvent(scene(), d->delayedPressEvent);
1093 delete d->delayedPressEvent;
1095 d->delayedPressEvent = 0;
1100 qreal QDeclarative1Flickable::minYExtent() const
1105 qreal QDeclarative1Flickable::minXExtent() const
1111 qreal QDeclarative1Flickable::maxXExtent() const
1113 return width() - vWidth();
1116 qreal QDeclarative1Flickable::maxYExtent() const
1118 return height() - vHeight();
1121 void QDeclarative1Flickable::viewportMoved()
1123 Q_D(QDeclarative1Flickable);
1125 qreal prevX = d->lastFlickablePosition.x();
1126 qreal prevY = d->lastFlickablePosition.y();
1127 d->velocityTimeline.clear();
1128 if (d->pressed || d->calcVelocity) {
1129 int elapsed = QDeclarativeItemPrivate::restart(d->velocityTime);
1131 qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / elapsed;
1132 qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / elapsed;
1133 d->velocityTimeline.move(d->hData.smoothVelocity, horizontalVelocity, d->reportedVelocitySmoothing);
1134 d->velocityTimeline.move(d->hData.smoothVelocity, 0, d->reportedVelocitySmoothing);
1135 d->velocityTimeline.move(d->vData.smoothVelocity, verticalVelocity, d->reportedVelocitySmoothing);
1136 d->velocityTimeline.move(d->vData.smoothVelocity, 0, d->reportedVelocitySmoothing);
1139 if (d->timeline.time() > d->vTime) {
1140 qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
1141 qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
1142 d->hData.smoothVelocity.setValue(horizontalVelocity);
1143 d->vData.smoothVelocity.setValue(verticalVelocity);
1147 if (!d->vData.inOvershoot && !d->vData.fixingUp && d->flickingVertically
1148 && (d->vData.move.value() > minYExtent() || d->vData.move.value() < maxYExtent())
1149 && qAbs(d->vData.smoothVelocity.value()) > 100) {
1150 // Increase deceleration if we've passed a bound
1151 d->vData.inOvershoot = true;
1152 qreal maxDistance = d->overShootDistance(height());
1153 d->timeline.reset(d->vData.move);
1154 d->timeline.accel(d->vData.move, -d->vData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
1155 d->timeline.callback(QDeclarative1TimeLineCallback(&d->vData.move, d->fixupY_callback, d));
1157 if (!d->hData.inOvershoot && !d->hData.fixingUp && d->flickingHorizontally
1158 && (d->hData.move.value() > minXExtent() || d->hData.move.value() < maxXExtent())
1159 && qAbs(d->hData.smoothVelocity.value()) > 100) {
1160 // Increase deceleration if we've passed a bound
1161 d->hData.inOvershoot = true;
1162 qreal maxDistance = d->overShootDistance(width());
1163 d->timeline.reset(d->hData.move);
1164 d->timeline.accel(d->hData.move, -d->hData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
1165 d->timeline.callback(QDeclarative1TimeLineCallback(&d->hData.move, d->fixupX_callback, d));
1168 d->lastFlickablePosition = QPointF(d->hData.move.value(), d->vData.move.value());
1170 d->vTime = d->timeline.time();
1171 d->updateBeginningEnd();
1174 void QDeclarative1Flickable::geometryChanged(const QRectF &newGeometry,
1175 const QRectF &oldGeometry)
1177 Q_D(QDeclarative1Flickable);
1178 QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
1180 bool changed = false;
1181 if (newGeometry.width() != oldGeometry.width()) {
1184 if (d->hData.viewSize < 0) {
1185 d->contentItem->setWidth(width());
1186 emit contentWidthChanged();
1188 // Make sure that we're entirely in view.
1189 if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
1190 d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
1194 if (newGeometry.height() != oldGeometry.height()) {
1197 if (d->vData.viewSize < 0) {
1198 d->contentItem->setHeight(height());
1199 emit contentHeightChanged();
1201 // Make sure that we're entirely in view.
1202 if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
1203 d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
1209 d->updateBeginningEnd();
1212 void QDeclarative1Flickable::cancelFlick()
1214 Q_D(QDeclarative1Flickable);
1215 d->timeline.reset(d->hData.move);
1216 d->timeline.reset(d->vData.move);
1220 void QDeclarative1FlickablePrivate::data_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
1222 QGraphicsObject *i = qobject_cast<QGraphicsObject *>(o);
1224 QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(i);
1225 if (static_cast<QDeclarativeItemPrivate*>(d)->componentComplete) {
1226 i->setParentItem(static_cast<QDeclarative1FlickablePrivate*>(prop->data)->contentItem);
1228 d->setParentItemHelper(static_cast<QDeclarative1FlickablePrivate*>(prop->data)->contentItem, 0, 0);
1231 o->setParent(prop->object);
1235 int QDeclarative1FlickablePrivate::data_count(QDeclarativeListProperty<QObject> *property)
1237 QDeclarativeItem *contentItem= static_cast<QDeclarative1FlickablePrivate*>(property->data)->contentItem;
1238 return contentItem->childItems().count() + contentItem->children().count();
1241 QObject *QDeclarative1FlickablePrivate::data_at(QDeclarativeListProperty<QObject> *property, int index)
1243 QDeclarativeItem *contentItem = static_cast<QDeclarative1FlickablePrivate*>(property->data)->contentItem;
1245 int childItemCount = contentItem->childItems().count();
1250 if (index < childItemCount) {
1251 return contentItem->childItems().at(index)->toGraphicsObject();
1253 return contentItem->children().at(index - childItemCount);
1259 void QDeclarative1FlickablePrivate::data_clear(QDeclarativeListProperty<QObject> *property)
1261 QDeclarativeItem *contentItem = static_cast<QDeclarative1FlickablePrivate*>(property->data)->contentItem;
1263 const QList<QGraphicsItem*> graphicsItems = contentItem->childItems();
1264 for (int i = 0; i < graphicsItems.count(); i++)
1265 contentItem->scene()->removeItem(graphicsItems[i]);
1267 const QList<QObject*> objects = contentItem->children();
1268 for (int i = 0; i < objects.count(); i++)
1269 objects[i]->setParent(0);
1272 QDeclarativeListProperty<QObject> QDeclarative1Flickable::flickableData()
1274 Q_D(QDeclarative1Flickable);
1275 return QDeclarativeListProperty<QObject>(this, (void *)d, QDeclarative1FlickablePrivate::data_append,
1276 QDeclarative1FlickablePrivate::data_count,
1277 QDeclarative1FlickablePrivate::data_at,
1278 QDeclarative1FlickablePrivate::data_clear);
1281 QDeclarativeListProperty<QGraphicsObject> QDeclarative1Flickable::flickableChildren()
1283 Q_D(QDeclarative1Flickable);
1284 return QGraphicsItemPrivate::get(d->contentItem)->childrenList();
1288 \qmlproperty enumeration QtQuick1::Flickable::boundsBehavior
1289 This property holds whether the surface may be dragged
1290 beyond the Fickable's boundaries, or overshoot the
1291 Flickable's boundaries when flicked.
1293 This enables the feeling that the edges of the view are soft,
1294 rather than a hard physical boundary.
1296 The \c boundsBehavior can be one of:
1299 \o Flickable.StopAtBounds - the contents can not be dragged beyond the boundary
1300 of the flickable, and flicks will not overshoot.
1301 \o Flickable.DragOverBounds - the contents can be dragged beyond the boundary
1302 of the Flickable, but flicks will not overshoot.
1303 \o Flickable.DragAndOvershootBounds (default) - the contents can be dragged
1304 beyond the boundary of the Flickable, and can overshoot the
1305 boundary when flicked.
1308 QDeclarative1Flickable::BoundsBehavior QDeclarative1Flickable::boundsBehavior() const
1310 Q_D(const QDeclarative1Flickable);
1311 return d->boundsBehavior;
1314 void QDeclarative1Flickable::setBoundsBehavior(BoundsBehavior b)
1316 Q_D(QDeclarative1Flickable);
1317 if (b == d->boundsBehavior)
1319 d->boundsBehavior = b;
1320 emit boundsBehaviorChanged();
1324 \qmlproperty real QtQuick1::Flickable::contentWidth
1325 \qmlproperty real QtQuick1::Flickable::contentHeight
1327 The dimensions of the content (the surface controlled by Flickable).
1328 This should typically be set to the combined size of the items placed in the
1331 The following snippet shows how these properties are used to display
1332 an image that is larger than the Flickable item itself:
1334 \snippet doc/src/snippets/declarative/flickable.qml document
1336 In some cases, the the content dimensions can be automatically set
1337 using the \l {Item::childrenRect.width}{childrenRect.width}
1338 and \l {Item::childrenRect.height}{childrenRect.height} properties.
1340 qreal QDeclarative1Flickable::contentWidth() const
1342 Q_D(const QDeclarative1Flickable);
1343 return d->hData.viewSize;
1346 void QDeclarative1Flickable::setContentWidth(qreal w)
1348 Q_D(QDeclarative1Flickable);
1349 if (d->hData.viewSize == w)
1351 d->hData.viewSize = w;
1353 d->contentItem->setWidth(width());
1355 d->contentItem->setWidth(w);
1356 // Make sure that we're entirely in view.
1357 if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
1358 d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
1360 } else if (!d->pressed && d->hData.fixingUp) {
1361 d->fixupMode = QDeclarative1FlickablePrivate::ExtentChanged;
1364 emit contentWidthChanged();
1365 d->updateBeginningEnd();
1368 qreal QDeclarative1Flickable::contentHeight() const
1370 Q_D(const QDeclarative1Flickable);
1371 return d->vData.viewSize;
1374 void QDeclarative1Flickable::setContentHeight(qreal h)
1376 Q_D(QDeclarative1Flickable);
1377 if (d->vData.viewSize == h)
1379 d->vData.viewSize = h;
1381 d->contentItem->setHeight(height());
1383 d->contentItem->setHeight(h);
1384 // Make sure that we're entirely in view.
1385 if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
1386 d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
1388 } else if (!d->pressed && d->vData.fixingUp) {
1389 d->fixupMode = QDeclarative1FlickablePrivate::ExtentChanged;
1392 emit contentHeightChanged();
1393 d->updateBeginningEnd();
1397 \qmlmethod QtQuick1::Flickable::resizeContent(real width, real height, QPointF center)
1401 Resizes the content to \a width x \a height about \a center.
1403 This does not scale the contents of the Flickable - it only resizes the \l contentWidth
1404 and \l contentHeight.
1406 Resizing the content may result in the content being positioned outside
1407 the bounds of the Flickable. Calling \l returnToBounds() will
1408 move the content back within legal bounds.
1410 void QDeclarative1Flickable::resizeContent(qreal w, qreal h, QPointF center)
1412 Q_D(QDeclarative1Flickable);
1413 if (w != d->hData.viewSize) {
1414 qreal oldSize = d->hData.viewSize;
1415 d->hData.viewSize = w;
1416 d->contentItem->setWidth(w);
1417 emit contentWidthChanged();
1418 if (center.x() != 0) {
1419 qreal pos = center.x() * w / oldSize;
1420 setContentX(contentX() + pos - center.x());
1423 if (h != d->vData.viewSize) {
1424 qreal oldSize = d->vData.viewSize;
1425 d->vData.viewSize = h;
1426 d->contentItem->setHeight(h);
1427 emit contentHeightChanged();
1428 if (center.y() != 0) {
1429 qreal pos = center.y() * h / oldSize;
1430 setContentY(contentY() + pos - center.y());
1433 d->updateBeginningEnd();
1437 \qmlmethod QtQuick1::Flickable::returnToBounds()
1441 Ensures the content is within legal bounds.
1443 This may be called to ensure that the content is within legal bounds
1444 after manually positioning the content.
1446 void QDeclarative1Flickable::returnToBounds()
1448 Q_D(QDeclarative1Flickable);
1453 qreal QDeclarative1Flickable::vWidth() const
1455 Q_D(const QDeclarative1Flickable);
1456 if (d->hData.viewSize < 0)
1459 return d->hData.viewSize;
1462 qreal QDeclarative1Flickable::vHeight() const
1464 Q_D(const QDeclarative1Flickable);
1465 if (d->vData.viewSize < 0)
1468 return d->vData.viewSize;
1471 bool QDeclarative1Flickable::xflick() const
1473 Q_D(const QDeclarative1Flickable);
1474 if (d->flickableDirection == QDeclarative1Flickable::AutoFlickDirection)
1475 return vWidth() != width();
1476 return d->flickableDirection & QDeclarative1Flickable::HorizontalFlick;
1479 bool QDeclarative1Flickable::yflick() const
1481 Q_D(const QDeclarative1Flickable);
1482 if (d->flickableDirection == QDeclarative1Flickable::AutoFlickDirection)
1483 return vHeight() != height();
1484 return d->flickableDirection & QDeclarative1Flickable::VerticalFlick;
1487 bool QDeclarative1Flickable::sceneEvent(QEvent *event)
1489 bool rv = QDeclarativeItem::sceneEvent(event);
1490 if (event->type() == QEvent::UngrabMouse) {
1491 Q_D(QDeclarative1Flickable);
1493 // if our mouse grab has been removed (probably by another Flickable),
1496 d->stealMouse = false;
1497 setKeepMouseGrab(false);
1503 bool QDeclarative1Flickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
1505 Q_D(QDeclarative1Flickable);
1506 QGraphicsSceneMouseEvent mouseEvent(event->type());
1507 QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
1509 QGraphicsScene *s = scene();
1510 QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
1511 QGraphicsItem *grabberItem = s ? s->mouseGrabberItem() : 0;
1512 bool disabledItem = grabberItem && !grabberItem->isEnabled();
1513 bool stealThisEvent = d->stealMouse;
1514 if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
1515 mouseEvent.setAccepted(false);
1516 for (int i = 0x1; i <= 0x10; i <<= 1) {
1517 if (event->buttons() & i) {
1518 Qt::MouseButton button = Qt::MouseButton(i);
1519 mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
1522 mouseEvent.setScenePos(event->scenePos());
1523 mouseEvent.setLastScenePos(event->lastScenePos());
1524 mouseEvent.setPos(mapFromScene(event->scenePos()));
1525 mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
1527 switch(mouseEvent.type()) {
1528 case QEvent::GraphicsSceneMouseMove:
1529 d->handleMouseMoveEvent(&mouseEvent);
1531 case QEvent::GraphicsSceneMousePress:
1532 if (d->pressed) // we are already pressed - this is a delayed replay
1535 d->handleMousePressEvent(&mouseEvent);
1536 d->captureDelayedPress(event);
1537 stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
1539 case QEvent::GraphicsSceneMouseRelease:
1540 if (d->delayedPressEvent) {
1541 // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
1542 // so we reset the grabber
1543 if (s->mouseGrabberItem() == d->delayedPressTarget)
1544 d->delayedPressTarget->ungrabMouse();
1545 //Use the event handler that will take care of finding the proper item to propagate the event
1546 QApplication::sendEvent(scene(), d->delayedPressEvent);
1547 d->clearDelayedPress();
1548 // We send the release
1549 scene()->sendEvent(s->mouseGrabberItem(), event);
1550 // And the event has been consumed
1551 d->stealMouse = false;
1555 d->handleMouseReleaseEvent(&mouseEvent);
1560 grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
1561 if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || disabledItem) {
1562 d->clearDelayedPress();
1566 return stealThisEvent || d->delayedPressEvent || disabledItem;
1567 } else if (d->lastPosTime.isValid()) {
1568 d->lastPosTime.invalidate();
1570 if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
1571 d->clearDelayedPress();
1572 d->stealMouse = false;
1579 bool QDeclarative1Flickable::sceneEventFilter(QGraphicsItem *i, QEvent *e)
1581 Q_D(QDeclarative1Flickable);
1582 if (!isVisible() || !d->interactive || !isEnabled())
1583 return QDeclarativeItem::sceneEventFilter(i, e);
1584 switch (e->type()) {
1585 case QEvent::GraphicsSceneMousePress:
1586 case QEvent::GraphicsSceneMouseMove:
1587 case QEvent::GraphicsSceneMouseRelease:
1588 return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
1593 return QDeclarativeItem::sceneEventFilter(i, e);
1597 \qmlproperty real QtQuick1::Flickable::maximumFlickVelocity
1598 This property holds the maximum velocity that the user can flick the view in pixels/second.
1600 The default value is platform dependent.
1602 qreal QDeclarative1Flickable::maximumFlickVelocity() const
1604 Q_D(const QDeclarative1Flickable);
1605 return d->maxVelocity;
1608 void QDeclarative1Flickable::setMaximumFlickVelocity(qreal v)
1610 Q_D(QDeclarative1Flickable);
1611 if (v == d->maxVelocity)
1614 emit maximumFlickVelocityChanged();
1618 \qmlproperty real QtQuick1::Flickable::flickDeceleration
1619 This property holds the rate at which a flick will decelerate.
1621 The default value is platform dependent.
1623 qreal QDeclarative1Flickable::flickDeceleration() const
1625 Q_D(const QDeclarative1Flickable);
1626 return d->deceleration;
1629 void QDeclarative1Flickable::setFlickDeceleration(qreal deceleration)
1631 Q_D(QDeclarative1Flickable);
1632 if (deceleration == d->deceleration)
1634 d->deceleration = deceleration;
1635 emit flickDecelerationChanged();
1638 bool QDeclarative1Flickable::isFlicking() const
1640 Q_D(const QDeclarative1Flickable);
1641 return d->flickingHorizontally || d->flickingVertically;
1645 \qmlproperty bool QtQuick1::Flickable::flicking
1646 \qmlproperty bool QtQuick1::Flickable::flickingHorizontally
1647 \qmlproperty bool QtQuick1::Flickable::flickingVertically
1649 These properties describe whether the view is currently moving horizontally,
1650 vertically or in either direction, due to the user flicking the view.
1652 bool QDeclarative1Flickable::isFlickingHorizontally() const
1654 Q_D(const QDeclarative1Flickable);
1655 return d->flickingHorizontally;
1658 bool QDeclarative1Flickable::isFlickingVertically() const
1660 Q_D(const QDeclarative1Flickable);
1661 return d->flickingVertically;
1665 \qmlproperty int QtQuick1::Flickable::pressDelay
1667 This property holds the time to delay (ms) delivering a press to
1668 children of the Flickable. This can be useful where reacting
1669 to a press before a flicking action has undesirable effects.
1671 If the flickable is dragged/flicked before the delay times out
1672 the press event will not be delivered. If the button is released
1673 within the timeout, both the press and release will be delivered.
1675 Note that for nested Flickables with pressDelay set, the pressDelay of
1676 inner Flickables is overridden by the outermost Flickable.
1678 int QDeclarative1Flickable::pressDelay() const
1680 Q_D(const QDeclarative1Flickable);
1681 return d->pressDelay;
1684 void QDeclarative1Flickable::setPressDelay(int delay)
1686 Q_D(QDeclarative1Flickable);
1687 if (d->pressDelay == delay)
1689 d->pressDelay = delay;
1690 emit pressDelayChanged();
1694 bool QDeclarative1Flickable::isMoving() const
1696 Q_D(const QDeclarative1Flickable);
1697 return d->movingHorizontally || d->movingVertically;
1701 \qmlproperty bool QtQuick1::Flickable::moving
1702 \qmlproperty bool QtQuick1::Flickable::movingHorizontally
1703 \qmlproperty bool QtQuick1::Flickable::movingVertically
1705 These properties describe whether the view is currently moving horizontally,
1706 vertically or in either direction, due to the user either dragging or
1709 bool QDeclarative1Flickable::isMovingHorizontally() const
1711 Q_D(const QDeclarative1Flickable);
1712 return d->movingHorizontally;
1715 bool QDeclarative1Flickable::isMovingVertically() const
1717 Q_D(const QDeclarative1Flickable);
1718 return d->movingVertically;
1721 void QDeclarative1Flickable::movementStarting()
1723 Q_D(QDeclarative1Flickable);
1724 if (d->hMoved && !d->movingHorizontally) {
1725 d->movingHorizontally = true;
1726 emit movingChanged();
1727 emit movingHorizontallyChanged();
1728 if (!d->movingVertically)
1729 emit movementStarted();
1731 else if (d->vMoved && !d->movingVertically) {
1732 d->movingVertically = true;
1733 emit movingChanged();
1734 emit movingVerticallyChanged();
1735 if (!d->movingHorizontally)
1736 emit movementStarted();
1740 void QDeclarative1Flickable::movementEnding()
1742 Q_D(QDeclarative1Flickable);
1745 d->hData.smoothVelocity.setValue(0);
1746 d->vData.smoothVelocity.setValue(0);
1749 void QDeclarative1Flickable::movementXEnding()
1751 Q_D(QDeclarative1Flickable);
1752 if (d->flickingHorizontally) {
1753 d->flickingHorizontally = false;
1754 emit flickingChanged();
1755 emit flickingHorizontallyChanged();
1756 if (!d->flickingVertically)
1759 if (!d->pressed && !d->stealMouse) {
1760 if (d->movingHorizontally) {
1761 d->movingHorizontally = false;
1763 emit movingChanged();
1764 emit movingHorizontallyChanged();
1765 if (!d->movingVertically)
1766 emit movementEnded();
1769 d->hData.fixingUp = false;
1772 void QDeclarative1Flickable::movementYEnding()
1774 Q_D(QDeclarative1Flickable);
1775 if (d->flickingVertically) {
1776 d->flickingVertically = false;
1777 emit flickingChanged();
1778 emit flickingVerticallyChanged();
1779 if (!d->flickingHorizontally)
1782 if (!d->pressed && !d->stealMouse) {
1783 if (d->movingVertically) {
1784 d->movingVertically = false;
1786 emit movingChanged();
1787 emit movingVerticallyChanged();
1788 if (!d->movingHorizontally)
1789 emit movementEnded();
1792 d->vData.fixingUp = false;
1795 void QDeclarative1FlickablePrivate::updateVelocity()
1797 Q_Q(QDeclarative1Flickable);
1798 emit q->horizontalVelocityChanged();
1799 emit q->verticalVelocityChanged();