Add contains method to QQuickItem public API
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickflickable.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickflickable_p.h"
43 #include "qquickflickable_p_p.h"
44 #include "qquickcanvas.h"
45 #include "qquickcanvas_p.h"
46 #include "qquickevents_p_p.h"
47
48 #include <private/qqmlglobal_p.h>
49
50 #include <QtQml/qqmlinfo.h>
51 #include <QtGui/qevent.h>
52 #include <QtGui/qguiapplication.h>
53 #include <QtGui/qstylehints.h>
54 #include "qplatformdefs.h"
55
56 QT_BEGIN_NAMESPACE
57
58 // The maximum number of pixels a flick can overshoot
59 #ifndef QML_FLICK_OVERSHOOT
60 #define QML_FLICK_OVERSHOOT 200
61 #endif
62
63 // The number of samples to use in calculating the velocity of a flick
64 #ifndef QML_FLICK_SAMPLEBUFFER
65 #define QML_FLICK_SAMPLEBUFFER 3
66 #endif
67
68 // The number of samples to discard when calculating the flick velocity.
69 // Touch panels often produce inaccurate results as the finger is lifted.
70 #ifndef QML_FLICK_DISCARDSAMPLES
71 #define QML_FLICK_DISCARDSAMPLES 0
72 #endif
73
74 // The default maximum velocity of a flick.
75 #ifndef QML_FLICK_DEFAULTMAXVELOCITY
76 #define QML_FLICK_DEFAULTMAXVELOCITY 2500
77 #endif
78
79 // The default deceleration of a flick.
80 #ifndef QML_FLICK_DEFAULTDECELERATION
81 #define QML_FLICK_DEFAULTDECELERATION 1500
82 #endif
83
84 // How much faster to decelerate when overshooting
85 #ifndef QML_FLICK_OVERSHOOTFRICTION
86 #define QML_FLICK_OVERSHOOTFRICTION 8
87 #endif
88
89 // Multiflick acceleration minimum flick velocity threshold
90 #ifndef QML_FLICK_MULTIFLICK_THRESHOLD
91 #define QML_FLICK_MULTIFLICK_THRESHOLD 1250
92 #endif
93
94 // Multiflick acceleration minimum contentSize/viewSize ratio
95 #ifndef QML_FLICK_MULTIFLICK_RATIO
96 #define QML_FLICK_MULTIFLICK_RATIO 10
97 #endif
98
99 // Multiflick acceleration maximum velocity multiplier
100 #ifndef QML_FLICK_MULTIFLICK_MAXBOOST
101 #define QML_FLICK_MULTIFLICK_MAXBOOST 3.0
102 #endif
103
104 // FlickThreshold determines how far the "mouse" must have moved
105 // before we perform a flick.
106 static const int FlickThreshold = 15;
107
108 // RetainGrabVelocity is the maxmimum instantaneous velocity that
109 // will ensure the Flickable retains the grab on consecutive flicks.
110 static const int RetainGrabVelocity = 100;
111
112 QQuickFlickableVisibleArea::QQuickFlickableVisibleArea(QQuickFlickable *parent)
113     : QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
114     , m_yPosition(0.), m_heightRatio(0.)
115 {
116 }
117
118 qreal QQuickFlickableVisibleArea::widthRatio() const
119 {
120     return m_widthRatio;
121 }
122
123 qreal QQuickFlickableVisibleArea::xPosition() const
124 {
125     return m_xPosition;
126 }
127
128 qreal QQuickFlickableVisibleArea::heightRatio() const
129 {
130     return m_heightRatio;
131 }
132
133 qreal QQuickFlickableVisibleArea::yPosition() const
134 {
135     return m_yPosition;
136 }
137
138 void QQuickFlickableVisibleArea::updateVisible()
139 {
140     QQuickFlickablePrivate *p = QQuickFlickablePrivate::get(flickable);
141
142     bool changeX = false;
143     bool changeY = false;
144     bool changeWidth = false;
145     bool changeHeight = false;
146
147     // Vertical
148     const qreal viewheight = flickable->height();
149     const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent();
150     qreal pagePos = (-p->vData.move.value() + flickable->minYExtent()) / (maxyextent + viewheight);
151     qreal pageSize = viewheight / (maxyextent + viewheight);
152
153     if (pageSize != m_heightRatio) {
154         m_heightRatio = pageSize;
155         changeHeight = true;
156     }
157     if (pagePos != m_yPosition) {
158         m_yPosition = pagePos;
159         changeY = true;
160     }
161
162     // Horizontal
163     const qreal viewwidth = flickable->width();
164     const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
165     pagePos = (-p->hData.move.value() + flickable->minXExtent()) / (maxxextent + viewwidth);
166     pageSize = viewwidth / (maxxextent + viewwidth);
167
168     if (pageSize != m_widthRatio) {
169         m_widthRatio = pageSize;
170         changeWidth = true;
171     }
172     if (pagePos != m_xPosition) {
173         m_xPosition = pagePos;
174         changeX = true;
175     }
176
177     if (changeX)
178         emit xPositionChanged(m_xPosition);
179     if (changeY)
180         emit yPositionChanged(m_yPosition);
181     if (changeWidth)
182         emit widthRatioChanged(m_widthRatio);
183     if (changeHeight)
184         emit heightRatioChanged(m_heightRatio);
185 }
186
187
188 QQuickFlickablePrivate::QQuickFlickablePrivate()
189   : contentItem(new QQuickItem)
190     , hData(this, &QQuickFlickablePrivate::setViewportX)
191     , vData(this, &QQuickFlickablePrivate::setViewportY)
192     , hMoved(false), vMoved(false)
193     , stealMouse(false), pressed(false), interactive(true), calcVelocity(false)
194     , pixelAligned(false)
195     , lastPosTime(-1)
196     , lastPressTime(0)
197     , deceleration(QML_FLICK_DEFAULTDECELERATION)
198     , maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100)
199     , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(400)
200     , flickBoost(1.0), fixupMode(Normal), vTime(0), visibleArea(0)
201     , flickableDirection(QQuickFlickable::AutoFlickDirection)
202     , boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
203 {
204 }
205
206 void QQuickFlickablePrivate::init()
207 {
208     Q_Q(QQuickFlickable);
209     QQml_setParent_noEvent(contentItem, q);
210     contentItem->setParentItem(q);
211     FAST_CONNECT(&timeline, SIGNAL(completed()), q, SLOT(movementEnding()))
212     q->setAcceptedMouseButtons(Qt::LeftButton);
213     q->setFiltersChildMouseEvents(true);
214     QQuickItemPrivate *viewportPrivate = QQuickItemPrivate::get(contentItem);
215     viewportPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
216 }
217
218 /*
219     Returns the amount to overshoot by given a velocity.
220     Will be roughly in range 0 - size/4
221 */
222 qreal QQuickFlickablePrivate::overShootDistance(qreal size)
223 {
224     if (maxVelocity <= 0)
225         return 0.0;
226
227     return qMin(qreal(QML_FLICK_OVERSHOOT), size/3);
228 }
229
230 void QQuickFlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity)
231 {
232     if (v > maxVelocity)
233         v = maxVelocity;
234     else if (v < -maxVelocity)
235         v = -maxVelocity;
236     velocityBuffer.append(v);
237     if (velocityBuffer.count() > QML_FLICK_SAMPLEBUFFER)
238         velocityBuffer.remove(0);
239 }
240
241 void QQuickFlickablePrivate::AxisData::updateVelocity()
242 {
243     velocity = 0;
244     if (velocityBuffer.count() > QML_FLICK_DISCARDSAMPLES) {
245         int count = velocityBuffer.count()-QML_FLICK_DISCARDSAMPLES;
246         for (int i = 0; i < count; ++i) {
247             qreal v = velocityBuffer.at(i);
248             velocity += v;
249         }
250         velocity /= count;
251     }
252 }
253
254 void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeom, const QRectF &oldGeom)
255 {
256     Q_Q(QQuickFlickable);
257     if (item == contentItem) {
258         bool xChanged = newGeom.x() != oldGeom.x();
259         bool yChanged = newGeom.y() != oldGeom.y();
260         if (xChanged || yChanged)
261             q->viewportMoved();
262         if (xChanged)
263             emit q->contentXChanged();
264         if (yChanged)
265             emit q->contentYChanged();
266     }
267 }
268
269 void QQuickFlickablePrivate::flickX(qreal velocity)
270 {
271     Q_Q(QQuickFlickable);
272     flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, velocity);
273 }
274
275 void QQuickFlickablePrivate::flickY(qreal velocity)
276 {
277     Q_Q(QQuickFlickable);
278     flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, velocity);
279 }
280
281 void QQuickFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal,
282                                          QQuickTimeLineCallback::Callback fixupCallback, qreal velocity)
283 {
284     Q_Q(QQuickFlickable);
285     qreal maxDistance = -1;
286     data.fixingUp = false;
287     // -ve velocity means list is moving up
288     if (velocity > 0) {
289         maxDistance = qAbs(minExtent - data.move.value());
290         data.flickTarget = minExtent;
291     } else {
292         maxDistance = qAbs(maxExtent - data.move.value());
293         data.flickTarget = maxExtent;
294     }
295     if (maxDistance > 0) {
296         qreal v = velocity;
297         if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
298             if (v < 0)
299                 v = -maxVelocity;
300             else
301                 v = maxVelocity;
302         }
303         timeline.reset(data.move);
304         if (boundsBehavior == QQuickFlickable::DragAndOvershootBounds)
305             timeline.accel(data.move, v, deceleration);
306         else
307             timeline.accel(data.move, v, deceleration, maxDistance);
308         timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
309         if (!hData.flicking && q->xflick() && (&data == &hData)) {
310             hData.flicking = true;
311             emit q->flickingChanged();
312             emit q->flickingHorizontallyChanged();
313             if (!vData.flicking)
314                 emit q->flickStarted();
315         }
316         if (!vData.flicking && q->yflick() && (&data == &vData)) {
317             vData.flicking = true;
318             emit q->flickingChanged();
319             emit q->flickingVerticallyChanged();
320             if (!hData.flicking)
321                 emit q->flickStarted();
322         }
323     } else {
324         timeline.reset(data.move);
325         fixup(data, minExtent, maxExtent);
326     }
327 }
328
329 void QQuickFlickablePrivate::fixupY_callback(void *data)
330 {
331     ((QQuickFlickablePrivate *)data)->fixupY();
332 }
333
334 void QQuickFlickablePrivate::fixupX_callback(void *data)
335 {
336     ((QQuickFlickablePrivate *)data)->fixupX();
337 }
338
339 void QQuickFlickablePrivate::fixupX()
340 {
341     Q_Q(QQuickFlickable);
342     fixup(hData, q->minXExtent(), q->maxXExtent());
343 }
344
345 void QQuickFlickablePrivate::fixupY()
346 {
347     Q_Q(QQuickFlickable);
348     fixup(vData, q->minYExtent(), q->maxYExtent());
349 }
350
351 void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
352 {
353     if (data.move.value() > minExtent || maxExtent > minExtent) {
354         timeline.reset(data.move);
355         if (data.move.value() != minExtent) {
356             switch (fixupMode) {
357             case Immediate:
358                 timeline.set(data.move, minExtent);
359                 break;
360             case ExtentChanged:
361                 // The target has changed. Don't start from the beginning; just complete the
362                 // second half of the animation using the new extent.
363                 timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
364                 data.fixingUp = true;
365                 break;
366             default: {
367                     qreal dist = minExtent - data.move;
368                     timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
369                     timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
370                     data.fixingUp = true;
371                 }
372             }
373         }
374     } else if (data.move.value() < maxExtent) {
375         timeline.reset(data.move);
376         switch (fixupMode) {
377         case Immediate:
378             timeline.set(data.move, maxExtent);
379             break;
380         case ExtentChanged:
381             // The target has changed. Don't start from the beginning; just complete the
382             // second half of the animation using the new extent.
383             timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
384             data.fixingUp = true;
385             break;
386         default: {
387                 qreal dist = maxExtent - data.move;
388                 timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
389                 timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
390                 data.fixingUp = true;
391             }
392         }
393     }
394     data.inOvershoot = false;
395     fixupMode = Normal;
396     vTime = timeline.time();
397 }
398
399 void QQuickFlickablePrivate::updateBeginningEnd()
400 {
401     Q_Q(QQuickFlickable);
402     bool atBoundaryChange = false;
403
404     // Vertical
405     const int maxyextent = int(-q->maxYExtent());
406     const qreal ypos = -vData.move.value();
407     bool atBeginning = (ypos <= -q->minYExtent());
408     bool atEnd = (maxyextent <= ypos);
409
410     if (atBeginning != vData.atBeginning) {
411         vData.atBeginning = atBeginning;
412         atBoundaryChange = true;
413     }
414     if (atEnd != vData.atEnd) {
415         vData.atEnd = atEnd;
416         atBoundaryChange = true;
417     }
418
419     // Horizontal
420     const int maxxextent = int(-q->maxXExtent());
421     const qreal xpos = -hData.move.value();
422     atBeginning = (xpos <= -q->minXExtent());
423     atEnd = (maxxextent <= xpos);
424
425     if (atBeginning != hData.atBeginning) {
426         hData.atBeginning = atBeginning;
427         atBoundaryChange = true;
428     }
429     if (atEnd != hData.atEnd) {
430         hData.atEnd = atEnd;
431         atBoundaryChange = true;
432     }
433
434     if (vData.extentsChanged) {
435         vData.extentsChanged = false;
436         emit q->yOriginChanged();
437     }
438
439     if (hData.extentsChanged) {
440         hData.extentsChanged = false;
441         emit q->xOriginChanged();
442     }
443
444     if (atBoundaryChange)
445         emit q->isAtBoundaryChanged();
446
447     if (visibleArea)
448         visibleArea->updateVisible();
449 }
450
451 /*
452 XXXTODO add docs describing moving, dragging, flicking properties, e.g.
453
454 When the user starts dragging the Flickable, the dragging and moving properties
455 will be true.
456
457 If the velocity is sufficient when the drag is ended, flicking may begin.
458
459 The moving properties will remain true until all dragging and flicking
460 is finished.
461 */
462
463 /*!
464     \qmlsignal QtQuick2::Flickable::onDragStarted()
465
466     This handler is called when the view starts to be dragged due to user
467     interaction.
468 */
469
470 /*!
471     \qmlsignal QtQuick2::Flickable::onDragEnded()
472
473     This handler is called when the user stops dragging the view.
474
475     If the velocity of the drag is suffient at the time the
476     touch/mouse button is released then a flick will start.
477 */
478
479 /*!
480     \qmlclass Flickable QQuickFlickable
481     \inqmlmodule QtQuick 2
482     \ingroup qml-basic-interaction-elements
483
484     \brief The Flickable item provides a surface that can be "flicked".
485     \inherits Item
486
487     The Flickable item places its children on a surface that can be dragged
488     and flicked, causing the view onto the child items to scroll. This
489     behavior forms the basis of Items that are designed to show large numbers
490     of child items, such as \l ListView and \l GridView.
491
492     In traditional user interfaces, views can be scrolled using standard
493     controls, such as scroll bars and arrow buttons. In some situations, it
494     is also possible to drag the view directly by pressing and holding a
495     mouse button while moving the cursor. In touch-based user interfaces,
496     this dragging action is often complemented with a flicking action, where
497     scrolling continues after the user has stopped touching the view.
498
499     Flickable does not automatically clip its contents. If it is not used as
500     a full-screen item, you should consider setting the \l{Item::}{clip} property
501     to true.
502
503     \section1 Example Usage
504
505     \div {class="float-right"}
506     \inlineimage flickable.gif
507     \enddiv
508
509     The following example shows a small view onto a large image in which the
510     user can drag or flick the image in order to view different parts of it.
511
512     \snippet doc/src/snippets/qml/flickable.qml document
513
514     \clearfloat
515
516     Items declared as children of a Flickable are automatically parented to the
517     Flickable's \l contentItem.  This should be taken into account when
518     operating on the children of the Flickable; it is usually the children of
519     \c contentItem that are relevant.  For example, the bound of Items added
520     to the Flickable will be available by \c contentItem.childrenRect
521
522     \section1 Limitations
523
524     \note Due to an implementation detail, items placed inside a Flickable cannot anchor to it by
525     \c id. Use \c parent instead.
526 */
527
528 /*!
529     \qmlsignal QtQuick2::Flickable::onMovementStarted()
530
531     This handler is called when the view begins moving due to user
532     interaction.
533 */
534
535 /*!
536     \qmlsignal QtQuick2::Flickable::onMovementEnded()
537
538     This handler is called when the view stops moving due to user
539     interaction.  If a flick was generated, this handler will
540     be triggered once the flick stops.  If a flick was not
541     generated, the handler will be triggered when the
542     user stops dragging - i.e. a mouse or touch release.
543 */
544
545 /*!
546     \qmlsignal QtQuick2::Flickable::onFlickStarted()
547
548     This handler is called when the view is flicked.  A flick
549     starts from the point that the mouse or touch is released,
550     while still in motion.
551 */
552
553 /*!
554     \qmlsignal QtQuick2::Flickable::onFlickEnded()
555
556     This handler is called when the view stops moving due to a flick.
557 */
558
559 /*!
560     \qmlproperty real QtQuick2::Flickable::visibleArea.xPosition
561     \qmlproperty real QtQuick2::Flickable::visibleArea.widthRatio
562     \qmlproperty real QtQuick2::Flickable::visibleArea.yPosition
563     \qmlproperty real QtQuick2::Flickable::visibleArea.heightRatio
564
565     These properties describe the position and size of the currently viewed area.
566     The size is defined as the percentage of the full view currently visible,
567     scaled to 0.0 - 1.0.  The page position is usually in the range 0.0 (beginning) to
568     1.0 minus size ratio (end), i.e. \c yPosition is in the range 0.0 to 1.0-\c heightRatio.
569     However, it is possible for the contents to be dragged outside of the normal
570     range, resulting in the page positions also being outside the normal range.
571
572     These properties are typically used to draw a scrollbar. For example:
573
574     \snippet doc/src/snippets/qml/flickableScrollbar.qml 0
575     \dots 8
576     \snippet doc/src/snippets/qml/flickableScrollbar.qml 1
577
578     \sa {declarative/ui-components/scrollbar}{scrollbar example}
579 */
580 QQuickFlickable::QQuickFlickable(QQuickItem *parent)
581   : QQuickItem(*(new QQuickFlickablePrivate), parent)
582 {
583     Q_D(QQuickFlickable);
584     d->init();
585 }
586
587 QQuickFlickable::QQuickFlickable(QQuickFlickablePrivate &dd, QQuickItem *parent)
588   : QQuickItem(dd, parent)
589 {
590     Q_D(QQuickFlickable);
591     d->init();
592 }
593
594 QQuickFlickable::~QQuickFlickable()
595 {
596 }
597
598 /*!
599     \qmlproperty real QtQuick2::Flickable::contentX
600     \qmlproperty real QtQuick2::Flickable::contentY
601
602     These properties hold the surface coordinate currently at the top-left
603     corner of the Flickable. For example, if you flick an image up 100 pixels,
604     \c contentY will be 100.
605 */
606 qreal QQuickFlickable::contentX() const
607 {
608     Q_D(const QQuickFlickable);
609     return -d->contentItem->x();
610 }
611
612 void QQuickFlickable::setContentX(qreal pos)
613 {
614     Q_D(QQuickFlickable);
615     d->hData.explicitValue = true;
616     d->timeline.reset(d->hData.move);
617     d->vTime = d->timeline.time();
618     movementXEnding();
619     if (-pos != d->hData.move.value())
620         d->hData.move.setValue(-pos);
621 }
622
623 qreal QQuickFlickable::contentY() const
624 {
625     Q_D(const QQuickFlickable);
626     return -d->contentItem->y();
627 }
628
629 void QQuickFlickable::setContentY(qreal pos)
630 {
631     Q_D(QQuickFlickable);
632     d->vData.explicitValue = true;
633     d->timeline.reset(d->vData.move);
634     d->vTime = d->timeline.time();
635     movementYEnding();
636     if (-pos != d->vData.move.value())
637         d->vData.move.setValue(-pos);
638 }
639
640 /*!
641     \qmlproperty bool QtQuick2::Flickable::interactive
642
643     This property describes whether the user can interact with the Flickable.
644     A user cannot drag or flick a Flickable that is not interactive.
645
646     By default, this property is true.
647
648     This property is useful for temporarily disabling flicking. This allows
649     special interaction with Flickable's children; for example, you might want
650     to freeze a flickable map while scrolling through a pop-up dialog that
651     is a child of the Flickable.
652 */
653 bool QQuickFlickable::isInteractive() const
654 {
655     Q_D(const QQuickFlickable);
656     return d->interactive;
657 }
658
659 void QQuickFlickable::setInteractive(bool interactive)
660 {
661     Q_D(QQuickFlickable);
662     if (interactive != d->interactive) {
663         d->interactive = interactive;
664         if (!interactive && (d->hData.flicking || d->vData.flicking)) {
665             d->timeline.clear();
666             d->vTime = d->timeline.time();
667             d->hData.flicking = false;
668             d->vData.flicking = false;
669             emit flickingChanged();
670             emit flickingHorizontallyChanged();
671             emit flickingVerticallyChanged();
672             emit flickEnded();
673         }
674         emit interactiveChanged();
675     }
676 }
677
678 /*!
679     \qmlproperty real QtQuick2::Flickable::horizontalVelocity
680     \qmlproperty real QtQuick2::Flickable::verticalVelocity
681
682     The instantaneous velocity of movement along the x and y axes, in pixels/sec.
683
684     The reported velocity is smoothed to avoid erratic output.
685
686     Note that for views with a large content size (more than 10 times the view size),
687     the velocity of the flick may exceed the velocity of the touch in the case
688     of multiple quick consecutive flicks.  This allows the user to flick faster
689     through large content.
690 */
691 qreal QQuickFlickable::horizontalVelocity() const
692 {
693     Q_D(const QQuickFlickable);
694     return d->hData.smoothVelocity.value();
695 }
696
697 qreal QQuickFlickable::verticalVelocity() const
698 {
699     Q_D(const QQuickFlickable);
700     return d->vData.smoothVelocity.value();
701 }
702
703 /*!
704     \qmlproperty bool QtQuick2::Flickable::atXBeginning
705     \qmlproperty bool QtQuick2::Flickable::atXEnd
706     \qmlproperty bool QtQuick2::Flickable::atYBeginning
707     \qmlproperty bool QtQuick2::Flickable::atYEnd
708
709     These properties are true if the flickable view is positioned at the beginning,
710     or end respectively.
711 */
712 bool QQuickFlickable::isAtXEnd() const
713 {
714     Q_D(const QQuickFlickable);
715     return d->hData.atEnd;
716 }
717
718 bool QQuickFlickable::isAtXBeginning() const
719 {
720     Q_D(const QQuickFlickable);
721     return d->hData.atBeginning;
722 }
723
724 bool QQuickFlickable::isAtYEnd() const
725 {
726     Q_D(const QQuickFlickable);
727     return d->vData.atEnd;
728 }
729
730 bool QQuickFlickable::isAtYBeginning() const
731 {
732     Q_D(const QQuickFlickable);
733     return d->vData.atBeginning;
734 }
735
736 /*!
737     \qmlproperty Item QtQuick2::Flickable::contentItem
738
739     The internal item that contains the Items to be moved in the Flickable.
740
741     Items declared as children of a Flickable are automatically parented to the Flickable's contentItem.
742
743     Items created dynamically need to be explicitly parented to the \e contentItem:
744     \code
745     Flickable {
746         id: myFlickable
747         function addItem(file) {
748             var component = Qt.createComponent(file)
749             component.createObject(myFlickable.contentItem);
750         }
751     }
752     \endcode
753 */
754 QQuickItem *QQuickFlickable::contentItem()
755 {
756     Q_D(QQuickFlickable);
757     return d->contentItem;
758 }
759
760 QQuickFlickableVisibleArea *QQuickFlickable::visibleArea()
761 {
762     Q_D(QQuickFlickable);
763     if (!d->visibleArea)
764         d->visibleArea = new QQuickFlickableVisibleArea(this);
765     return d->visibleArea;
766 }
767
768 /*!
769     \qmlproperty enumeration QtQuick2::Flickable::flickableDirection
770
771     This property determines which directions the view can be flicked.
772
773     \list
774     \li Flickable.AutoFlickDirection (default) - allows flicking vertically if the
775     \e contentHeight is not equal to the \e height of the Flickable.
776     Allows flicking horizontally if the \e contentWidth is not equal
777     to the \e width of the Flickable.
778     \li Flickable.HorizontalFlick - allows flicking horizontally.
779     \li Flickable.VerticalFlick - allows flicking vertically.
780     \li Flickable.HorizontalAndVerticalFlick - allows flicking in both directions.
781     \endlist
782 */
783 QQuickFlickable::FlickableDirection QQuickFlickable::flickableDirection() const
784 {
785     Q_D(const QQuickFlickable);
786     return d->flickableDirection;
787 }
788
789 void QQuickFlickable::setFlickableDirection(FlickableDirection direction)
790 {
791     Q_D(QQuickFlickable);
792     if (direction != d->flickableDirection) {
793         d->flickableDirection = direction;
794         emit flickableDirectionChanged();
795     }
796 }
797
798 bool QQuickFlickable::pixelAligned() const
799 {
800     Q_D(const QQuickFlickable);
801     return d->pixelAligned;
802 }
803
804 void QQuickFlickable::setPixelAligned(bool align)
805 {
806     Q_D(QQuickFlickable);
807     if (align != d->pixelAligned) {
808         d->pixelAligned = align;
809         emit pixelAlignedChanged();
810     }
811 }
812
813 qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event)
814 {
815     if (0 != event->timestamp() && QQuickItemPrivate::consistentTime == -1)
816         return event->timestamp();
817
818     return QQuickItemPrivate::elapsed(timer);
819 }
820
821 void QQuickFlickablePrivate::handleMousePressEvent(QMouseEvent *event)
822 {
823     Q_Q(QQuickFlickable);
824     QQuickItemPrivate::start(timer);
825     if (interactive && timeline.isActive()
826         && ((qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity && !hData.fixingUp && !hData.inOvershoot)
827             || (qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity && !vData.fixingUp && !vData.inOvershoot))) {
828         stealMouse = true; // If we've been flicked then steal the click.
829         int flickTime = timeline.time();
830         if (flickTime > 600) {
831             // too long between flicks - cancel boost
832             hData.continuousFlickVelocity = 0;
833             vData.continuousFlickVelocity = 0;
834             flickBoost = 1.0;
835         } else {
836             hData.continuousFlickVelocity = -hData.smoothVelocity.value();
837             vData.continuousFlickVelocity = -vData.smoothVelocity.value();
838             if (flickTime > 300) // slower flicking - reduce boost
839                 flickBoost = qMax(1.0, flickBoost - 0.5);
840         }
841     } else {
842         stealMouse = false;
843         hData.continuousFlickVelocity = 0;
844         vData.continuousFlickVelocity = 0;
845         flickBoost = 1.0;
846     }
847     q->setKeepMouseGrab(stealMouse);
848     pressed = true;
849     if (!hData.fixingUp)
850         timeline.reset(hData.move);
851     if (!vData.fixingUp)
852         timeline.reset(vData.move);
853     hData.reset();
854     vData.reset();
855     hData.dragMinBound = q->minXExtent();
856     vData.dragMinBound = q->minYExtent();
857     hData.dragMaxBound = q->maxXExtent();
858     vData.dragMaxBound = q->maxYExtent();
859     fixupMode = Normal;
860     lastPos = QPointF();
861     pressPos = event->localPos();
862     hData.pressPos = hData.move.value();
863     vData.pressPos = vData.move.value();
864     bool wasFlicking = hData.flicking || vData.flicking;
865     if (hData.flicking) {
866         hData.flicking = false;
867         emit q->flickingHorizontallyChanged();
868     }
869     if (vData.flicking) {
870         vData.flicking = false;
871         emit q->flickingVerticallyChanged();
872     }
873     if (wasFlicking)
874         emit q->flickingChanged();
875     lastPosTime = lastPressTime = computeCurrentTime(event);
876     QQuickItemPrivate::start(velocityTime);
877 }
878
879 void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
880 {
881     Q_Q(QQuickFlickable);
882     if (!interactive || lastPosTime == -1)
883         return;
884     bool rejectY = false;
885     bool rejectX = false;
886
887     bool stealY = stealMouse;
888     bool stealX = stealMouse;
889
890     qint64 elapsedSincePress = computeCurrentTime(event) - lastPressTime;
891
892     if (q->yflick()) {
893         qreal dy = event->localPos().y() - pressPos.y();
894         if (qAbs(dy) > qApp->styleHints()->startDragDistance() || elapsedSincePress > 200) {
895             if (!vMoved)
896                 vData.dragStartOffset = dy;
897             qreal newY = dy + vData.pressPos - vData.dragStartOffset;
898             const qreal minY = vData.dragMinBound;
899             const qreal maxY = vData.dragMaxBound;
900             if (newY > minY)
901                 newY = minY + (newY - minY) / 2;
902             if (newY < maxY && maxY - minY <= 0)
903                 newY = maxY + (newY - maxY) / 2;
904             if (boundsBehavior == QQuickFlickable::StopAtBounds && (newY > minY || newY < maxY)) {
905                 rejectY = true;
906                 if (newY < maxY) {
907                     newY = maxY;
908                     rejectY = false;
909                 }
910                 if (newY > minY) {
911                     newY = minY;
912                     rejectY = false;
913                 }
914             }
915             if (!rejectY && stealMouse && dy != 0.0) {
916                 timeline.clear();
917                 vData.move.setValue(newY);
918                 vMoved = true;
919             }
920             if (qAbs(dy) > qApp->styleHints()->startDragDistance())
921                 stealY = true;
922         }
923     }
924
925     if (q->xflick()) {
926         qreal dx = event->localPos().x() - pressPos.x();
927         if (qAbs(dx) > qApp->styleHints()->startDragDistance() || elapsedSincePress > 200) {
928             if (!hMoved)
929                 hData.dragStartOffset = dx;
930             qreal newX = dx + hData.pressPos - hData.dragStartOffset;
931             const qreal minX = hData.dragMinBound;
932             const qreal maxX = hData.dragMaxBound;
933             if (newX > minX)
934                 newX = minX + (newX - minX) / 2;
935             if (newX < maxX && maxX - minX <= 0)
936                 newX = maxX + (newX - maxX) / 2;
937             if (boundsBehavior == QQuickFlickable::StopAtBounds && (newX > minX || newX < maxX)) {
938                 rejectX = true;
939                 if (newX < maxX) {
940                     newX = maxX;
941                     rejectX = false;
942                 }
943                 if (newX > minX) {
944                     newX = minX;
945                     rejectX = false;
946                 }
947             }
948             if (!rejectX && stealMouse && dx != 0.0) {
949                 timeline.clear();
950                 hData.move.setValue(newX);
951                 hMoved = true;
952             }
953
954             if (qAbs(dx) > qApp->styleHints()->startDragDistance())
955                 stealX = true;
956         }
957     }
958
959     stealMouse = stealX || stealY;
960     if (stealMouse)
961         q->setKeepMouseGrab(true);
962
963     if (rejectY) {
964         vData.velocityBuffer.clear();
965         vData.velocity = 0;
966     }
967     if (rejectX) {
968         hData.velocityBuffer.clear();
969         hData.velocity = 0;
970     }
971
972     if (hMoved || vMoved) {
973         draggingStarting();
974         q->movementStarting();
975     }
976
977     qint64 currentTimestamp = computeCurrentTime(event);
978     qreal elapsed = qreal(currentTimestamp - (lastPos.isNull() ? lastPressTime : lastPosTime)) / 1000.;
979     if (elapsed <= 0)
980         return;
981     lastPosTime = currentTimestamp;
982     QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event);
983     if (q->yflick() && !rejectY) {
984         if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
985             vData.addVelocitySample(extended->velocity().y(), maxVelocity);
986         } else {
987             qreal dy = event->localPos().y() - (lastPos.isNull() ? pressPos.y() : lastPos.y());
988             vData.addVelocitySample(dy/elapsed, maxVelocity);
989         }
990     }
991     if (q->xflick() && !rejectX) {
992         if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
993             hData.addVelocitySample(extended->velocity().x(), maxVelocity);
994         } else {
995             qreal dx = event->localPos().x() - (lastPos.isNull() ? pressPos.x() : lastPos.x());
996             hData.addVelocitySample(dx/elapsed, maxVelocity);
997         }
998     }
999
1000     lastPos = event->localPos();
1001 }
1002
1003 void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
1004 {
1005     Q_Q(QQuickFlickable);
1006     stealMouse = false;
1007     q->setKeepMouseGrab(false);
1008     pressed = false;
1009
1010     // if we drag then pause before release we should not cause a flick.
1011     qint64 elapsed = computeCurrentTime(event) - lastPosTime;
1012
1013     vData.updateVelocity();
1014     hData.updateVelocity();
1015
1016     draggingEnding();
1017
1018     if (lastPosTime == -1)
1019         return;
1020
1021     vTime = timeline.time();
1022
1023     bool canBoost = false;
1024
1025     qreal vVelocity = 0;
1026     if (elapsed < 100 && vData.velocity != 0.) {
1027         QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event);
1028         vVelocity = (extended && extended->capabilities().testFlag(QTouchDevice::Velocity))
1029                 ? extended->velocity().y() : vData.velocity;
1030     }
1031     if ((vData.atBeginning && vVelocity > 0.) || (vData.atEnd && vVelocity < 0.)) {
1032         vVelocity /= 2;
1033     } else if (vData.continuousFlickVelocity != 0.0
1034                && vData.viewSize/q->height() > QML_FLICK_MULTIFLICK_RATIO
1035                && ((vVelocity > 0) == (vData.continuousFlickVelocity > 0))
1036                && qAbs(vVelocity) > QML_FLICK_MULTIFLICK_THRESHOLD) {
1037         // accelerate flick for large view flicked quickly
1038         canBoost = true;
1039     }
1040
1041     qreal hVelocity = 0;
1042     if (elapsed < 100 && hData.velocity != 0.) {
1043         QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event);
1044         hVelocity = (extended && extended->capabilities().testFlag(QTouchDevice::Velocity))
1045                 ? extended->velocity().x() : hData.velocity;
1046     }
1047     if ((hData.atBeginning && hVelocity > 0.) || (hData.atEnd && hVelocity < 0.)) {
1048         hVelocity /= 2;
1049     } else if (hData.continuousFlickVelocity != 0.0
1050                && hData.viewSize/q->width() > QML_FLICK_MULTIFLICK_RATIO
1051                && ((hVelocity > 0) == (hData.continuousFlickVelocity > 0))
1052                && qAbs(hVelocity) > QML_FLICK_MULTIFLICK_THRESHOLD) {
1053         // accelerate flick for large view flicked quickly
1054         canBoost = true;
1055     }
1056
1057     flickBoost = canBoost ? qBound(1.0, flickBoost+0.25, QML_FLICK_MULTIFLICK_MAXBOOST) : 1.0;
1058
1059     vVelocity *= flickBoost;
1060     if (q->yflick() && qAbs(vVelocity) > MinimumFlickVelocity && qAbs(event->localPos().y() - pressPos.y()) > FlickThreshold) {
1061         velocityTimeline.reset(vData.smoothVelocity);
1062         vData.smoothVelocity.setValue(-vVelocity);
1063         flickY(vVelocity);
1064     } else {
1065         fixupY();
1066     }
1067
1068     hVelocity *= flickBoost;
1069     if (q->xflick() && qAbs(hVelocity) > MinimumFlickVelocity && qAbs(event->localPos().x() - pressPos.x()) > FlickThreshold) {
1070         velocityTimeline.reset(hData.smoothVelocity);
1071         hData.smoothVelocity.setValue(-hVelocity);
1072         flickX(hVelocity);
1073     } else {
1074         fixupX();
1075     }
1076
1077     if (!timeline.isActive())
1078         q->movementEnding();
1079 }
1080
1081 void QQuickFlickable::mousePressEvent(QMouseEvent *event)
1082 {
1083     Q_D(QQuickFlickable);
1084     if (d->interactive) {
1085         if (!d->pressed)
1086             d->handleMousePressEvent(event);
1087         event->accept();
1088     } else {
1089         QQuickItem::mousePressEvent(event);
1090     }
1091 }
1092
1093 void QQuickFlickable::mouseMoveEvent(QMouseEvent *event)
1094 {
1095     Q_D(QQuickFlickable);
1096     if (d->interactive) {
1097         d->handleMouseMoveEvent(event);
1098         event->accept();
1099     } else {
1100         QQuickItem::mouseMoveEvent(event);
1101     }
1102 }
1103
1104 void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event)
1105 {
1106     Q_D(QQuickFlickable);
1107     if (d->interactive) {
1108         d->clearDelayedPress();
1109         d->handleMouseReleaseEvent(event);
1110         event->accept();
1111         if (canvas() && canvas()->mouseGrabberItem() == this)
1112             ungrabMouse();
1113     } else {
1114         QQuickItem::mouseReleaseEvent(event);
1115     }
1116 }
1117
1118 void QQuickFlickable::wheelEvent(QWheelEvent *event)
1119 {
1120     Q_D(QQuickFlickable);
1121     if (!d->interactive) {
1122         QQuickItem::wheelEvent(event);
1123     } else if (yflick() && event->orientation() == Qt::Vertical) {
1124         bool valid = false;
1125         if (event->delta() > 0 && contentY() > -minYExtent()) {
1126             d->vData.velocity = qMax(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(d->maxVelocity/4));
1127             valid = true;
1128         } else if (event->delta() < 0 && contentY() < -maxYExtent()) {
1129             d->vData.velocity = qMin(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
1130             valid = true;
1131         }
1132         if (valid) {
1133             d->vData.flicking = false;
1134             d->flickY(d->vData.velocity);
1135             if (d->vData.flicking) {
1136                 d->vMoved = true;
1137                 movementStarting();
1138             }
1139             event->accept();
1140         }
1141     } else if (xflick() && event->orientation() == Qt::Horizontal) {
1142         bool valid = false;
1143         if (event->delta() > 0 && contentX() > -minXExtent()) {
1144             d->hData.velocity = qMax(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(d->maxVelocity/4));
1145             valid = true;
1146         } else if (event->delta() < 0 && contentX() < -maxXExtent()) {
1147             d->hData.velocity = qMin(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
1148             valid = true;
1149         }
1150         if (valid) {
1151             d->hData.flicking = false;
1152             d->flickX(d->hData.velocity);
1153             if (d->hData.flicking) {
1154                 d->hMoved = true;
1155                 movementStarting();
1156             }
1157             event->accept();
1158         }
1159     } else {
1160         QQuickItem::wheelEvent(event);
1161     }
1162 }
1163
1164 bool QQuickFlickablePrivate::isOutermostPressDelay() const
1165 {
1166     Q_Q(const QQuickFlickable);
1167     QQuickItem *item = q->parentItem();
1168     while (item) {
1169         QQuickFlickable *flick = qobject_cast<QQuickFlickable*>(item);
1170         if (flick && flick->pressDelay() > 0 && flick->isInteractive())
1171             return false;
1172         item = item->parentItem();
1173     }
1174
1175     return true;
1176 }
1177
1178 void QQuickFlickablePrivate::captureDelayedPress(QMouseEvent *event)
1179 {
1180     Q_Q(QQuickFlickable);
1181     if (!q->canvas() || pressDelay <= 0)
1182         return;
1183     if (!isOutermostPressDelay())
1184         return;
1185     delayedPressTarget = q->canvas()->mouseGrabberItem();
1186     delayedPressEvent = new QQuickMouseEventEx(*event);
1187     delayedPressEvent->setAccepted(false);
1188     delayedPressTimer.start(pressDelay, q);
1189 }
1190
1191 void QQuickFlickablePrivate::clearDelayedPress()
1192 {
1193     if (delayedPressEvent) {
1194         delayedPressTimer.stop();
1195         delete delayedPressEvent;
1196         delayedPressEvent = 0;
1197     }
1198 }
1199
1200 //XXX pixelAligned ignores the global position of the Flickable, i.e. assumes Flickable itself is pixel aligned.
1201 void QQuickFlickablePrivate::setViewportX(qreal x)
1202 {
1203     contentItem->setX(pixelAligned ? qRound(x) : x);
1204 }
1205
1206 void QQuickFlickablePrivate::setViewportY(qreal y)
1207 {
1208     contentItem->setY(pixelAligned ? qRound(y) : y);
1209 }
1210
1211 void QQuickFlickable::timerEvent(QTimerEvent *event)
1212 {
1213     Q_D(QQuickFlickable);
1214     if (event->timerId() == d->delayedPressTimer.timerId()) {
1215         d->delayedPressTimer.stop();
1216         if (d->delayedPressEvent) {
1217             QQuickItem *grabber = canvas() ? canvas()->mouseGrabberItem() : 0;
1218             if (!grabber || grabber != this) {
1219                 // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
1220                 // so we reset the grabber
1221                 if (canvas()->mouseGrabberItem() == d->delayedPressTarget)
1222                     d->delayedPressTarget->ungrabMouse();
1223                 // Use the event handler that will take care of finding the proper item to propagate the event
1224                 QQuickCanvasPrivate::get(canvas())->deliverMouseEvent(d->delayedPressEvent);
1225             }
1226             delete d->delayedPressEvent;
1227             d->delayedPressEvent = 0;
1228         }
1229     }
1230 }
1231
1232 qreal QQuickFlickable::minYExtent() const
1233 {
1234     Q_D(const QQuickFlickable);
1235     return d->vData.startMargin;
1236 }
1237
1238 qreal QQuickFlickable::minXExtent() const
1239 {
1240     Q_D(const QQuickFlickable);
1241     return d->hData.startMargin;
1242 }
1243
1244 /* returns -ve */
1245 qreal QQuickFlickable::maxXExtent() const
1246 {
1247     Q_D(const QQuickFlickable);
1248     return width() - vWidth() - d->hData.endMargin;
1249 }
1250 /* returns -ve */
1251 qreal QQuickFlickable::maxYExtent() const
1252 {
1253     Q_D(const QQuickFlickable);
1254     return height() - vHeight() - d->vData.endMargin;
1255 }
1256
1257 void QQuickFlickable::componentComplete()
1258 {
1259     Q_D(QQuickFlickable);
1260     QQuickItem::componentComplete();
1261     if (!d->hData.explicitValue && d->hData.startMargin != 0.)
1262         setContentX(-minXExtent());
1263     if (!d->vData.explicitValue && d->vData.startMargin != 0.)
1264         setContentY(-minYExtent());
1265 }
1266
1267 void QQuickFlickable::viewportMoved()
1268 {
1269     Q_D(QQuickFlickable);
1270
1271     qreal prevX = d->lastFlickablePosition.x();
1272     qreal prevY = d->lastFlickablePosition.y();
1273     if (d->pressed || d->calcVelocity) {
1274         int elapsed = QQuickItemPrivate::restart(d->velocityTime);
1275         if (elapsed > 0) {
1276             qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / elapsed;
1277             if (qAbs(horizontalVelocity) > 0) {
1278                 d->velocityTimeline.reset(d->hData.smoothVelocity);
1279                 if (d->calcVelocity)
1280                     d->velocityTimeline.set(d->hData.smoothVelocity, horizontalVelocity);
1281                 else
1282                     d->velocityTimeline.move(d->hData.smoothVelocity, horizontalVelocity, d->reportedVelocitySmoothing);
1283                 d->velocityTimeline.move(d->hData.smoothVelocity, 0, d->reportedVelocitySmoothing);
1284             }
1285             qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / elapsed;
1286             if (qAbs(verticalVelocity) > 0) {
1287                 d->velocityTimeline.reset(d->vData.smoothVelocity);
1288                 if (d->calcVelocity)
1289                     d->velocityTimeline.set(d->vData.smoothVelocity, verticalVelocity);
1290                 else
1291                     d->velocityTimeline.move(d->vData.smoothVelocity, verticalVelocity, d->reportedVelocitySmoothing);
1292                 d->velocityTimeline.move(d->vData.smoothVelocity, 0, d->reportedVelocitySmoothing);
1293             }
1294         }
1295     } else {
1296         if (d->timeline.time() > d->vTime) {
1297             d->velocityTimeline.clear();
1298             qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
1299             qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
1300             d->hData.smoothVelocity.setValue(horizontalVelocity);
1301             d->vData.smoothVelocity.setValue(verticalVelocity);
1302         }
1303     }
1304
1305     if (!d->vData.inOvershoot && !d->vData.fixingUp && d->vData.flicking
1306             && (d->vData.move.value() > minYExtent() || d->vData.move.value() < maxYExtent())
1307             && qAbs(d->vData.smoothVelocity.value()) > 100) {
1308         // Increase deceleration if we've passed a bound
1309         d->vData.inOvershoot = true;
1310         qreal maxDistance = d->overShootDistance(height());
1311         d->timeline.reset(d->vData.move);
1312         d->timeline.accel(d->vData.move, -d->vData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
1313         d->timeline.callback(QQuickTimeLineCallback(&d->vData.move, d->fixupY_callback, d));
1314     }
1315     if (!d->hData.inOvershoot && !d->hData.fixingUp && d->hData.flicking
1316             && (d->hData.move.value() > minXExtent() || d->hData.move.value() < maxXExtent())
1317             && qAbs(d->hData.smoothVelocity.value()) > 100) {
1318         // Increase deceleration if we've passed a bound
1319         d->hData.inOvershoot = true;
1320         qreal maxDistance = d->overShootDistance(width());
1321         d->timeline.reset(d->hData.move);
1322         d->timeline.accel(d->hData.move, -d->hData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
1323         d->timeline.callback(QQuickTimeLineCallback(&d->hData.move, d->fixupX_callback, d));
1324     }
1325
1326     d->lastFlickablePosition = QPointF(d->hData.move.value(), d->vData.move.value());
1327
1328     d->vTime = d->timeline.time();
1329     d->updateBeginningEnd();
1330 }
1331
1332 void QQuickFlickable::geometryChanged(const QRectF &newGeometry,
1333                              const QRectF &oldGeometry)
1334 {
1335     Q_D(QQuickFlickable);
1336     QQuickItem::geometryChanged(newGeometry, oldGeometry);
1337
1338     bool changed = false;
1339     if (newGeometry.width() != oldGeometry.width()) {
1340         if (xflick())
1341             changed = true;
1342         if (d->hData.viewSize < 0) {
1343             d->contentItem->setWidth(width());
1344             emit contentWidthChanged();
1345         }
1346         // Make sure that we're entirely in view.
1347         if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1348             d->fixupMode = QQuickFlickablePrivate::Immediate;
1349             d->fixupX();
1350         }
1351     }
1352     if (newGeometry.height() != oldGeometry.height()) {
1353         if (yflick())
1354             changed = true;
1355         if (d->vData.viewSize < 0) {
1356             d->contentItem->setHeight(height());
1357             emit contentHeightChanged();
1358         }
1359         // Make sure that we're entirely in view.
1360         if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1361             d->fixupMode = QQuickFlickablePrivate::Immediate;
1362             d->fixupY();
1363         }
1364     }
1365
1366     if (changed)
1367         d->updateBeginningEnd();
1368 }
1369
1370 /*!
1371     \qmlmethod QtQuick2::Flickable::flick(qreal xVelocity, qreal yVelocity)
1372
1373     Flicks the content with \a xVelocity horizontally and \a yVelocity vertically in pixels/sec.
1374 */
1375
1376 void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity)
1377 {
1378     Q_D(QQuickFlickable);
1379     d->flickX(xVelocity);
1380     d->flickY(yVelocity);
1381 }
1382
1383 /*!
1384     \qmlmethod QtQuick2::Flickable::cancelFlick()
1385
1386     Cancels the current flick animation.
1387 */
1388
1389 void QQuickFlickable::cancelFlick()
1390 {
1391     Q_D(QQuickFlickable);
1392     d->timeline.reset(d->hData.move);
1393     d->timeline.reset(d->vData.move);
1394     movementEnding();
1395 }
1396
1397 void QQuickFlickablePrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
1398 {
1399     QQuickItem *i = qobject_cast<QQuickItem *>(o);
1400     if (i) {
1401         i->setParentItem(static_cast<QQuickFlickablePrivate*>(prop->data)->contentItem);
1402     } else {
1403         o->setParent(prop->object); // XXX todo - do we want this?
1404     }
1405 }
1406
1407 int QQuickFlickablePrivate::data_count(QQmlListProperty<QObject> *)
1408 {
1409     // XXX todo
1410     return 0;
1411 }
1412
1413 QObject *QQuickFlickablePrivate::data_at(QQmlListProperty<QObject> *, int)
1414 {
1415     // XXX todo
1416     return 0;
1417 }
1418
1419 void QQuickFlickablePrivate::data_clear(QQmlListProperty<QObject> *)
1420 {
1421     // XXX todo
1422 }
1423
1424 QQmlListProperty<QObject> QQuickFlickable::flickableData()
1425 {
1426     Q_D(QQuickFlickable);
1427     return QQmlListProperty<QObject>(this, (void *)d, QQuickFlickablePrivate::data_append,
1428                                              QQuickFlickablePrivate::data_count,
1429                                              QQuickFlickablePrivate::data_at,
1430                                              QQuickFlickablePrivate::data_clear);
1431 }
1432
1433 QQmlListProperty<QQuickItem> QQuickFlickable::flickableChildren()
1434 {
1435     Q_D(QQuickFlickable);
1436     return QQuickItemPrivate::get(d->contentItem)->children();
1437 }
1438
1439 /*!
1440     \qmlproperty enumeration QtQuick2::Flickable::boundsBehavior
1441     This property holds whether the surface may be dragged
1442     beyond the Flickable's boundaries, or overshoot the
1443     Flickable's boundaries when flicked.
1444
1445     This enables the feeling that the edges of the view are soft,
1446     rather than a hard physical boundary.
1447
1448     The \c boundsBehavior can be one of:
1449
1450     \list
1451     \li Flickable.StopAtBounds - the contents can not be dragged beyond the boundary
1452     of the flickable, and flicks will not overshoot.
1453     \li Flickable.DragOverBounds - the contents can be dragged beyond the boundary
1454     of the Flickable, but flicks will not overshoot.
1455     \li Flickable.DragAndOvershootBounds (default) - the contents can be dragged
1456     beyond the boundary of the Flickable, and can overshoot the
1457     boundary when flicked.
1458     \endlist
1459 */
1460 QQuickFlickable::BoundsBehavior QQuickFlickable::boundsBehavior() const
1461 {
1462     Q_D(const QQuickFlickable);
1463     return d->boundsBehavior;
1464 }
1465
1466 void QQuickFlickable::setBoundsBehavior(BoundsBehavior b)
1467 {
1468     Q_D(QQuickFlickable);
1469     if (b == d->boundsBehavior)
1470         return;
1471     d->boundsBehavior = b;
1472     emit boundsBehaviorChanged();
1473 }
1474
1475 /*!
1476     \qmlproperty real QtQuick2::Flickable::contentWidth
1477     \qmlproperty real QtQuick2::Flickable::contentHeight
1478
1479     The dimensions of the content (the surface controlled by Flickable).
1480     This should typically be set to the combined size of the items placed in the
1481     Flickable.
1482
1483     The following snippet shows how these properties are used to display
1484     an image that is larger than the Flickable item itself:
1485
1486     \snippet doc/src/snippets/qml/flickable.qml document
1487
1488     In some cases, the the content dimensions can be automatically set
1489     using the \l {Item::childrenRect.width}{childrenRect.width}
1490     and \l {Item::childrenRect.height}{childrenRect.height} properties.
1491 */
1492 qreal QQuickFlickable::contentWidth() const
1493 {
1494     Q_D(const QQuickFlickable);
1495     return d->hData.viewSize;
1496 }
1497
1498 void QQuickFlickable::setContentWidth(qreal w)
1499 {
1500     Q_D(QQuickFlickable);
1501     if (d->hData.viewSize == w)
1502         return;
1503     d->hData.viewSize = w;
1504     if (w < 0)
1505         d->contentItem->setWidth(width());
1506     else
1507         d->contentItem->setWidth(w);
1508     d->hData.markExtentsDirty();
1509     // Make sure that we're entirely in view.
1510     if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1511         d->fixupMode = QQuickFlickablePrivate::Immediate;
1512         d->fixupX();
1513     } else if (!d->pressed && d->hData.fixingUp) {
1514         d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
1515         d->fixupX();
1516     }
1517     emit contentWidthChanged();
1518     d->updateBeginningEnd();
1519 }
1520
1521 qreal QQuickFlickable::contentHeight() const
1522 {
1523     Q_D(const QQuickFlickable);
1524     return d->vData.viewSize;
1525 }
1526
1527 void QQuickFlickable::setContentHeight(qreal h)
1528 {
1529     Q_D(QQuickFlickable);
1530     if (d->vData.viewSize == h)
1531         return;
1532     d->vData.viewSize = h;
1533     if (h < 0)
1534         d->contentItem->setHeight(height());
1535     else
1536         d->contentItem->setHeight(h);
1537     d->vData.markExtentsDirty();
1538     // Make sure that we're entirely in view.
1539     if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1540         d->fixupMode = QQuickFlickablePrivate::Immediate;
1541         d->fixupY();
1542     } else if (!d->pressed && d->vData.fixingUp) {
1543         d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
1544         d->fixupY();
1545     }
1546     emit contentHeightChanged();
1547     d->updateBeginningEnd();
1548 }
1549
1550 /*!
1551     \qmlproperty real QtQuick2::Flickable::topMargin
1552     \qmlproperty real QtQuick2::Flickable::leftMargin
1553     \qmlproperty real QtQuick2::Flickable::bottomMargin
1554     \qmlproperty real QtQuick2::Flickable::rightMargin
1555
1556     These properties hold the margins around the content.  This space is reserved
1557     in addition to the contentWidth and contentHeight.
1558 */
1559
1560
1561 qreal QQuickFlickable::topMargin() const
1562 {
1563     Q_D(const QQuickFlickable);
1564     return d->vData.startMargin;
1565 }
1566
1567 void QQuickFlickable::setTopMargin(qreal m)
1568 {
1569     Q_D(QQuickFlickable);
1570     if (d->vData.startMargin == m)
1571         return;
1572     d->vData.startMargin = m;
1573     d->vData.markExtentsDirty();
1574     if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1575         d->fixupMode = QQuickFlickablePrivate::Immediate;
1576         d->fixupY();
1577     }
1578     emit topMarginChanged();
1579     d->updateBeginningEnd();
1580 }
1581
1582 qreal QQuickFlickable::bottomMargin() const
1583 {
1584     Q_D(const QQuickFlickable);
1585     return d->vData.endMargin;
1586 }
1587
1588 void QQuickFlickable::setBottomMargin(qreal m)
1589 {
1590     Q_D(QQuickFlickable);
1591     if (d->vData.endMargin == m)
1592         return;
1593     d->vData.endMargin = m;
1594     d->vData.markExtentsDirty();
1595     if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1596         d->fixupMode = QQuickFlickablePrivate::Immediate;
1597         d->fixupY();
1598     }
1599     emit bottomMarginChanged();
1600     d->updateBeginningEnd();
1601 }
1602
1603 qreal QQuickFlickable::leftMargin() const
1604 {
1605     Q_D(const QQuickFlickable);
1606     return d->hData.startMargin;
1607 }
1608
1609 void QQuickFlickable::setLeftMargin(qreal m)
1610 {
1611     Q_D(QQuickFlickable);
1612     if (d->hData.startMargin == m)
1613         return;
1614     d->hData.startMargin = m;
1615     d->hData.markExtentsDirty();
1616     if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1617         d->fixupMode = QQuickFlickablePrivate::Immediate;
1618         d->fixupX();
1619     }
1620     emit leftMarginChanged();
1621     d->updateBeginningEnd();
1622 }
1623
1624 qreal QQuickFlickable::rightMargin() const
1625 {
1626     Q_D(const QQuickFlickable);
1627     return d->hData.endMargin;
1628 }
1629
1630 void QQuickFlickable::setRightMargin(qreal m)
1631 {
1632     Q_D(QQuickFlickable);
1633     if (d->hData.endMargin == m)
1634         return;
1635     d->hData.endMargin = m;
1636     d->hData.markExtentsDirty();
1637     if (!d->pressed && !d->hData.moving && !d->vData.moving) {
1638         d->fixupMode = QQuickFlickablePrivate::Immediate;
1639         d->fixupX();
1640     }
1641     emit rightMarginChanged();
1642     d->updateBeginningEnd();
1643 }
1644
1645 /*!
1646     \qmlproperty real QtQuick2::Flickable::xOrigin
1647     \qmlproperty real QtQuick2::Flickable::yOrigin
1648
1649     These properties hold the origin of the content.  This is usually (0,0), however
1650     ListView and GridView may have an arbitrary origin due to delegate size variation,
1651     or item insertion/removal outside the visible region.
1652 */
1653
1654 qreal QQuickFlickable::yOrigin() const
1655 {
1656     Q_D(const QQuickFlickable);
1657     return -minYExtent() + d->vData.startMargin;
1658 }
1659
1660 qreal QQuickFlickable::xOrigin() const
1661 {
1662     Q_D(const QQuickFlickable);
1663     return -minXExtent() + d->hData.startMargin;
1664 }
1665
1666
1667 /*!
1668     \qmlmethod QtQuick2::Flickable::resizeContent(real width, real height, QPointF center)
1669
1670     Resizes the content to \a width x \a height about \a center.
1671
1672     This does not scale the contents of the Flickable - it only resizes the \l contentWidth
1673     and \l contentHeight.
1674
1675     Resizing the content may result in the content being positioned outside
1676     the bounds of the Flickable.  Calling \l returnToBounds() will
1677     move the content back within legal bounds.
1678 */
1679 void QQuickFlickable::resizeContent(qreal w, qreal h, QPointF center)
1680 {
1681     Q_D(QQuickFlickable);
1682     if (w != d->hData.viewSize) {
1683         qreal oldSize = d->hData.viewSize;
1684         d->hData.viewSize = w;
1685         d->contentItem->setWidth(w);
1686         emit contentWidthChanged();
1687         if (center.x() != 0) {
1688             qreal pos = center.x() * w / oldSize;
1689             setContentX(contentX() + pos - center.x());
1690         }
1691     }
1692     if (h != d->vData.viewSize) {
1693         qreal oldSize = d->vData.viewSize;
1694         d->vData.viewSize = h;
1695         d->contentItem->setHeight(h);
1696         emit contentHeightChanged();
1697         if (center.y() != 0) {
1698             qreal pos = center.y() * h / oldSize;
1699             setContentY(contentY() + pos - center.y());
1700         }
1701     }
1702     d->updateBeginningEnd();
1703 }
1704
1705 /*!
1706     \qmlmethod QtQuick2::Flickable::returnToBounds()
1707
1708     Ensures the content is within legal bounds.
1709
1710     This may be called to ensure that the content is within legal bounds
1711     after manually positioning the content.
1712 */
1713 void QQuickFlickable::returnToBounds()
1714 {
1715     Q_D(QQuickFlickable);
1716     d->fixupX();
1717     d->fixupY();
1718 }
1719
1720 qreal QQuickFlickable::vWidth() const
1721 {
1722     Q_D(const QQuickFlickable);
1723     if (d->hData.viewSize < 0)
1724         return width();
1725     else
1726         return d->hData.viewSize;
1727 }
1728
1729 qreal QQuickFlickable::vHeight() const
1730 {
1731     Q_D(const QQuickFlickable);
1732     if (d->vData.viewSize < 0)
1733         return height();
1734     else
1735         return d->vData.viewSize;
1736 }
1737
1738 bool QQuickFlickable::xflick() const
1739 {
1740     Q_D(const QQuickFlickable);
1741     if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
1742         return vWidth() != width();
1743     return d->flickableDirection & QQuickFlickable::HorizontalFlick;
1744 }
1745
1746 bool QQuickFlickable::yflick() const
1747 {
1748     Q_D(const QQuickFlickable);
1749     if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
1750         return vHeight() !=  height();
1751     return d->flickableDirection & QQuickFlickable::VerticalFlick;
1752 }
1753
1754 void QQuickFlickable::mouseUngrabEvent()
1755 {
1756     Q_D(QQuickFlickable);
1757     if (d->pressed) {
1758         // if our mouse grab has been removed (probably by another Flickable),
1759         // fix our state
1760         d->clearDelayedPress();
1761         d->pressed = false;
1762         d->draggingEnding();
1763         d->stealMouse = false;
1764         setKeepMouseGrab(false);
1765         d->fixupX();
1766         d->fixupY();
1767         if (!d->timeline.isActive())
1768             movementEnding();
1769     }
1770 }
1771
1772 bool QQuickFlickable::sendMouseEvent(QMouseEvent *event)
1773 {
1774     Q_D(QQuickFlickable);
1775     QPointF localPos = mapFromScene(event->windowPos());
1776
1777     QQuickCanvas *c = canvas();
1778     QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
1779     bool disabledItem = grabber && !grabber->isEnabled();
1780     bool stealThisEvent = d->stealMouse;
1781     if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
1782         QQuickMouseEventEx mouseEvent(event->type(), localPos,
1783                                 event->windowPos(), event->screenPos(),
1784                                 event->button(), event->buttons(), event->modifiers());
1785         QQuickMouseEventEx *eventEx = QQuickMouseEventEx::extended(event);
1786         if (eventEx) {
1787             mouseEvent.setVelocity(eventEx->velocity());
1788             mouseEvent.setCapabilities(eventEx->capabilities());
1789         }
1790         mouseEvent.setTimestamp(event->timestamp());
1791         mouseEvent.setAccepted(false);
1792
1793         switch (mouseEvent.type()) {
1794         case QEvent::MouseMove:
1795             d->handleMouseMoveEvent(&mouseEvent);
1796             break;
1797         case QEvent::MouseButtonPress:
1798             if (d->pressed) // we are already pressed - this is a delayed replay
1799                 return false;
1800
1801             d->handleMousePressEvent(&mouseEvent);
1802             d->captureDelayedPress(event);
1803             stealThisEvent = d->stealMouse;   // Update stealThisEvent in case changed by function call above
1804             break;
1805         case QEvent::MouseButtonRelease:
1806             if (d->delayedPressEvent) {
1807                 // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
1808                 // so we reset the grabber
1809                 if (c->mouseGrabberItem() == d->delayedPressTarget)
1810                     d->delayedPressTarget->ungrabMouse();
1811                 //Use the event handler that will take care of finding the proper item to propagate the event
1812                 QQuickCanvasPrivate::get(canvas())->deliverMouseEvent(d->delayedPressEvent);
1813                 d->clearDelayedPress();
1814                 // We send the release
1815                 canvas()->sendEvent(c->mouseGrabberItem(), event);
1816                 // And the event has been consumed
1817                 d->stealMouse = false;
1818                 d->pressed = false;
1819                 return true;
1820             }
1821             d->handleMouseReleaseEvent(&mouseEvent);
1822             break;
1823         default:
1824             break;
1825         }
1826         grabber = qobject_cast<QQuickItem*>(c->mouseGrabberItem());
1827         if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || disabledItem) {
1828             d->clearDelayedPress();
1829             grabMouse();
1830         }
1831
1832         return stealThisEvent || d->delayedPressEvent || disabledItem;
1833     } else if (d->lastPosTime != -1) {
1834         d->lastPosTime = -1;
1835         returnToBounds();
1836     }
1837     if (event->type() == QEvent::MouseButtonRelease) {
1838         d->lastPosTime = -1;
1839         d->clearDelayedPress();
1840         d->stealMouse = false;
1841         d->pressed = false;
1842     }
1843     return false;
1844 }
1845
1846
1847 bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
1848 {
1849     Q_D(QQuickFlickable);
1850     if (!isVisible() || !isEnabled())
1851         return QQuickItem::childMouseEventFilter(i, e);
1852     switch (e->type()) {
1853     case QEvent::MouseButtonPress:
1854     case QEvent::MouseMove:
1855     case QEvent::MouseButtonRelease:
1856         return sendMouseEvent(static_cast<QMouseEvent *>(e));
1857     case QEvent::UngrabMouse:
1858         if (d->canvas && d->canvas->mouseGrabberItem() && d->canvas->mouseGrabberItem() != this) {
1859             // The grab has been taken away from a child and given to some other item.
1860             mouseUngrabEvent();
1861         }
1862         break;
1863     default:
1864         break;
1865     }
1866
1867     return QQuickItem::childMouseEventFilter(i, e);
1868 }
1869
1870 /*!
1871     \qmlproperty real QtQuick2::Flickable::maximumFlickVelocity
1872     This property holds the maximum velocity that the user can flick the view in pixels/second.
1873
1874     The default value is platform dependent.
1875 */
1876 qreal QQuickFlickable::maximumFlickVelocity() const
1877 {
1878     Q_D(const QQuickFlickable);
1879     return d->maxVelocity;
1880 }
1881
1882 void QQuickFlickable::setMaximumFlickVelocity(qreal v)
1883 {
1884     Q_D(QQuickFlickable);
1885     if (v == d->maxVelocity)
1886         return;
1887     d->maxVelocity = v;
1888     emit maximumFlickVelocityChanged();
1889 }
1890
1891 /*!
1892     \qmlproperty real QtQuick2::Flickable::flickDeceleration
1893     This property holds the rate at which a flick will decelerate.
1894
1895     The default value is platform dependent.
1896 */
1897 qreal QQuickFlickable::flickDeceleration() const
1898 {
1899     Q_D(const QQuickFlickable);
1900     return d->deceleration;
1901 }
1902
1903 void QQuickFlickable::setFlickDeceleration(qreal deceleration)
1904 {
1905     Q_D(QQuickFlickable);
1906     if (deceleration == d->deceleration)
1907         return;
1908     d->deceleration = deceleration;
1909     emit flickDecelerationChanged();
1910 }
1911
1912 bool QQuickFlickable::isFlicking() const
1913 {
1914     Q_D(const QQuickFlickable);
1915     return d->hData.flicking ||  d->vData.flicking;
1916 }
1917
1918 /*!
1919     \qmlproperty bool QtQuick2::Flickable::flicking
1920     \qmlproperty bool QtQuick2::Flickable::flickingHorizontally
1921     \qmlproperty bool QtQuick2::Flickable::flickingVertically
1922
1923     These properties describe whether the view is currently moving horizontally,
1924     vertically or in either direction, due to the user flicking the view.
1925 */
1926 bool QQuickFlickable::isFlickingHorizontally() const
1927 {
1928     Q_D(const QQuickFlickable);
1929     return d->hData.flicking;
1930 }
1931
1932 bool QQuickFlickable::isFlickingVertically() const
1933 {
1934     Q_D(const QQuickFlickable);
1935     return d->vData.flicking;
1936 }
1937
1938 /*!
1939     \qmlproperty bool QtQuick2::Flickable::dragging
1940     \qmlproperty bool QtQuick2::Flickable::draggingHorizontally
1941     \qmlproperty bool QtQuick2::Flickable::draggingVertically
1942
1943     These properties describe whether the view is currently moving horizontally,
1944     vertically or in either direction, due to the user dragging the view.
1945 */
1946 bool QQuickFlickable::isDragging() const
1947 {
1948     Q_D(const QQuickFlickable);
1949     return d->hData.dragging ||  d->vData.dragging;
1950 }
1951
1952 bool QQuickFlickable::isDraggingHorizontally() const
1953 {
1954     Q_D(const QQuickFlickable);
1955     return d->hData.dragging;
1956 }
1957
1958 bool QQuickFlickable::isDraggingVertically() const
1959 {
1960     Q_D(const QQuickFlickable);
1961     return d->vData.dragging;
1962 }
1963
1964 void QQuickFlickablePrivate::draggingStarting()
1965 {
1966     Q_Q(QQuickFlickable);
1967     bool wasDragging = hData.dragging || vData.dragging;
1968     if (hMoved && !hData.dragging) {
1969         hData.dragging = true;
1970         emit q->draggingHorizontallyChanged();
1971     }
1972     if (vMoved && !vData.dragging) {
1973         vData.dragging = true;
1974         emit q->draggingVerticallyChanged();
1975     }
1976     if (!wasDragging && (hData.dragging || vData.dragging)) {
1977         emit q->draggingChanged();
1978         emit q->dragStarted();
1979     }
1980 }
1981
1982 void QQuickFlickablePrivate::draggingEnding()
1983 {
1984     Q_Q(QQuickFlickable);
1985     bool wasDragging = hData.dragging || vData.dragging;
1986     if (hData.dragging) {
1987         hData.dragging = false;
1988         emit q->draggingHorizontallyChanged();
1989     }
1990     if (vData.dragging) {
1991         vData.dragging = false;
1992         emit q->draggingVerticallyChanged();
1993     }
1994     if (wasDragging && !hData.dragging && !vData.dragging) {
1995         emit q->draggingChanged();
1996         emit q->dragEnded();
1997     }
1998 }
1999
2000 /*!
2001     \qmlproperty int QtQuick2::Flickable::pressDelay
2002
2003     This property holds the time to delay (ms) delivering a press to
2004     children of the Flickable.  This can be useful where reacting
2005     to a press before a flicking action has undesirable effects.
2006
2007     If the flickable is dragged/flicked before the delay times out
2008     the press event will not be delivered.  If the button is released
2009     within the timeout, both the press and release will be delivered.
2010
2011     Note that for nested Flickables with pressDelay set, the pressDelay of
2012     inner Flickables is overridden by the outermost Flickable.
2013 */
2014 int QQuickFlickable::pressDelay() const
2015 {
2016     Q_D(const QQuickFlickable);
2017     return d->pressDelay;
2018 }
2019
2020 void QQuickFlickable::setPressDelay(int delay)
2021 {
2022     Q_D(QQuickFlickable);
2023     if (d->pressDelay == delay)
2024         return;
2025     d->pressDelay = delay;
2026     emit pressDelayChanged();
2027 }
2028
2029 /*!
2030     \qmlproperty bool QtQuick2::Flickable::moving
2031     \qmlproperty bool QtQuick2::Flickable::movingHorizontally
2032     \qmlproperty bool QtQuick2::Flickable::movingVertically
2033
2034     These properties describe whether the view is currently moving horizontally,
2035     vertically or in either direction, due to the user either dragging or
2036     flicking the view.
2037 */
2038
2039 bool QQuickFlickable::isMoving() const
2040 {
2041     Q_D(const QQuickFlickable);
2042     return d->hData.moving || d->vData.moving;
2043 }
2044
2045 bool QQuickFlickable::isMovingHorizontally() const
2046 {
2047     Q_D(const QQuickFlickable);
2048     return d->hData.moving;
2049 }
2050
2051 bool QQuickFlickable::isMovingVertically() const
2052 {
2053     Q_D(const QQuickFlickable);
2054     return d->vData.moving;
2055 }
2056
2057 void QQuickFlickable::movementStarting()
2058 {
2059     Q_D(QQuickFlickable);
2060     if (d->hMoved && !d->hData.moving) {
2061         d->hData.moving = true;
2062         emit movingChanged();
2063         emit movingHorizontallyChanged();
2064         if (!d->vData.moving)
2065             emit movementStarted();
2066     }
2067     else if (d->vMoved && !d->vData.moving) {
2068         d->vData.moving = true;
2069         emit movingChanged();
2070         emit movingVerticallyChanged();
2071         if (!d->hData.moving)
2072             emit movementStarted();
2073     }
2074 }
2075
2076 void QQuickFlickable::movementEnding()
2077 {
2078     Q_D(QQuickFlickable);
2079     movementXEnding();
2080     movementYEnding();
2081     d->hData.smoothVelocity.setValue(0);
2082     d->vData.smoothVelocity.setValue(0);
2083 }
2084
2085 void QQuickFlickable::movementXEnding()
2086 {
2087     Q_D(QQuickFlickable);
2088     if (d->hData.flicking) {
2089         d->hData.flicking = false;
2090         emit flickingChanged();
2091         emit flickingHorizontallyChanged();
2092         if (!d->vData.flicking)
2093            emit flickEnded();
2094     }
2095     if (!d->pressed && !d->stealMouse) {
2096         if (d->hData.moving) {
2097             d->hData.moving = false;
2098             d->hMoved = false;
2099             emit movingChanged();
2100             emit movingHorizontallyChanged();
2101             if (!d->vData.moving)
2102                 emit movementEnded();
2103         }
2104     }
2105     d->hData.fixingUp = false;
2106 }
2107
2108 void QQuickFlickable::movementYEnding()
2109 {
2110     Q_D(QQuickFlickable);
2111     if (d->vData.flicking) {
2112         d->vData.flicking = false;
2113         emit flickingChanged();
2114         emit flickingVerticallyChanged();
2115         if (!d->hData.flicking)
2116            emit flickEnded();
2117     }
2118     if (!d->pressed && !d->stealMouse) {
2119         if (d->vData.moving) {
2120             d->vData.moving = false;
2121             d->vMoved = false;
2122             emit movingChanged();
2123             emit movingVerticallyChanged();
2124             if (!d->hData.moving)
2125                 emit movementEnded();
2126         }
2127     }
2128     d->vData.fixingUp = false;
2129 }
2130
2131 void QQuickFlickablePrivate::updateVelocity()
2132 {
2133     Q_Q(QQuickFlickable);
2134     emit q->horizontalVelocityChanged();
2135     emit q->verticalVelocityChanged();
2136 }
2137
2138 QT_END_NAMESPACE