1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** 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 , hMoved(false), vMoved(false)
174 , stealMouse(false), pressed(false), interactive(true), calcVelocity(false)
175 , deceleration(QML_FLICK_DEFAULTDECELERATION)
176 , maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100)
177 , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(400)
178 , fixupMode(Normal), vTime(0), visibleArea(0)
179 , flickableDirection(QDeclarative1Flickable::AutoFlickDirection)
180 , boundsBehavior(QDeclarative1Flickable::DragAndOvershootBounds)
184 void QDeclarative1FlickablePrivate::init()
186 Q_Q(QDeclarative1Flickable);
187 QDeclarative_setParent_noEvent(contentItem, q);
188 contentItem->setParentItem(q);
189 static int timelineUpdatedIdx = -1;
190 static int timelineCompletedIdx = -1;
191 static int flickableTickedIdx = -1;
192 static int flickableMovementEndingIdx = -1;
193 if (timelineUpdatedIdx == -1) {
194 timelineUpdatedIdx = QDeclarative1TimeLine::staticMetaObject.indexOfSignal("updated()");
195 timelineCompletedIdx = QDeclarative1TimeLine::staticMetaObject.indexOfSignal("completed()");
196 flickableTickedIdx = QDeclarative1Flickable::staticMetaObject.indexOfSlot("ticked()");
197 flickableMovementEndingIdx = QDeclarative1Flickable::staticMetaObject.indexOfSlot("movementEnding()");
199 QMetaObject::connect(&timeline, timelineUpdatedIdx,
200 q, flickableTickedIdx, Qt::DirectConnection);
201 QMetaObject::connect(&timeline, timelineCompletedIdx,
202 q, flickableMovementEndingIdx, Qt::DirectConnection);
203 q->setAcceptedMouseButtons(Qt::LeftButton);
204 q->setFiltersChildEvents(true);
205 QDeclarativeItemPrivate *viewportPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(contentItem));
206 viewportPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
207 lastPosTime.invalidate();
211 Returns the amount to overshoot by given a view size.
212 Will be up to the lesser of 1/3 of the view size or QML_FLICK_OVERSHOOT
214 qreal QDeclarative1FlickablePrivate::overShootDistance(qreal size)
216 if (maxVelocity <= 0)
219 return qMin(qreal(QML_FLICK_OVERSHOOT), size/3);
222 void QDeclarative1FlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity)
226 else if (v < -maxVelocity)
228 velocityBuffer.append(v);
229 if (velocityBuffer.count() > QML_FLICK_SAMPLEBUFFER)
230 velocityBuffer.remove(0);
233 void QDeclarative1FlickablePrivate::AxisData::updateVelocity()
235 if (velocityBuffer.count() > QML_FLICK_DISCARDSAMPLES) {
237 int count = velocityBuffer.count()-QML_FLICK_DISCARDSAMPLES;
238 for (int i = 0; i < count; ++i) {
239 qreal v = velocityBuffer.at(i);
246 void QDeclarative1FlickablePrivate::itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeom, const QRectF &oldGeom)
248 Q_Q(QDeclarative1Flickable);
249 if (item == contentItem) {
250 if (newGeom.x() != oldGeom.x())
251 emit q->contentXChanged();
252 if (newGeom.y() != oldGeom.y())
253 emit q->contentYChanged();
257 void QDeclarative1FlickablePrivate::flickX(qreal velocity)
259 Q_Q(QDeclarative1Flickable);
260 flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, velocity);
263 void QDeclarative1FlickablePrivate::flickY(qreal velocity)
265 Q_Q(QDeclarative1Flickable);
266 flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, velocity);
269 void QDeclarative1FlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal,
270 QDeclarative1TimeLineCallback::Callback fixupCallback, qreal velocity)
272 Q_Q(QDeclarative1Flickable);
273 qreal maxDistance = -1;
274 data.fixingUp = false;
275 // -ve velocity means list is moving up
277 maxDistance = qAbs(minExtent - data.move.value());
278 data.flickTarget = minExtent;
280 maxDistance = qAbs(maxExtent - data.move.value());
281 data.flickTarget = maxExtent;
283 if (maxDistance > 0) {
285 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
291 timeline.reset(data.move);
292 if (boundsBehavior == QDeclarative1Flickable::DragAndOvershootBounds)
293 timeline.accel(data.move, v, deceleration);
295 timeline.accel(data.move, v, deceleration, maxDistance);
296 timeline.callback(QDeclarative1TimeLineCallback(&data.move, fixupCallback, this));
297 if (!hData.flicking && q->xflick()) {
298 hData.flicking = true;
299 emit q->flickingChanged();
300 emit q->flickingHorizontallyChanged();
302 emit q->flickStarted();
304 if (!vData.flicking && q->yflick()) {
305 vData.flicking = true;
306 emit q->flickingChanged();
307 emit q->flickingVerticallyChanged();
309 emit q->flickStarted();
312 timeline.reset(data.move);
313 fixup(data, minExtent, maxExtent);
317 void QDeclarative1FlickablePrivate::fixupY_callback(void *data)
319 ((QDeclarative1FlickablePrivate *)data)->fixupY();
322 void QDeclarative1FlickablePrivate::fixupX_callback(void *data)
324 ((QDeclarative1FlickablePrivate *)data)->fixupX();
327 void QDeclarative1FlickablePrivate::fixupX()
329 Q_Q(QDeclarative1Flickable);
330 fixup(hData, q->minXExtent(), q->maxXExtent());
333 void QDeclarative1FlickablePrivate::fixupY()
335 Q_Q(QDeclarative1Flickable);
336 fixup(vData, q->minYExtent(), q->maxYExtent());
339 void QDeclarative1FlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
341 if (data.move.value() > minExtent || maxExtent > minExtent) {
342 timeline.reset(data.move);
343 if (data.move.value() != minExtent) {
346 timeline.set(data.move, minExtent);
349 // The target has changed. Don't start from the beginning; just complete the
350 // second half of the animation using the new extent.
351 timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
352 data.fixingUp = true;
355 qreal dist = minExtent - data.move;
356 timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
357 timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
358 data.fixingUp = true;
362 } else if (data.move.value() < maxExtent) {
363 timeline.reset(data.move);
366 timeline.set(data.move, maxExtent);
369 // The target has changed. Don't start from the beginning; just complete the
370 // second half of the animation using the new extent.
371 timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
372 data.fixingUp = true;
375 qreal dist = maxExtent - data.move;
376 timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
377 timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
378 data.fixingUp = true;
382 data.inOvershoot = false;
384 vTime = timeline.time();
387 void QDeclarative1FlickablePrivate::updateBeginningEnd()
389 Q_Q(QDeclarative1Flickable);
390 bool atBoundaryChange = false;
393 const int maxyextent = int(-q->maxYExtent());
394 const qreal ypos = -vData.move.value();
395 bool atBeginning = (ypos <= -q->minYExtent());
396 bool atEnd = (maxyextent <= ypos);
398 if (atBeginning != vData.atBeginning) {
399 vData.atBeginning = atBeginning;
400 atBoundaryChange = true;
402 if (atEnd != vData.atEnd) {
404 atBoundaryChange = true;
408 const int maxxextent = int(-q->maxXExtent());
409 const qreal xpos = -hData.move.value();
410 atBeginning = (xpos <= -q->minXExtent());
411 atEnd = (maxxextent <= xpos);
413 if (atBeginning != hData.atBeginning) {
414 hData.atBeginning = atBeginning;
415 atBoundaryChange = true;
417 if (atEnd != hData.atEnd) {
419 atBoundaryChange = true;
422 if (atBoundaryChange)
423 emit q->isAtBoundaryChanged();
426 visibleArea->updateVisible();
430 \qmlclass Flickable QDeclarative1Flickable
431 \inqmlmodule QtQuick 1
433 \ingroup qml-basic-interaction-elements
435 \brief The Flickable item provides a surface that can be "flicked".
438 The Flickable item places its children on a surface that can be dragged
439 and flicked, causing the view onto the child items to scroll. This
440 behavior forms the basis of Items that are designed to show large numbers
441 of child items, such as \l ListView and \l GridView.
443 In traditional user interfaces, views can be scrolled using standard
444 controls, such as scroll bars and arrow buttons. In some situations, it
445 is also possible to drag the view directly by pressing and holding a
446 mouse button while moving the cursor. In touch-based user interfaces,
447 this dragging action is often complemented with a flicking action, where
448 scrolling continues after the user has stopped touching the view.
450 Flickable does not automatically clip its contents. If it is not used as
451 a full-screen item, you should consider setting the \l{Item::}{clip} property
454 \section1 Example Usage
456 \div {class="float-right"}
457 \inlineimage flickable.gif
460 The following example shows a small view onto a large image in which the
461 user can drag or flick the image in order to view different parts of it.
463 \snippet doc/src/snippets/qtquick1/flickable.qml document
467 Items declared as children of a Flickable are automatically parented to the
468 Flickable's \l contentItem. This should be taken into account when
469 operating on the children of the Flickable; it is usually the children of
470 \c contentItem that are relevant. For example, the bound of Items added
471 to the Flickable will be available by \c contentItem.childrenRect
473 \section1 Limitations
475 \note Due to an implementation detail, items placed inside a Flickable cannot anchor to it by
476 \c id. Use \c parent instead.
480 \qmlsignal QtQuick1::Flickable::onMovementStarted()
482 This handler is called when the view begins moving due to user
487 \qmlsignal QtQuick1::Flickable::onMovementEnded()
489 This handler is called when the view stops moving due to user
490 interaction. If a flick was generated, this handler will
491 be triggered once the flick stops. If a flick was not
492 generated, the handler will be triggered when the
493 user stops dragging - i.e. a mouse or touch release.
497 \qmlsignal QtQuick1::Flickable::onFlickStarted()
499 This handler is called when the view is flicked. A flick
500 starts from the point that the mouse or touch is released,
501 while still in motion.
505 \qmlsignal QtQuick1::Flickable::onFlickEnded()
507 This handler is called when the view stops moving due to a flick.
511 \qmlproperty real QtQuick1::Flickable::visibleArea.xPosition
512 \qmlproperty real QtQuick1::Flickable::visibleArea.widthRatio
513 \qmlproperty real QtQuick1::Flickable::visibleArea.yPosition
514 \qmlproperty real QtQuick1::Flickable::visibleArea.heightRatio
516 These properties describe the position and size of the currently viewed area.
517 The size is defined as the percentage of the full view currently visible,
518 scaled to 0.0 - 1.0. The page position is usually in the range 0.0 (beginning) to
519 1.0 minus size ratio (end), i.e. \c yPosition is in the range 0.0 to 1.0-\c heightRatio.
520 However, it is possible for the contents to be dragged outside of the normal
521 range, resulting in the page positions also being outside the normal range.
523 These properties are typically used to draw a scrollbar. For example:
525 \snippet doc/src/snippets/qtquick1/flickableScrollbar.qml 0
527 \snippet doc/src/snippets/qtquick1/flickableScrollbar.qml 1
529 \sa {declarative/ui-components/scrollbar}{scrollbar example}
532 QDeclarative1Flickable::QDeclarative1Flickable(QDeclarativeItem *parent)
533 : QDeclarativeItem(*(new QDeclarative1FlickablePrivate), parent)
535 Q_D(QDeclarative1Flickable);
539 QDeclarative1Flickable::QDeclarative1Flickable(QDeclarative1FlickablePrivate &dd, QDeclarativeItem *parent)
540 : QDeclarativeItem(dd, parent)
542 Q_D(QDeclarative1Flickable);
546 QDeclarative1Flickable::~QDeclarative1Flickable()
551 \qmlproperty real QtQuick1::Flickable::contentX
552 \qmlproperty real QtQuick1::Flickable::contentY
554 These properties hold the surface coordinate currently at the top-left
555 corner of the Flickable. For example, if you flick an image up 100 pixels,
556 \c contentY will be 100.
558 qreal QDeclarative1Flickable::contentX() const
560 Q_D(const QDeclarative1Flickable);
561 return -d->contentItem->x();
564 void QDeclarative1Flickable::setContentX(qreal pos)
566 Q_D(QDeclarative1Flickable);
567 d->timeline.reset(d->hData.move);
568 d->vTime = d->timeline.time();
570 if (-pos != d->hData.move.value()) {
571 d->hData.move.setValue(-pos);
576 qreal QDeclarative1Flickable::contentY() const
578 Q_D(const QDeclarative1Flickable);
579 return -d->contentItem->y();
582 void QDeclarative1Flickable::setContentY(qreal pos)
584 Q_D(QDeclarative1Flickable);
585 d->timeline.reset(d->vData.move);
586 d->vTime = d->timeline.time();
588 if (-pos != d->vData.move.value()) {
589 d->vData.move.setValue(-pos);
595 \qmlproperty bool QtQuick1::Flickable::interactive
597 This property describes whether the user can interact with the Flickable.
598 A user cannot drag or flick a Flickable that is not interactive.
600 By default, this property is true.
602 This property is useful for temporarily disabling flicking. This allows
603 special interaction with Flickable's children; for example, you might want
604 to freeze a flickable map while scrolling through a pop-up dialog that
605 is a child of the Flickable.
607 bool QDeclarative1Flickable::isInteractive() const
609 Q_D(const QDeclarative1Flickable);
610 return d->interactive;
613 void QDeclarative1Flickable::setInteractive(bool interactive)
615 Q_D(QDeclarative1Flickable);
616 if (interactive != d->interactive) {
617 d->interactive = interactive;
618 if (!interactive && (d->hData.flicking || d->vData.flicking)) {
620 d->vTime = d->timeline.time();
621 d->hData.flicking = false;
622 d->vData.flicking = false;
623 emit flickingChanged();
624 emit flickingHorizontallyChanged();
625 emit flickingVerticallyChanged();
628 emit interactiveChanged();
633 \qmlproperty real QtQuick1::Flickable::horizontalVelocity
634 \qmlproperty real QtQuick1::Flickable::verticalVelocity
636 The instantaneous velocity of movement along the x and y axes, in pixels/sec.
638 The reported velocity is smoothed to avoid erratic output.
640 qreal QDeclarative1Flickable::horizontalVelocity() const
642 Q_D(const QDeclarative1Flickable);
643 return d->hData.smoothVelocity.value();
646 qreal QDeclarative1Flickable::verticalVelocity() const
648 Q_D(const QDeclarative1Flickable);
649 return d->vData.smoothVelocity.value();
653 \qmlproperty bool QtQuick1::Flickable::atXBeginning
654 \qmlproperty bool QtQuick1::Flickable::atXEnd
655 \qmlproperty bool QtQuick1::Flickable::atYBeginning
656 \qmlproperty bool QtQuick1::Flickable::atYEnd
658 These properties are true if the flickable view is positioned at the beginning,
661 bool QDeclarative1Flickable::isAtXEnd() const
663 Q_D(const QDeclarative1Flickable);
664 return d->hData.atEnd;
667 bool QDeclarative1Flickable::isAtXBeginning() const
669 Q_D(const QDeclarative1Flickable);
670 return d->hData.atBeginning;
673 bool QDeclarative1Flickable::isAtYEnd() const
675 Q_D(const QDeclarative1Flickable);
676 return d->vData.atEnd;
679 bool QDeclarative1Flickable::isAtYBeginning() const
681 Q_D(const QDeclarative1Flickable);
682 return d->vData.atBeginning;
685 void QDeclarative1Flickable::ticked()
691 \qmlproperty Item QtQuick1::Flickable::contentItem
693 The internal item that contains the Items to be moved in the Flickable.
695 Items declared as children of a Flickable are automatically parented to the Flickable's contentItem.
697 Items created dynamically need to be explicitly parented to the \e contentItem:
701 function addItem(file) {
702 var component = Qt.createComponent(file)
703 component.createObject(myFlickable.contentItem);
708 QDeclarativeItem *QDeclarative1Flickable::contentItem()
710 Q_D(QDeclarative1Flickable);
711 return d->contentItem;
714 QDeclarative1FlickableVisibleArea *QDeclarative1Flickable::visibleArea()
716 Q_D(QDeclarative1Flickable);
718 d->visibleArea = new QDeclarative1FlickableVisibleArea(this);
719 return d->visibleArea;
723 \qmlproperty enumeration QtQuick1::Flickable::flickableDirection
725 This property determines which directions the view can be flicked.
728 \o Flickable.AutoFlickDirection (default) - allows flicking vertically if the
729 \e contentHeight is not equal to the \e height of the Flickable.
730 Allows flicking horizontally if the \e contentWidth is not equal
731 to the \e width of the Flickable.
732 \o Flickable.HorizontalFlick - allows flicking horizontally.
733 \o Flickable.VerticalFlick - allows flicking vertically.
734 \o Flickable.HorizontalAndVerticalFlick - allows flicking in both directions.
737 QDeclarative1Flickable::FlickableDirection QDeclarative1Flickable::flickableDirection() const
739 Q_D(const QDeclarative1Flickable);
740 return d->flickableDirection;
743 void QDeclarative1Flickable::setFlickableDirection(FlickableDirection direction)
745 Q_D(QDeclarative1Flickable);
746 if (direction != d->flickableDirection) {
747 d->flickableDirection = direction;
748 emit flickableDirectionChanged();
752 void QDeclarative1FlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
754 Q_Q(QDeclarative1Flickable);
755 if (interactive && timeline.isActive()
756 && (qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity || qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity))
757 stealMouse = true; // If we've been flicked then steal the click.
760 q->setKeepMouseGrab(stealMouse);
765 hData.dragMinBound = q->minXExtent();
766 vData.dragMinBound = q->minYExtent();
767 hData.dragMaxBound = q->maxXExtent();
768 vData.dragMaxBound = q->maxYExtent();
771 QDeclarativeItemPrivate::start(lastPosTime);
772 pressPos = event->pos();
773 hData.pressPos = hData.move.value();
774 vData.pressPos = vData.move.value();
775 hData.flicking = false;
776 vData.flicking = false;
777 QDeclarativeItemPrivate::start(pressTime);
778 QDeclarativeItemPrivate::start(velocityTime);
781 void QDeclarative1FlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
783 Q_Q(QDeclarative1Flickable);
784 if (!interactive || !lastPosTime.isValid())
786 bool rejectY = false;
787 bool rejectX = false;
789 bool stealY = stealMouse;
790 bool stealX = stealMouse;
793 int dy = int(event->pos().y() - pressPos.y());
794 if (qAbs(dy) > QApplication::startDragDistance() || QDeclarativeItemPrivate::elapsed(pressTime) > 200) {
796 vData.dragStartOffset = dy;
797 qreal newY = dy + vData.pressPos - vData.dragStartOffset;
798 const qreal minY = vData.dragMinBound;
799 const qreal maxY = vData.dragMaxBound;
801 newY = minY + (newY - minY) / 2;
802 if (newY < maxY && maxY - minY <= 0)
803 newY = maxY + (newY - maxY) / 2;
804 if (boundsBehavior == QDeclarative1Flickable::StopAtBounds && (newY > minY || newY < maxY)) {
815 if (!rejectY && stealMouse) {
816 vData.move.setValue(qRound(newY));
819 if (qAbs(dy) > QApplication::startDragDistance())
825 int dx = int(event->pos().x() - pressPos.x());
826 if (qAbs(dx) > QApplication::startDragDistance() || QDeclarativeItemPrivate::elapsed(pressTime) > 200) {
828 hData.dragStartOffset = dx;
829 qreal newX = dx + hData.pressPos - hData.dragStartOffset;
830 const qreal minX = hData.dragMinBound;
831 const qreal maxX = hData.dragMaxBound;
833 newX = minX + (newX - minX) / 2;
834 if (newX < maxX && maxX - minX <= 0)
835 newX = maxX + (newX - maxX) / 2;
836 if (boundsBehavior == QDeclarative1Flickable::StopAtBounds && (newX > minX || newX < maxX)) {
847 if (!rejectX && stealMouse) {
848 hData.move.setValue(qRound(newX));
852 if (qAbs(dx) > QApplication::startDragDistance())
857 stealMouse = stealX || stealY;
859 q->setKeepMouseGrab(true);
862 vData.velocityBuffer.clear();
866 hData.velocityBuffer.clear();
870 if (hMoved || vMoved) {
871 q->movementStarting();
875 if (!lastPos.isNull()) {
876 qreal elapsed = qreal(QDeclarativeItemPrivate::elapsed(lastPosTime)) / 1000.;
879 QDeclarativeItemPrivate::restart(lastPosTime);
880 qreal dy = event->pos().y()-lastPos.y();
881 if (q->yflick() && !rejectY)
882 vData.addVelocitySample(dy/elapsed, maxVelocity);
883 qreal dx = event->pos().x()-lastPos.x();
884 if (q->xflick() && !rejectX)
885 hData.addVelocitySample(dx/elapsed, maxVelocity);
888 lastPos = event->pos();
891 void QDeclarative1FlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
893 Q_Q(QDeclarative1Flickable);
895 q->setKeepMouseGrab(false);
897 if (!lastPosTime.isValid())
900 // if we drag then pause before release we should not cause a flick.
901 qint64 elapsed = QDeclarativeItemPrivate::elapsed(lastPosTime);
903 vData.updateVelocity();
904 hData.updateVelocity();
906 vTime = timeline.time();
908 qreal velocity = elapsed < 100 ? vData.velocity : 0;
909 if (vData.atBeginning || vData.atEnd)
911 if (q->yflick() && qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().y() - pressPos.y()) > FlickThreshold) {
912 velocityTimeline.reset(vData.smoothVelocity);
913 vData.smoothVelocity.setValue(-velocity);
919 velocity = elapsed < 100 ? hData.velocity : 0;
920 if (hData.atBeginning || hData.atEnd)
922 if (q->xflick() && qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().x() - pressPos.x()) > FlickThreshold) {
923 velocityTimeline.reset(hData.smoothVelocity);
924 hData.smoothVelocity.setValue(-velocity);
930 if (!timeline.isActive())
934 void QDeclarative1Flickable::mousePressEvent(QGraphicsSceneMouseEvent *event)
936 Q_D(QDeclarative1Flickable);
937 if (d->interactive) {
939 d->handleMousePressEvent(event);
942 QDeclarativeItem::mousePressEvent(event);
946 void QDeclarative1Flickable::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
948 Q_D(QDeclarative1Flickable);
949 if (d->interactive) {
950 d->handleMouseMoveEvent(event);
953 QDeclarativeItem::mouseMoveEvent(event);
957 void QDeclarative1Flickable::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
959 Q_D(QDeclarative1Flickable);
960 if (d->interactive) {
961 d->clearDelayedPress();
962 d->handleMouseReleaseEvent(event);
966 QDeclarativeItem::mouseReleaseEvent(event);
970 void QDeclarative1Flickable::wheelEvent(QGraphicsSceneWheelEvent *event)
972 Q_D(QDeclarative1Flickable);
973 if (!d->interactive) {
974 QDeclarativeItem::wheelEvent(event);
975 } else if (yflick() && event->orientation() == Qt::Vertical) {
977 if (event->delta() > 0 && contentY() > -minYExtent()) {
978 d->vData.velocity = qMax(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(d->maxVelocity/4));
980 } else if (event->delta() < 0 && contentY() < -maxYExtent()) {
981 d->vData.velocity = qMin(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
985 d->vData.flicking = false;
986 d->flickY(d->vData.velocity);
987 if (d->vData.flicking) {
993 } else if (xflick() && event->orientation() == Qt::Horizontal) {
995 if (event->delta() > 0 && contentX() > -minXExtent()) {
996 d->hData.velocity = qMax(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(d->maxVelocity/4));
998 } else if (event->delta() < 0 && contentX() < -maxXExtent()) {
999 d->hData.velocity = qMin(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
1003 d->hData.flicking = false;
1004 d->flickX(d->hData.velocity);
1005 if (d->hData.flicking) {
1012 QDeclarativeItem::wheelEvent(event);
1016 bool QDeclarative1FlickablePrivate::isOutermostPressDelay() const
1018 Q_Q(const QDeclarative1Flickable);
1019 QDeclarativeItem *item = q->parentItem();
1021 QDeclarative1Flickable *flick = qobject_cast<QDeclarative1Flickable*>(item);
1022 if (flick && flick->pressDelay() > 0 && flick->isInteractive())
1024 item = item->parentItem();
1030 void QDeclarative1FlickablePrivate::captureDelayedPress(QGraphicsSceneMouseEvent *event)
1032 Q_Q(QDeclarative1Flickable);
1033 if (!q->scene() || pressDelay <= 0)
1035 if (!isOutermostPressDelay())
1037 delayedPressTarget = q->scene()->mouseGrabberItem();
1038 delayedPressEvent = new QGraphicsSceneMouseEvent(event->type());
1039 delayedPressEvent->setAccepted(false);
1040 for (int i = 0x1; i <= 0x10; i <<= 1) {
1041 if (event->buttons() & i) {
1042 Qt::MouseButton button = Qt::MouseButton(i);
1043 delayedPressEvent->setButtonDownPos(button, event->buttonDownPos(button));
1044 delayedPressEvent->setButtonDownScenePos(button, event->buttonDownScenePos(button));
1045 delayedPressEvent->setButtonDownScreenPos(button, event->buttonDownScreenPos(button));
1048 delayedPressEvent->setButtons(event->buttons());
1049 delayedPressEvent->setButton(event->button());
1050 delayedPressEvent->setPos(event->pos());
1051 delayedPressEvent->setScenePos(event->scenePos());
1052 delayedPressEvent->setScreenPos(event->screenPos());
1053 delayedPressEvent->setLastPos(event->lastPos());
1054 delayedPressEvent->setLastScenePos(event->lastScenePos());
1055 delayedPressEvent->setLastScreenPos(event->lastScreenPos());
1056 delayedPressEvent->setModifiers(event->modifiers());
1057 delayedPressTimer.start(pressDelay, q);
1060 void QDeclarative1FlickablePrivate::clearDelayedPress()
1062 if (delayedPressEvent) {
1063 delayedPressTimer.stop();
1064 delete delayedPressEvent;
1065 delayedPressEvent = 0;
1069 void QDeclarative1FlickablePrivate::setRoundedViewportX(qreal x)
1071 contentItem->setX(qRound(x));
1074 void QDeclarative1FlickablePrivate::setRoundedViewportY(qreal y)
1076 contentItem->setY(qRound(y));
1079 void QDeclarative1Flickable::timerEvent(QTimerEvent *event)
1081 Q_D(QDeclarative1Flickable);
1082 if (event->timerId() == d->delayedPressTimer.timerId()) {
1083 d->delayedPressTimer.stop();
1084 if (d->delayedPressEvent) {
1085 QDeclarativeItem *grabber = scene() ? qobject_cast<QDeclarativeItem*>(scene()->mouseGrabberItem()) : 0;
1086 if (!grabber || grabber != this) {
1087 // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
1088 // so we reset the grabber
1089 if (scene()->mouseGrabberItem() == d->delayedPressTarget)
1090 d->delayedPressTarget->ungrabMouse();
1091 //Use the event handler that will take care of finding the proper item to propagate the event
1092 QApplication::postEvent(scene(), d->delayedPressEvent);
1094 delete d->delayedPressEvent;
1096 d->delayedPressEvent = 0;
1101 qreal QDeclarative1Flickable::minYExtent() const
1106 qreal QDeclarative1Flickable::minXExtent() const
1112 qreal QDeclarative1Flickable::maxXExtent() const
1114 return width() - vWidth();
1117 qreal QDeclarative1Flickable::maxYExtent() const
1119 return height() - vHeight();
1122 void QDeclarative1Flickable::viewportMoved()
1124 Q_D(QDeclarative1Flickable);
1126 qreal prevX = d->lastFlickablePosition.x();
1127 qreal prevY = d->lastFlickablePosition.y();
1128 if (d->pressed || d->calcVelocity) {
1129 int elapsed = QDeclarativeItemPrivate::restart(d->velocityTime);
1131 qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / elapsed;
1132 if (qAbs(horizontalVelocity) > 0) {
1133 d->velocityTimeline.reset(d->hData.smoothVelocity);
1134 d->velocityTimeline.move(d->hData.smoothVelocity, horizontalVelocity, d->reportedVelocitySmoothing);
1135 d->velocityTimeline.move(d->hData.smoothVelocity, 0, d->reportedVelocitySmoothing);
1137 qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / elapsed;
1138 if (qAbs(verticalVelocity) > 0) {
1139 d->velocityTimeline.reset(d->vData.smoothVelocity);
1140 d->velocityTimeline.move(d->vData.smoothVelocity, verticalVelocity, d->reportedVelocitySmoothing);
1141 d->velocityTimeline.move(d->vData.smoothVelocity, 0, d->reportedVelocitySmoothing);
1145 if (d->timeline.time() > d->vTime) {
1146 d->velocityTimeline.clear();
1147 qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
1148 qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
1149 d->hData.smoothVelocity.setValue(horizontalVelocity);
1150 d->vData.smoothVelocity.setValue(verticalVelocity);
1154 if (!d->vData.inOvershoot && !d->vData.fixingUp && d->vData.flicking
1155 && (d->vData.move.value() > minYExtent() || d->vData.move.value() < maxYExtent())
1156 && qAbs(d->vData.smoothVelocity.value()) > 100) {
1157 // Increase deceleration if we've passed a bound
1158 d->vData.inOvershoot = true;
1159 qreal maxDistance = d->overShootDistance(height());
1160 d->timeline.reset(d->vData.move);
1161 d->timeline.accel(d->vData.move, -d->vData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
1162 d->timeline.callback(QDeclarative1TimeLineCallback(&d->vData.move, d->fixupY_callback, d));
1164 if (!d->hData.inOvershoot && !d->hData.fixingUp && d->hData.flicking
1165 && (d->hData.move.value() > minXExtent() || d->hData.move.value() < maxXExtent())
1166 && qAbs(d->hData.smoothVelocity.value()) > 100) {
1167 // Increase deceleration if we've passed a bound
1168 d->hData.inOvershoot = true;
1169 qreal maxDistance = d->overShootDistance(width());
1170 d->timeline.reset(d->hData.move);
1171 d->timeline.accel(d->hData.move, -d->hData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
1172 d->timeline.callback(QDeclarative1TimeLineCallback(&d->hData.move, d->fixupX_callback, d));
1175 d->lastFlickablePosition = QPointF(d->hData.move.value(), d->vData.move.value());
1177 d->vTime = d->timeline.time();
1178 d->updateBeginningEnd();
1181 void QDeclarative1Flickable::geometryChanged(const QRectF &newGeometry,
1182 const QRectF &oldGeometry)
1184 Q_D(QDeclarative1Flickable);
1185 QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
1187 bool changed = false;
1188 if (newGeometry.width() != oldGeometry.width()) {
1191 if (d->hData.viewSize < 0) {
1192 d->contentItem->setWidth(width());
1193 emit contentWidthChanged();
1195 // Make sure that we're entirely in view.
1196 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1197 d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
1201 if (newGeometry.height() != oldGeometry.height()) {
1204 if (d->vData.viewSize < 0) {
1205 d->contentItem->setHeight(height());
1206 emit contentHeightChanged();
1208 // Make sure that we're entirely in view.
1209 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1210 d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
1216 d->updateBeginningEnd();
1219 void QDeclarative1Flickable::cancelFlick()
1221 Q_D(QDeclarative1Flickable);
1222 d->timeline.reset(d->hData.move);
1223 d->timeline.reset(d->vData.move);
1227 void QDeclarative1FlickablePrivate::data_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
1229 QGraphicsObject *i = qobject_cast<QGraphicsObject *>(o);
1231 QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(i);
1232 if (static_cast<QDeclarativeItemPrivate*>(d)->componentComplete) {
1233 i->setParentItem(static_cast<QDeclarative1FlickablePrivate*>(prop->data)->contentItem);
1235 d->setParentItemHelper(static_cast<QDeclarative1FlickablePrivate*>(prop->data)->contentItem, 0, 0);
1238 o->setParent(prop->object);
1242 int QDeclarative1FlickablePrivate::data_count(QDeclarativeListProperty<QObject> *property)
1244 QDeclarativeItem *contentItem= static_cast<QDeclarative1FlickablePrivate*>(property->data)->contentItem;
1245 return contentItem->childItems().count() + contentItem->children().count();
1248 QObject *QDeclarative1FlickablePrivate::data_at(QDeclarativeListProperty<QObject> *property, int index)
1250 QDeclarativeItem *contentItem = static_cast<QDeclarative1FlickablePrivate*>(property->data)->contentItem;
1252 int childItemCount = contentItem->childItems().count();
1257 if (index < childItemCount) {
1258 return contentItem->childItems().at(index)->toGraphicsObject();
1260 return contentItem->children().at(index - childItemCount);
1266 void QDeclarative1FlickablePrivate::data_clear(QDeclarativeListProperty<QObject> *property)
1268 QDeclarativeItem *contentItem = static_cast<QDeclarative1FlickablePrivate*>(property->data)->contentItem;
1270 const QList<QGraphicsItem*> graphicsItems = contentItem->childItems();
1271 for (int i = 0; i < graphicsItems.count(); i++)
1272 contentItem->scene()->removeItem(graphicsItems[i]);
1274 const QList<QObject*> objects = contentItem->children();
1275 for (int i = 0; i < objects.count(); i++)
1276 objects[i]->setParent(0);
1279 QDeclarativeListProperty<QObject> QDeclarative1Flickable::flickableData()
1281 Q_D(QDeclarative1Flickable);
1282 return QDeclarativeListProperty<QObject>(this, (void *)d, QDeclarative1FlickablePrivate::data_append,
1283 QDeclarative1FlickablePrivate::data_count,
1284 QDeclarative1FlickablePrivate::data_at,
1285 QDeclarative1FlickablePrivate::data_clear);
1288 QDeclarativeListProperty<QGraphicsObject> QDeclarative1Flickable::flickableChildren()
1290 Q_D(QDeclarative1Flickable);
1291 return QGraphicsItemPrivate::get(d->contentItem)->childrenList();
1295 \qmlproperty enumeration QtQuick1::Flickable::boundsBehavior
1296 This property holds whether the surface may be dragged
1297 beyond the Fickable's boundaries, or overshoot the
1298 Flickable's boundaries when flicked.
1300 This enables the feeling that the edges of the view are soft,
1301 rather than a hard physical boundary.
1303 The \c boundsBehavior can be one of:
1306 \o Flickable.StopAtBounds - the contents can not be dragged beyond the boundary
1307 of the flickable, and flicks will not overshoot.
1308 \o Flickable.DragOverBounds - the contents can be dragged beyond the boundary
1309 of the Flickable, but flicks will not overshoot.
1310 \o Flickable.DragAndOvershootBounds (default) - the contents can be dragged
1311 beyond the boundary of the Flickable, and can overshoot the
1312 boundary when flicked.
1315 QDeclarative1Flickable::BoundsBehavior QDeclarative1Flickable::boundsBehavior() const
1317 Q_D(const QDeclarative1Flickable);
1318 return d->boundsBehavior;
1321 void QDeclarative1Flickable::setBoundsBehavior(BoundsBehavior b)
1323 Q_D(QDeclarative1Flickable);
1324 if (b == d->boundsBehavior)
1326 d->boundsBehavior = b;
1327 emit boundsBehaviorChanged();
1331 \qmlproperty real QtQuick1::Flickable::contentWidth
1332 \qmlproperty real QtQuick1::Flickable::contentHeight
1334 The dimensions of the content (the surface controlled by Flickable).
1335 This should typically be set to the combined size of the items placed in the
1338 The following snippet shows how these properties are used to display
1339 an image that is larger than the Flickable item itself:
1341 \snippet doc/src/snippets/qtquick1/flickable.qml document
1343 In some cases, the the content dimensions can be automatically set
1344 using the \l {Item::childrenRect.width}{childrenRect.width}
1345 and \l {Item::childrenRect.height}{childrenRect.height} properties.
1347 qreal QDeclarative1Flickable::contentWidth() const
1349 Q_D(const QDeclarative1Flickable);
1350 return d->hData.viewSize;
1353 void QDeclarative1Flickable::setContentWidth(qreal w)
1355 Q_D(QDeclarative1Flickable);
1356 if (d->hData.viewSize == w)
1358 d->hData.viewSize = w;
1360 d->contentItem->setWidth(width());
1362 d->contentItem->setWidth(w);
1363 // Make sure that we're entirely in view.
1364 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1365 d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
1367 } else if (!d->pressed && d->hData.fixingUp) {
1368 d->fixupMode = QDeclarative1FlickablePrivate::ExtentChanged;
1371 emit contentWidthChanged();
1372 d->updateBeginningEnd();
1375 qreal QDeclarative1Flickable::contentHeight() const
1377 Q_D(const QDeclarative1Flickable);
1378 return d->vData.viewSize;
1381 void QDeclarative1Flickable::setContentHeight(qreal h)
1383 Q_D(QDeclarative1Flickable);
1384 if (d->vData.viewSize == h)
1386 d->vData.viewSize = h;
1388 d->contentItem->setHeight(height());
1390 d->contentItem->setHeight(h);
1391 // Make sure that we're entirely in view.
1392 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1393 d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
1395 } else if (!d->pressed && d->vData.fixingUp) {
1396 d->fixupMode = QDeclarative1FlickablePrivate::ExtentChanged;
1399 emit contentHeightChanged();
1400 d->updateBeginningEnd();
1404 \qmlmethod QtQuick1::Flickable::resizeContent(real width, real height, QPointF center)
1408 Resizes the content to \a width x \a height about \a center.
1410 This does not scale the contents of the Flickable - it only resizes the \l contentWidth
1411 and \l contentHeight.
1413 Resizing the content may result in the content being positioned outside
1414 the bounds of the Flickable. Calling \l returnToBounds() will
1415 move the content back within legal bounds.
1417 void QDeclarative1Flickable::resizeContent(qreal w, qreal h, QPointF center)
1419 Q_D(QDeclarative1Flickable);
1420 if (w != d->hData.viewSize) {
1421 qreal oldSize = d->hData.viewSize;
1422 d->hData.viewSize = w;
1423 d->contentItem->setWidth(w);
1424 emit contentWidthChanged();
1425 if (center.x() != 0) {
1426 qreal pos = center.x() * w / oldSize;
1427 setContentX(contentX() + pos - center.x());
1430 if (h != d->vData.viewSize) {
1431 qreal oldSize = d->vData.viewSize;
1432 d->vData.viewSize = h;
1433 d->contentItem->setHeight(h);
1434 emit contentHeightChanged();
1435 if (center.y() != 0) {
1436 qreal pos = center.y() * h / oldSize;
1437 setContentY(contentY() + pos - center.y());
1440 d->updateBeginningEnd();
1444 \qmlmethod QtQuick1::Flickable::returnToBounds()
1448 Ensures the content is within legal bounds.
1450 This may be called to ensure that the content is within legal bounds
1451 after manually positioning the content.
1453 void QDeclarative1Flickable::returnToBounds()
1455 Q_D(QDeclarative1Flickable);
1460 qreal QDeclarative1Flickable::vWidth() const
1462 Q_D(const QDeclarative1Flickable);
1463 if (d->hData.viewSize < 0)
1466 return d->hData.viewSize;
1469 qreal QDeclarative1Flickable::vHeight() const
1471 Q_D(const QDeclarative1Flickable);
1472 if (d->vData.viewSize < 0)
1475 return d->vData.viewSize;
1478 bool QDeclarative1Flickable::xflick() const
1480 Q_D(const QDeclarative1Flickable);
1481 if (d->flickableDirection == QDeclarative1Flickable::AutoFlickDirection)
1482 return vWidth() != width();
1483 return d->flickableDirection & QDeclarative1Flickable::HorizontalFlick;
1486 bool QDeclarative1Flickable::yflick() const
1488 Q_D(const QDeclarative1Flickable);
1489 if (d->flickableDirection == QDeclarative1Flickable::AutoFlickDirection)
1490 return vHeight() != height();
1491 return d->flickableDirection & QDeclarative1Flickable::VerticalFlick;
1494 bool QDeclarative1Flickable::sceneEvent(QEvent *event)
1496 bool rv = QDeclarativeItem::sceneEvent(event);
1497 if (event->type() == QEvent::UngrabMouse) {
1498 Q_D(QDeclarative1Flickable);
1500 // if our mouse grab has been removed (probably by another Flickable),
1503 d->stealMouse = false;
1504 setKeepMouseGrab(false);
1510 bool QDeclarative1Flickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
1512 Q_D(QDeclarative1Flickable);
1513 QGraphicsSceneMouseEvent mouseEvent(event->type());
1514 QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
1516 QGraphicsScene *s = scene();
1517 QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
1518 QGraphicsItem *grabberItem = s ? s->mouseGrabberItem() : 0;
1519 bool disabledItem = grabberItem && !grabberItem->isEnabled();
1520 bool stealThisEvent = d->stealMouse;
1521 if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
1522 mouseEvent.setAccepted(false);
1523 for (int i = 0x1; i <= 0x10; i <<= 1) {
1524 if (event->buttons() & i) {
1525 Qt::MouseButton button = Qt::MouseButton(i);
1526 mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
1529 mouseEvent.setScenePos(event->scenePos());
1530 mouseEvent.setLastScenePos(event->lastScenePos());
1531 mouseEvent.setPos(mapFromScene(event->scenePos()));
1532 mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
1534 switch(mouseEvent.type()) {
1535 case QEvent::GraphicsSceneMouseMove:
1536 d->handleMouseMoveEvent(&mouseEvent);
1538 case QEvent::GraphicsSceneMousePress:
1539 if (d->pressed) // we are already pressed - this is a delayed replay
1542 d->handleMousePressEvent(&mouseEvent);
1543 d->captureDelayedPress(event);
1544 stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
1546 case QEvent::GraphicsSceneMouseRelease:
1547 if (d->delayedPressEvent) {
1548 // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
1549 // so we reset the grabber
1550 if (s->mouseGrabberItem() == d->delayedPressTarget)
1551 d->delayedPressTarget->ungrabMouse();
1552 //Use the event handler that will take care of finding the proper item to propagate the event
1553 QApplication::sendEvent(scene(), d->delayedPressEvent);
1554 d->clearDelayedPress();
1555 // We send the release
1556 scene()->sendEvent(s->mouseGrabberItem(), event);
1557 // And the event has been consumed
1558 d->stealMouse = false;
1562 d->handleMouseReleaseEvent(&mouseEvent);
1567 grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
1568 if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || disabledItem) {
1569 d->clearDelayedPress();
1573 return stealThisEvent || d->delayedPressEvent || disabledItem;
1574 } else if (d->lastPosTime.isValid()) {
1575 d->lastPosTime.invalidate();
1578 if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
1579 d->clearDelayedPress();
1580 d->stealMouse = false;
1587 bool QDeclarative1Flickable::sceneEventFilter(QGraphicsItem *i, QEvent *e)
1589 Q_D(QDeclarative1Flickable);
1590 if (!isVisible() || !d->interactive || !isEnabled())
1591 return QDeclarativeItem::sceneEventFilter(i, e);
1592 switch (e->type()) {
1593 case QEvent::GraphicsSceneMousePress:
1594 case QEvent::GraphicsSceneMouseMove:
1595 case QEvent::GraphicsSceneMouseRelease:
1596 return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
1601 return QDeclarativeItem::sceneEventFilter(i, e);
1605 \qmlproperty real QtQuick1::Flickable::maximumFlickVelocity
1606 This property holds the maximum velocity that the user can flick the view in pixels/second.
1608 The default value is platform dependent.
1610 qreal QDeclarative1Flickable::maximumFlickVelocity() const
1612 Q_D(const QDeclarative1Flickable);
1613 return d->maxVelocity;
1616 void QDeclarative1Flickable::setMaximumFlickVelocity(qreal v)
1618 Q_D(QDeclarative1Flickable);
1619 if (v == d->maxVelocity)
1622 emit maximumFlickVelocityChanged();
1626 \qmlproperty real QtQuick1::Flickable::flickDeceleration
1627 This property holds the rate at which a flick will decelerate.
1629 The default value is platform dependent.
1631 qreal QDeclarative1Flickable::flickDeceleration() const
1633 Q_D(const QDeclarative1Flickable);
1634 return d->deceleration;
1637 void QDeclarative1Flickable::setFlickDeceleration(qreal deceleration)
1639 Q_D(QDeclarative1Flickable);
1640 if (deceleration == d->deceleration)
1642 d->deceleration = deceleration;
1643 emit flickDecelerationChanged();
1646 bool QDeclarative1Flickable::isFlicking() const
1648 Q_D(const QDeclarative1Flickable);
1649 return d->hData.flicking || d->vData.flicking;
1653 \qmlproperty bool QtQuick1::Flickable::flicking
1654 \qmlproperty bool QtQuick1::Flickable::flickingHorizontally
1655 \qmlproperty bool QtQuick1::Flickable::flickingVertically
1657 These properties describe whether the view is currently moving horizontally,
1658 vertically or in either direction, due to the user flicking the view.
1660 bool QDeclarative1Flickable::isFlickingHorizontally() const
1662 Q_D(const QDeclarative1Flickable);
1663 return d->hData.flicking;
1666 bool QDeclarative1Flickable::isFlickingVertically() const
1668 Q_D(const QDeclarative1Flickable);
1669 return d->vData.flicking;
1673 \qmlproperty int QtQuick1::Flickable::pressDelay
1675 This property holds the time to delay (ms) delivering a press to
1676 children of the Flickable. This can be useful where reacting
1677 to a press before a flicking action has undesirable effects.
1679 If the flickable is dragged/flicked before the delay times out
1680 the press event will not be delivered. If the button is released
1681 within the timeout, both the press and release will be delivered.
1683 Note that for nested Flickables with pressDelay set, the pressDelay of
1684 inner Flickables is overridden by the outermost Flickable.
1686 int QDeclarative1Flickable::pressDelay() const
1688 Q_D(const QDeclarative1Flickable);
1689 return d->pressDelay;
1692 void QDeclarative1Flickable::setPressDelay(int delay)
1694 Q_D(QDeclarative1Flickable);
1695 if (d->pressDelay == delay)
1697 d->pressDelay = delay;
1698 emit pressDelayChanged();
1702 bool QDeclarative1Flickable::isMoving() const
1704 Q_D(const QDeclarative1Flickable);
1705 return d->hData.moving || d->vData.moving;
1709 \qmlproperty bool QtQuick1::Flickable::moving
1710 \qmlproperty bool QtQuick1::Flickable::movingHorizontally
1711 \qmlproperty bool QtQuick1::Flickable::movingVertically
1713 These properties describe whether the view is currently moving horizontally,
1714 vertically or in either direction, due to the user either dragging or
1717 bool QDeclarative1Flickable::isMovingHorizontally() const
1719 Q_D(const QDeclarative1Flickable);
1720 return d->hData.moving;
1723 bool QDeclarative1Flickable::isMovingVertically() const
1725 Q_D(const QDeclarative1Flickable);
1726 return d->vData.moving;
1729 void QDeclarative1Flickable::movementStarting()
1731 Q_D(QDeclarative1Flickable);
1732 if (d->hMoved && !d->hData.moving) {
1733 d->hData.moving = true;
1734 emit movingChanged();
1735 emit movingHorizontallyChanged();
1736 if (!d->vData.moving)
1737 emit movementStarted();
1739 else if (d->vMoved && !d->vData.moving) {
1740 d->vData.moving = true;
1741 emit movingChanged();
1742 emit movingVerticallyChanged();
1743 if (!d->hData.moving)
1744 emit movementStarted();
1748 void QDeclarative1Flickable::movementEnding()
1750 Q_D(QDeclarative1Flickable);
1753 d->hData.smoothVelocity.setValue(0);
1754 d->vData.smoothVelocity.setValue(0);
1757 void QDeclarative1Flickable::movementXEnding()
1759 Q_D(QDeclarative1Flickable);
1760 if (d->hData.flicking) {
1761 d->hData.flicking = false;
1762 emit flickingChanged();
1763 emit flickingHorizontallyChanged();
1764 if (!d->vData.flicking)
1767 if (!d->pressed && !d->stealMouse) {
1768 if (d->hData.moving) {
1769 d->hData.moving = false;
1771 emit movingChanged();
1772 emit movingHorizontallyChanged();
1773 if (!d->vData.moving)
1774 emit movementEnded();
1777 d->hData.fixingUp = false;
1780 void QDeclarative1Flickable::movementYEnding()
1782 Q_D(QDeclarative1Flickable);
1783 if (d->vData.flicking) {
1784 d->vData.flicking = false;
1785 emit flickingChanged();
1786 emit flickingVerticallyChanged();
1787 if (!d->hData.flicking)
1790 if (!d->pressed && !d->stealMouse) {
1791 if (d->vData.moving) {
1792 d->vData.moving = false;
1794 emit movingChanged();
1795 emit movingVerticallyChanged();
1796 if (!d->hData.moving)
1797 emit movementEnded();
1800 d->vData.fixingUp = false;
1803 void QDeclarative1FlickablePrivate::updateVelocity()
1805 Q_Q(QDeclarative1Flickable);
1806 emit q->horizontalVelocityChanged();
1807 emit q->verticalVelocityChanged();