1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation (qt-info@nokia.com)
|
---|
6 | **
|
---|
7 | ** This file is part of the QtDeclarative module of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at qt-info@nokia.com.
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include "private/qdeclarativeflickable_p.h"
|
---|
43 | #include "private/qdeclarativeflickable_p_p.h"
|
---|
44 | #include <qdeclarativeinfo.h>
|
---|
45 | #include <QGraphicsSceneMouseEvent>
|
---|
46 | #include <QPointer>
|
---|
47 | #include <QTimer>
|
---|
48 |
|
---|
49 | QT_BEGIN_NAMESPACE
|
---|
50 |
|
---|
51 |
|
---|
52 | // FlickThreshold determines how far the "mouse" must have moved
|
---|
53 | // before we perform a flick.
|
---|
54 | static const int FlickThreshold = 20;
|
---|
55 |
|
---|
56 | QDeclarativeFlickableVisibleArea::QDeclarativeFlickableVisibleArea(QDeclarativeFlickable *parent)
|
---|
57 | : QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
|
---|
58 | , m_yPosition(0.), m_heightRatio(0.)
|
---|
59 | {
|
---|
60 | }
|
---|
61 |
|
---|
62 | qreal QDeclarativeFlickableVisibleArea::widthRatio() const
|
---|
63 | {
|
---|
64 | return m_widthRatio;
|
---|
65 | }
|
---|
66 |
|
---|
67 | qreal QDeclarativeFlickableVisibleArea::xPosition() const
|
---|
68 | {
|
---|
69 | return m_xPosition;
|
---|
70 | }
|
---|
71 |
|
---|
72 | qreal QDeclarativeFlickableVisibleArea::heightRatio() const
|
---|
73 | {
|
---|
74 | return m_heightRatio;
|
---|
75 | }
|
---|
76 |
|
---|
77 | qreal QDeclarativeFlickableVisibleArea::yPosition() const
|
---|
78 | {
|
---|
79 | return m_yPosition;
|
---|
80 | }
|
---|
81 |
|
---|
82 | void QDeclarativeFlickableVisibleArea::updateVisible()
|
---|
83 | {
|
---|
84 | QDeclarativeFlickablePrivate *p = static_cast<QDeclarativeFlickablePrivate *>(QGraphicsItemPrivate::get(flickable));
|
---|
85 |
|
---|
86 | bool changeX = false;
|
---|
87 | bool changeY = false;
|
---|
88 | bool changeWidth = false;
|
---|
89 | bool changeHeight = false;
|
---|
90 |
|
---|
91 | // Vertical
|
---|
92 | const qreal viewheight = flickable->height();
|
---|
93 | const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent();
|
---|
94 | qreal pagePos = (-p->vData.move.value() + flickable->minYExtent()) / (maxyextent + viewheight);
|
---|
95 | qreal pageSize = viewheight / (maxyextent + viewheight);
|
---|
96 |
|
---|
97 | if (pageSize != m_heightRatio) {
|
---|
98 | m_heightRatio = pageSize;
|
---|
99 | changeHeight = true;
|
---|
100 | }
|
---|
101 | if (pagePos != m_yPosition) {
|
---|
102 | m_yPosition = pagePos;
|
---|
103 | changeY = true;
|
---|
104 | }
|
---|
105 |
|
---|
106 | // Horizontal
|
---|
107 | const qreal viewwidth = flickable->width();
|
---|
108 | const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
|
---|
109 | pagePos = (-p->hData.move.value() + flickable->minXExtent()) / (maxxextent + viewwidth);
|
---|
110 | pageSize = viewwidth / (maxxextent + viewwidth);
|
---|
111 |
|
---|
112 | if (pageSize != m_widthRatio) {
|
---|
113 | m_widthRatio = pageSize;
|
---|
114 | changeWidth = true;
|
---|
115 | }
|
---|
116 | if (pagePos != m_xPosition) {
|
---|
117 | m_xPosition = pagePos;
|
---|
118 | changeX = true;
|
---|
119 | }
|
---|
120 |
|
---|
121 | if (changeX)
|
---|
122 | emit xPositionChanged(m_xPosition);
|
---|
123 | if (changeY)
|
---|
124 | emit yPositionChanged(m_yPosition);
|
---|
125 | if (changeWidth)
|
---|
126 | emit widthRatioChanged(m_widthRatio);
|
---|
127 | if (changeHeight)
|
---|
128 | emit heightRatioChanged(m_heightRatio);
|
---|
129 | }
|
---|
130 |
|
---|
131 |
|
---|
132 | QDeclarativeFlickablePrivate::QDeclarativeFlickablePrivate()
|
---|
133 | : contentItem(new QDeclarativeItem)
|
---|
134 | , hData(this, &QDeclarativeFlickablePrivate::setRoundedViewportX)
|
---|
135 | , vData(this, &QDeclarativeFlickablePrivate::setRoundedViewportY)
|
---|
136 | , flickingHorizontally(false), flickingVertically(false)
|
---|
137 | , hMoved(false), vMoved(false)
|
---|
138 | , movingHorizontally(false), movingVertically(false)
|
---|
139 | , stealMouse(false), pressed(false), interactive(true), calcVelocity(false)
|
---|
140 | , deceleration(500), maxVelocity(2000), reportedVelocitySmoothing(100)
|
---|
141 | , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(600)
|
---|
142 | , vTime(0), visibleArea(0)
|
---|
143 | , flickableDirection(QDeclarativeFlickable::AutoFlickDirection)
|
---|
144 | , boundsBehavior(QDeclarativeFlickable::DragAndOvershootBounds)
|
---|
145 | {
|
---|
146 | }
|
---|
147 |
|
---|
148 | void QDeclarativeFlickablePrivate::init()
|
---|
149 | {
|
---|
150 | Q_Q(QDeclarativeFlickable);
|
---|
151 | QDeclarative_setParent_noEvent(contentItem, q);
|
---|
152 | contentItem->setParentItem(q);
|
---|
153 | static int timelineUpdatedIdx = -1;
|
---|
154 | static int timelineCompletedIdx = -1;
|
---|
155 | static int flickableTickedIdx = -1;
|
---|
156 | static int flickableMovementEndingIdx = -1;
|
---|
157 | if (timelineUpdatedIdx == -1) {
|
---|
158 | timelineUpdatedIdx = QDeclarativeTimeLine::staticMetaObject.indexOfSignal("updated()");
|
---|
159 | timelineCompletedIdx = QDeclarativeTimeLine::staticMetaObject.indexOfSignal("completed()");
|
---|
160 | flickableTickedIdx = QDeclarativeFlickable::staticMetaObject.indexOfSlot("ticked()");
|
---|
161 | flickableMovementEndingIdx = QDeclarativeFlickable::staticMetaObject.indexOfSlot("movementEnding()");
|
---|
162 | }
|
---|
163 | QMetaObject::connect(&timeline, timelineUpdatedIdx,
|
---|
164 | q, flickableTickedIdx, Qt::DirectConnection);
|
---|
165 | QMetaObject::connect(&timeline, timelineCompletedIdx,
|
---|
166 | q, flickableMovementEndingIdx, Qt::DirectConnection);
|
---|
167 | q->setAcceptedMouseButtons(Qt::LeftButton);
|
---|
168 | q->setFiltersChildEvents(true);
|
---|
169 | QDeclarativeItemPrivate *viewportPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(contentItem));
|
---|
170 | viewportPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
|
---|
171 | lastPosTime.invalidate();
|
---|
172 | }
|
---|
173 |
|
---|
174 | /*
|
---|
175 | Returns the amount to overshoot by given a velocity.
|
---|
176 | Will be roughly in range 0 - size/4
|
---|
177 | */
|
---|
178 | qreal QDeclarativeFlickablePrivate::overShootDistance(qreal velocity, qreal size)
|
---|
179 | {
|
---|
180 | if (maxVelocity <= 0)
|
---|
181 | return 0.0;
|
---|
182 |
|
---|
183 | velocity = qAbs(velocity);
|
---|
184 | if (velocity > maxVelocity)
|
---|
185 | velocity = maxVelocity;
|
---|
186 | qreal dist = size / 4 * velocity / maxVelocity;
|
---|
187 | return dist;
|
---|
188 | }
|
---|
189 |
|
---|
190 | void QDeclarativeFlickablePrivate::itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeom, const QRectF &oldGeom)
|
---|
191 | {
|
---|
192 | Q_Q(QDeclarativeFlickable);
|
---|
193 | if (item == contentItem) {
|
---|
194 | if (newGeom.x() != oldGeom.x())
|
---|
195 | emit q->contentXChanged();
|
---|
196 | if (newGeom.y() != oldGeom.y())
|
---|
197 | emit q->contentYChanged();
|
---|
198 | }
|
---|
199 | }
|
---|
200 |
|
---|
201 | void QDeclarativeFlickablePrivate::flickX(qreal velocity)
|
---|
202 | {
|
---|
203 | Q_Q(QDeclarativeFlickable);
|
---|
204 | flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, velocity);
|
---|
205 | }
|
---|
206 |
|
---|
207 | void QDeclarativeFlickablePrivate::flickY(qreal velocity)
|
---|
208 | {
|
---|
209 | Q_Q(QDeclarativeFlickable);
|
---|
210 | flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, velocity);
|
---|
211 | }
|
---|
212 |
|
---|
213 | void QDeclarativeFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
|
---|
214 | QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
|
---|
215 | {
|
---|
216 | Q_Q(QDeclarativeFlickable);
|
---|
217 | qreal maxDistance = -1;
|
---|
218 | bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds;
|
---|
219 | // -ve velocity means list is moving up
|
---|
220 | if (velocity > 0) {
|
---|
221 | if (data.move.value() < minExtent)
|
---|
222 | maxDistance = qAbs(minExtent - data.move.value() + (overShoot?overShootDistance(velocity,vSize):0));
|
---|
223 | data.flickTarget = minExtent;
|
---|
224 | } else {
|
---|
225 | if (data.move.value() > maxExtent)
|
---|
226 | maxDistance = qAbs(maxExtent - data.move.value()) + (overShoot?overShootDistance(velocity,vSize):0);
|
---|
227 | data.flickTarget = maxExtent;
|
---|
228 | }
|
---|
229 | if (maxDistance > 0) {
|
---|
230 | qreal v = velocity;
|
---|
231 | if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
|
---|
232 | if (v < 0)
|
---|
233 | v = -maxVelocity;
|
---|
234 | else
|
---|
235 | v = maxVelocity;
|
---|
236 | }
|
---|
237 | timeline.reset(data.move);
|
---|
238 | timeline.accel(data.move, v, deceleration, maxDistance);
|
---|
239 | timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
|
---|
240 | if (!flickingHorizontally && q->xflick()) {
|
---|
241 | flickingHorizontally = true;
|
---|
242 | emit q->flickingChanged();
|
---|
243 | emit q->flickingHorizontallyChanged();
|
---|
244 | if (!flickingVertically)
|
---|
245 | emit q->flickStarted();
|
---|
246 | }
|
---|
247 | if (!flickingVertically && q->yflick()) {
|
---|
248 | flickingVertically = true;
|
---|
249 | emit q->flickingChanged();
|
---|
250 | emit q->flickingVerticallyChanged();
|
---|
251 | if (!flickingHorizontally)
|
---|
252 | emit q->flickStarted();
|
---|
253 | }
|
---|
254 | } else {
|
---|
255 | timeline.reset(data.move);
|
---|
256 | fixup(data, minExtent, maxExtent);
|
---|
257 | }
|
---|
258 | }
|
---|
259 |
|
---|
260 | void QDeclarativeFlickablePrivate::fixupY_callback(void *data)
|
---|
261 | {
|
---|
262 | ((QDeclarativeFlickablePrivate *)data)->fixupY();
|
---|
263 | }
|
---|
264 |
|
---|
265 | void QDeclarativeFlickablePrivate::fixupX_callback(void *data)
|
---|
266 | {
|
---|
267 | ((QDeclarativeFlickablePrivate *)data)->fixupX();
|
---|
268 | }
|
---|
269 |
|
---|
270 | void QDeclarativeFlickablePrivate::fixupX()
|
---|
271 | {
|
---|
272 | Q_Q(QDeclarativeFlickable);
|
---|
273 | fixup(hData, q->minXExtent(), q->maxXExtent());
|
---|
274 | }
|
---|
275 |
|
---|
276 | void QDeclarativeFlickablePrivate::fixupY()
|
---|
277 | {
|
---|
278 | Q_Q(QDeclarativeFlickable);
|
---|
279 | fixup(vData, q->minYExtent(), q->maxYExtent());
|
---|
280 | }
|
---|
281 |
|
---|
282 | void QDeclarativeFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
|
---|
283 | {
|
---|
284 | if (data.move.value() > minExtent || maxExtent > minExtent) {
|
---|
285 | timeline.reset(data.move);
|
---|
286 | if (data.move.value() != minExtent) {
|
---|
287 | if (fixupDuration) {
|
---|
288 | qreal dist = minExtent - data.move;
|
---|
289 | timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
|
---|
290 | timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
|
---|
291 | } else {
|
---|
292 | timeline.set(data.move, minExtent);
|
---|
293 | }
|
---|
294 | }
|
---|
295 | } else if (data.move.value() < maxExtent) {
|
---|
296 | timeline.reset(data.move);
|
---|
297 | if (fixupDuration) {
|
---|
298 | qreal dist = maxExtent - data.move;
|
---|
299 | timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
|
---|
300 | timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
|
---|
301 | } else {
|
---|
302 | timeline.set(data.move, maxExtent);
|
---|
303 | }
|
---|
304 | }
|
---|
305 | vTime = timeline.time();
|
---|
306 | }
|
---|
307 |
|
---|
308 | void QDeclarativeFlickablePrivate::updateBeginningEnd()
|
---|
309 | {
|
---|
310 | Q_Q(QDeclarativeFlickable);
|
---|
311 | bool atBoundaryChange = false;
|
---|
312 |
|
---|
313 | // Vertical
|
---|
314 | const int maxyextent = int(-q->maxYExtent());
|
---|
315 | const qreal ypos = -vData.move.value();
|
---|
316 | bool atBeginning = (ypos <= -q->minYExtent());
|
---|
317 | bool atEnd = (maxyextent <= ypos);
|
---|
318 |
|
---|
319 | if (atBeginning != vData.atBeginning) {
|
---|
320 | vData.atBeginning = atBeginning;
|
---|
321 | atBoundaryChange = true;
|
---|
322 | }
|
---|
323 | if (atEnd != vData.atEnd) {
|
---|
324 | vData.atEnd = atEnd;
|
---|
325 | atBoundaryChange = true;
|
---|
326 | }
|
---|
327 |
|
---|
328 | // Horizontal
|
---|
329 | const int maxxextent = int(-q->maxXExtent());
|
---|
330 | const qreal xpos = -hData.move.value();
|
---|
331 | atBeginning = (xpos <= -q->minXExtent());
|
---|
332 | atEnd = (maxxextent <= xpos);
|
---|
333 |
|
---|
334 | if (atBeginning != hData.atBeginning) {
|
---|
335 | hData.atBeginning = atBeginning;
|
---|
336 | atBoundaryChange = true;
|
---|
337 | }
|
---|
338 | if (atEnd != hData.atEnd) {
|
---|
339 | hData.atEnd = atEnd;
|
---|
340 | atBoundaryChange = true;
|
---|
341 | }
|
---|
342 |
|
---|
343 | if (atBoundaryChange)
|
---|
344 | emit q->isAtBoundaryChanged();
|
---|
345 |
|
---|
346 | if (visibleArea)
|
---|
347 | visibleArea->updateVisible();
|
---|
348 | }
|
---|
349 |
|
---|
350 | /*!
|
---|
351 | \qmlclass Flickable QDeclarativeFlickable
|
---|
352 | \since 4.7
|
---|
353 | \ingroup qml-basic-interaction-elements
|
---|
354 |
|
---|
355 | \brief The Flickable item provides a surface that can be "flicked".
|
---|
356 | \inherits Item
|
---|
357 |
|
---|
358 | The Flickable item places its children on a surface that can be dragged
|
---|
359 | and flicked, causing the view onto the child items to scroll. This
|
---|
360 | behavior forms the basis of Items that are designed to show large numbers
|
---|
361 | of child items, such as \l ListView and \l GridView.
|
---|
362 |
|
---|
363 | In traditional user interfaces, views can be scrolled using standard
|
---|
364 | controls, such as scroll bars and arrow buttons. In some situations, it
|
---|
365 | is also possible to drag the view directly by pressing and holding a
|
---|
366 | mouse button while moving the cursor. In touch-based user interfaces,
|
---|
367 | this dragging action is often complemented with a flicking action, where
|
---|
368 | scrolling continues after the user has stopped touching the view.
|
---|
369 |
|
---|
370 | Flickable does not automatically clip its contents. If it is not used as
|
---|
371 | a full-screen item, you should consider setting the \l{Item::}{clip} property
|
---|
372 | to true.
|
---|
373 |
|
---|
374 | \section1 Example Usage
|
---|
375 |
|
---|
376 | \beginfloatright
|
---|
377 | \inlineimage flickable.gif
|
---|
378 | \endfloat
|
---|
379 |
|
---|
380 | The following example shows a small view onto a large image in which the
|
---|
381 | user can drag or flick the image in order to view different parts of it.
|
---|
382 |
|
---|
383 | \snippet doc/src/snippets/declarative/flickable.qml document
|
---|
384 |
|
---|
385 | \clearfloat
|
---|
386 |
|
---|
387 | Items declared as children of a Flickable are automatically parented to the
|
---|
388 | Flickable's \l contentItem. This should be taken into account when
|
---|
389 | operating on the children of the Flickable; it is usually the children of
|
---|
390 | \c contentItem that are relevant. For example, the bound of Items added
|
---|
391 | to the Flickable will be available by \c contentItem.childrenRect
|
---|
392 |
|
---|
393 | \section1 Limitations
|
---|
394 |
|
---|
395 | \note Due to an implementation detail, items placed inside a Flickable cannot anchor to it by
|
---|
396 | \c id. Use \c parent instead.
|
---|
397 | */
|
---|
398 |
|
---|
399 | /*!
|
---|
400 | \qmlsignal Flickable::onMovementStarted()
|
---|
401 |
|
---|
402 | This handler is called when the view begins moving due to user
|
---|
403 | interaction.
|
---|
404 | */
|
---|
405 |
|
---|
406 | /*!
|
---|
407 | \qmlsignal Flickable::onMovementEnded()
|
---|
408 |
|
---|
409 | This handler is called when the view stops moving due to user
|
---|
410 | interaction. If a flick was generated, this handler will
|
---|
411 | be triggered once the flick stops. If a flick was not
|
---|
412 | generated, the handler will be triggered when the
|
---|
413 | user stops dragging - i.e. a mouse or touch release.
|
---|
414 | */
|
---|
415 |
|
---|
416 | /*!
|
---|
417 | \qmlsignal Flickable::onFlickStarted()
|
---|
418 |
|
---|
419 | This handler is called when the view is flicked. A flick
|
---|
420 | starts from the point that the mouse or touch is released,
|
---|
421 | while still in motion.
|
---|
422 | */
|
---|
423 |
|
---|
424 | /*!
|
---|
425 | \qmlsignal Flickable::onFlickEnded()
|
---|
426 |
|
---|
427 | This handler is called when the view stops moving due to a flick.
|
---|
428 | */
|
---|
429 |
|
---|
430 | /*!
|
---|
431 | \qmlproperty real Flickable::visibleArea.xPosition
|
---|
432 | \qmlproperty real Flickable::visibleArea.widthRatio
|
---|
433 | \qmlproperty real Flickable::visibleArea.yPosition
|
---|
434 | \qmlproperty real Flickable::visibleArea.heightRatio
|
---|
435 |
|
---|
436 | These properties describe the position and size of the currently viewed area.
|
---|
437 | The size is defined as the percentage of the full view currently visible,
|
---|
438 | scaled to 0.0 - 1.0. The page position is usually in the range 0.0 (beginning) to
|
---|
439 | 1.0 minus size ratio (end), i.e. \c yPosition is in the range 0.0 to 1.0-\c heightRatio.
|
---|
440 | However, it is possible for the contents to be dragged outside of the normal
|
---|
441 | range, resulting in the page positions also being outside the normal range.
|
---|
442 |
|
---|
443 | These properties are typically used to draw a scrollbar. For example:
|
---|
444 |
|
---|
445 | \snippet doc/src/snippets/declarative/flickableScrollbar.qml 0
|
---|
446 | \dots 8
|
---|
447 | \snippet doc/src/snippets/declarative/flickableScrollbar.qml 1
|
---|
448 |
|
---|
449 | \sa {declarative/ui-components/scrollbar}{scrollbar example}
|
---|
450 | */
|
---|
451 |
|
---|
452 | QDeclarativeFlickable::QDeclarativeFlickable(QDeclarativeItem *parent)
|
---|
453 | : QDeclarativeItem(*(new QDeclarativeFlickablePrivate), parent)
|
---|
454 | {
|
---|
455 | Q_D(QDeclarativeFlickable);
|
---|
456 | d->init();
|
---|
457 | }
|
---|
458 |
|
---|
459 | QDeclarativeFlickable::QDeclarativeFlickable(QDeclarativeFlickablePrivate &dd, QDeclarativeItem *parent)
|
---|
460 | : QDeclarativeItem(dd, parent)
|
---|
461 | {
|
---|
462 | Q_D(QDeclarativeFlickable);
|
---|
463 | d->init();
|
---|
464 | }
|
---|
465 |
|
---|
466 | QDeclarativeFlickable::~QDeclarativeFlickable()
|
---|
467 | {
|
---|
468 | }
|
---|
469 |
|
---|
470 | /*!
|
---|
471 | \qmlproperty real Flickable::contentX
|
---|
472 | \qmlproperty real Flickable::contentY
|
---|
473 |
|
---|
474 | These properties hold the surface coordinate currently at the top-left
|
---|
475 | corner of the Flickable. For example, if you flick an image up 100 pixels,
|
---|
476 | \c contentY will be 100.
|
---|
477 | */
|
---|
478 | qreal QDeclarativeFlickable::contentX() const
|
---|
479 | {
|
---|
480 | Q_D(const QDeclarativeFlickable);
|
---|
481 | return -d->contentItem->x();
|
---|
482 | }
|
---|
483 |
|
---|
484 | void QDeclarativeFlickable::setContentX(qreal pos)
|
---|
485 | {
|
---|
486 | Q_D(QDeclarativeFlickable);
|
---|
487 | d->timeline.reset(d->hData.move);
|
---|
488 | d->vTime = d->timeline.time();
|
---|
489 | movementXEnding();
|
---|
490 | if (-pos != d->hData.move.value()) {
|
---|
491 | d->hData.move.setValue(-pos);
|
---|
492 | viewportMoved();
|
---|
493 | }
|
---|
494 | }
|
---|
495 |
|
---|
496 | qreal QDeclarativeFlickable::contentY() const
|
---|
497 | {
|
---|
498 | Q_D(const QDeclarativeFlickable);
|
---|
499 | return -d->contentItem->y();
|
---|
500 | }
|
---|
501 |
|
---|
502 | void QDeclarativeFlickable::setContentY(qreal pos)
|
---|
503 | {
|
---|
504 | Q_D(QDeclarativeFlickable);
|
---|
505 | d->timeline.reset(d->vData.move);
|
---|
506 | d->vTime = d->timeline.time();
|
---|
507 | movementYEnding();
|
---|
508 | if (-pos != d->vData.move.value()) {
|
---|
509 | d->vData.move.setValue(-pos);
|
---|
510 | viewportMoved();
|
---|
511 | }
|
---|
512 | }
|
---|
513 |
|
---|
514 | /*!
|
---|
515 | \qmlproperty bool Flickable::interactive
|
---|
516 |
|
---|
517 | This property describes whether the user can interact with the Flickable.
|
---|
518 | A user cannot drag or flick a Flickable that is not interactive.
|
---|
519 |
|
---|
520 | By default, this property is true.
|
---|
521 |
|
---|
522 | This property is useful for temporarily disabling flicking. This allows
|
---|
523 | special interaction with Flickable's children; for example, you might want
|
---|
524 | to freeze a flickable map while scrolling through a pop-up dialog that
|
---|
525 | is a child of the Flickable.
|
---|
526 | */
|
---|
527 | bool QDeclarativeFlickable::isInteractive() const
|
---|
528 | {
|
---|
529 | Q_D(const QDeclarativeFlickable);
|
---|
530 | return d->interactive;
|
---|
531 | }
|
---|
532 |
|
---|
533 | void QDeclarativeFlickable::setInteractive(bool interactive)
|
---|
534 | {
|
---|
535 | Q_D(QDeclarativeFlickable);
|
---|
536 | if (interactive != d->interactive) {
|
---|
537 | d->interactive = interactive;
|
---|
538 | if (!interactive && (d->flickingHorizontally || d->flickingVertically)) {
|
---|
539 | d->timeline.clear();
|
---|
540 | d->vTime = d->timeline.time();
|
---|
541 | d->flickingHorizontally = false;
|
---|
542 | d->flickingVertically = false;
|
---|
543 | emit flickingChanged();
|
---|
544 | emit flickingHorizontallyChanged();
|
---|
545 | emit flickingVerticallyChanged();
|
---|
546 | emit flickEnded();
|
---|
547 | }
|
---|
548 | emit interactiveChanged();
|
---|
549 | }
|
---|
550 | }
|
---|
551 |
|
---|
552 | /*!
|
---|
553 | \qmlproperty real Flickable::horizontalVelocity
|
---|
554 | \qmlproperty real Flickable::verticalVelocity
|
---|
555 |
|
---|
556 | The instantaneous velocity of movement along the x and y axes, in pixels/sec.
|
---|
557 |
|
---|
558 | The reported velocity is smoothed to avoid erratic output.
|
---|
559 | */
|
---|
560 | qreal QDeclarativeFlickable::horizontalVelocity() const
|
---|
561 | {
|
---|
562 | Q_D(const QDeclarativeFlickable);
|
---|
563 | return d->hData.smoothVelocity.value();
|
---|
564 | }
|
---|
565 |
|
---|
566 | qreal QDeclarativeFlickable::verticalVelocity() const
|
---|
567 | {
|
---|
568 | Q_D(const QDeclarativeFlickable);
|
---|
569 | return d->vData.smoothVelocity.value();
|
---|
570 | }
|
---|
571 |
|
---|
572 | /*!
|
---|
573 | \qmlproperty bool Flickable::atXBeginning
|
---|
574 | \qmlproperty bool Flickable::atXEnd
|
---|
575 | \qmlproperty bool Flickable::atYBeginning
|
---|
576 | \qmlproperty bool Flickable::atYEnd
|
---|
577 |
|
---|
578 | These properties are true if the flickable view is positioned at the beginning,
|
---|
579 | or end respecively.
|
---|
580 | */
|
---|
581 | bool QDeclarativeFlickable::isAtXEnd() const
|
---|
582 | {
|
---|
583 | Q_D(const QDeclarativeFlickable);
|
---|
584 | return d->hData.atEnd;
|
---|
585 | }
|
---|
586 |
|
---|
587 | bool QDeclarativeFlickable::isAtXBeginning() const
|
---|
588 | {
|
---|
589 | Q_D(const QDeclarativeFlickable);
|
---|
590 | return d->hData.atBeginning;
|
---|
591 | }
|
---|
592 |
|
---|
593 | bool QDeclarativeFlickable::isAtYEnd() const
|
---|
594 | {
|
---|
595 | Q_D(const QDeclarativeFlickable);
|
---|
596 | return d->vData.atEnd;
|
---|
597 | }
|
---|
598 |
|
---|
599 | bool QDeclarativeFlickable::isAtYBeginning() const
|
---|
600 | {
|
---|
601 | Q_D(const QDeclarativeFlickable);
|
---|
602 | return d->vData.atBeginning;
|
---|
603 | }
|
---|
604 |
|
---|
605 | void QDeclarativeFlickable::ticked()
|
---|
606 | {
|
---|
607 | viewportMoved();
|
---|
608 | }
|
---|
609 |
|
---|
610 | /*!
|
---|
611 | \qmlproperty Item Flickable::contentItem
|
---|
612 |
|
---|
613 | The internal item that contains the Items to be moved in the Flickable.
|
---|
614 |
|
---|
615 | Items declared as children of a Flickable are automatically parented to the Flickable's contentItem.
|
---|
616 |
|
---|
617 | Items created dynamically need to be explicitly parented to the \e contentItem:
|
---|
618 | \code
|
---|
619 | Flickable {
|
---|
620 | id: myFlickable
|
---|
621 | function addItem(file) {
|
---|
622 | var component = Qt.createComponent(file)
|
---|
623 | component.createObject(myFlickable.contentItem);
|
---|
624 | }
|
---|
625 | }
|
---|
626 | \endcode
|
---|
627 | */
|
---|
628 | QDeclarativeItem *QDeclarativeFlickable::contentItem()
|
---|
629 | {
|
---|
630 | Q_D(QDeclarativeFlickable);
|
---|
631 | return d->contentItem;
|
---|
632 | }
|
---|
633 |
|
---|
634 | QDeclarativeFlickableVisibleArea *QDeclarativeFlickable::visibleArea()
|
---|
635 | {
|
---|
636 | Q_D(QDeclarativeFlickable);
|
---|
637 | if (!d->visibleArea)
|
---|
638 | d->visibleArea = new QDeclarativeFlickableVisibleArea(this);
|
---|
639 | return d->visibleArea;
|
---|
640 | }
|
---|
641 |
|
---|
642 | /*!
|
---|
643 | \qmlproperty enumeration Flickable::flickableDirection
|
---|
644 |
|
---|
645 | This property determines which directions the view can be flicked.
|
---|
646 |
|
---|
647 | \list
|
---|
648 | \o Flickable.AutoFlickDirection (default) - allows flicking vertically if the
|
---|
649 | \e contentHeight is not equal to the \e height of the Flickable.
|
---|
650 | Allows flicking horizontally if the \e contentWidth is not equal
|
---|
651 | to the \e width of the Flickable.
|
---|
652 | \o Flickable.HorizontalFlick - allows flicking horizontally.
|
---|
653 | \o Flickable.VerticalFlick - allows flicking vertically.
|
---|
654 | \o Flickable.HorizontalAndVerticalFlick - allows flicking in both directions.
|
---|
655 | \endlist
|
---|
656 | */
|
---|
657 | QDeclarativeFlickable::FlickableDirection QDeclarativeFlickable::flickableDirection() const
|
---|
658 | {
|
---|
659 | Q_D(const QDeclarativeFlickable);
|
---|
660 | return d->flickableDirection;
|
---|
661 | }
|
---|
662 |
|
---|
663 | void QDeclarativeFlickable::setFlickableDirection(FlickableDirection direction)
|
---|
664 | {
|
---|
665 | Q_D(QDeclarativeFlickable);
|
---|
666 | if (direction != d->flickableDirection) {
|
---|
667 | d->flickableDirection = direction;
|
---|
668 | emit flickableDirectionChanged();
|
---|
669 | }
|
---|
670 | }
|
---|
671 |
|
---|
672 | void QDeclarativeFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
|
---|
673 | {
|
---|
674 | Q_Q(QDeclarativeFlickable);
|
---|
675 | if (interactive && timeline.isActive() && (qAbs(hData.velocity) > 10 || qAbs(vData.velocity) > 10))
|
---|
676 | stealMouse = true; // If we've been flicked then steal the click.
|
---|
677 | else
|
---|
678 | stealMouse = false;
|
---|
679 | q->setKeepMouseGrab(stealMouse);
|
---|
680 | pressed = true;
|
---|
681 | timeline.clear();
|
---|
682 | hData.velocity = 0;
|
---|
683 | vData.velocity = 0;
|
---|
684 | hData.dragStartOffset = 0;
|
---|
685 | vData.dragStartOffset = 0;
|
---|
686 | lastPos = QPoint();
|
---|
687 | QDeclarativeItemPrivate::start(lastPosTime);
|
---|
688 | pressPos = event->pos();
|
---|
689 | hData.pressPos = hData.move.value();
|
---|
690 | vData.pressPos = vData.move.value();
|
---|
691 | flickingHorizontally = false;
|
---|
692 | flickingVertically = false;
|
---|
693 | QDeclarativeItemPrivate::start(pressTime);
|
---|
694 | QDeclarativeItemPrivate::start(velocityTime);
|
---|
695 | }
|
---|
696 |
|
---|
697 | void QDeclarativeFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
---|
698 | {
|
---|
699 | Q_Q(QDeclarativeFlickable);
|
---|
700 | if (!interactive || !lastPosTime.isValid())
|
---|
701 | return;
|
---|
702 | bool rejectY = false;
|
---|
703 | bool rejectX = false;
|
---|
704 |
|
---|
705 | bool stealY = stealMouse;
|
---|
706 | bool stealX = stealMouse;
|
---|
707 |
|
---|
708 | if (q->yflick()) {
|
---|
709 | int dy = int(event->pos().y() - pressPos.y());
|
---|
710 | if (qAbs(dy) > QApplication::startDragDistance() || QDeclarativeItemPrivate::elapsed(pressTime) > 200) {
|
---|
711 | if (!vMoved)
|
---|
712 | vData.dragStartOffset = dy;
|
---|
713 | qreal newY = dy + vData.pressPos - vData.dragStartOffset;
|
---|
714 | const qreal minY = q->minYExtent();
|
---|
715 | const qreal maxY = q->maxYExtent();
|
---|
716 | if (newY > minY)
|
---|
717 | newY = minY + (newY - minY) / 2;
|
---|
718 | if (newY < maxY && maxY - minY <= 0)
|
---|
719 | newY = maxY + (newY - maxY) / 2;
|
---|
720 | if (boundsBehavior == QDeclarativeFlickable::StopAtBounds && (newY > minY || newY < maxY)) {
|
---|
721 | rejectY = true;
|
---|
722 | if (newY < maxY) {
|
---|
723 | newY = maxY;
|
---|
724 | rejectY = false;
|
---|
725 | }
|
---|
726 | if (newY > minY) {
|
---|
727 | newY = minY;
|
---|
728 | rejectY = false;
|
---|
729 | }
|
---|
730 | }
|
---|
731 | if (!rejectY && stealMouse) {
|
---|
732 | vData.move.setValue(qRound(newY));
|
---|
733 | vMoved = true;
|
---|
734 | }
|
---|
735 | if (qAbs(dy) > QApplication::startDragDistance())
|
---|
736 | stealY = true;
|
---|
737 | }
|
---|
738 | }
|
---|
739 |
|
---|
740 | if (q->xflick()) {
|
---|
741 | int dx = int(event->pos().x() - pressPos.x());
|
---|
742 | if (qAbs(dx) > QApplication::startDragDistance() || QDeclarativeItemPrivate::elapsed(pressTime) > 200) {
|
---|
743 | if (!hMoved)
|
---|
744 | hData.dragStartOffset = dx;
|
---|
745 | qreal newX = dx + hData.pressPos - hData.dragStartOffset;
|
---|
746 | const qreal minX = q->minXExtent();
|
---|
747 | const qreal maxX = q->maxXExtent();
|
---|
748 | if (newX > minX)
|
---|
749 | newX = minX + (newX - minX) / 2;
|
---|
750 | if (newX < maxX && maxX - minX <= 0)
|
---|
751 | newX = maxX + (newX - maxX) / 2;
|
---|
752 | if (boundsBehavior == QDeclarativeFlickable::StopAtBounds && (newX > minX || newX < maxX)) {
|
---|
753 | rejectX = true;
|
---|
754 | if (newX < maxX) {
|
---|
755 | newX = maxX;
|
---|
756 | rejectX = false;
|
---|
757 | }
|
---|
758 | if (newX > minX) {
|
---|
759 | newX = minX;
|
---|
760 | rejectX = false;
|
---|
761 | }
|
---|
762 | }
|
---|
763 | if (!rejectX && stealMouse) {
|
---|
764 | hData.move.setValue(qRound(newX));
|
---|
765 | hMoved = true;
|
---|
766 | }
|
---|
767 |
|
---|
768 | if (qAbs(dx) > QApplication::startDragDistance())
|
---|
769 | stealX = true;
|
---|
770 | }
|
---|
771 | }
|
---|
772 |
|
---|
773 | stealMouse = stealX || stealY;
|
---|
774 | if (stealMouse)
|
---|
775 | q->setKeepMouseGrab(true);
|
---|
776 |
|
---|
777 | if (!lastPos.isNull()) {
|
---|
778 | qreal elapsed = qreal(QDeclarativeItemPrivate::restart(lastPosTime)) / 1000.;
|
---|
779 | if (elapsed <= 0)
|
---|
780 | elapsed = 1;
|
---|
781 | if (q->yflick()) {
|
---|
782 | qreal diff = event->pos().y() - lastPos.y();
|
---|
783 | // average to reduce the effect of spurious moves
|
---|
784 | vData.velocity += diff / elapsed;
|
---|
785 | vData.velocity /= 2;
|
---|
786 | }
|
---|
787 |
|
---|
788 | if (q->xflick()) {
|
---|
789 | qreal diff = event->pos().x() - lastPos.x();
|
---|
790 | // average to reduce the effect of spurious moves
|
---|
791 | hData.velocity += diff / elapsed;
|
---|
792 | hData.velocity /= 2;
|
---|
793 | }
|
---|
794 | }
|
---|
795 |
|
---|
796 | if (rejectY) vData.velocity = 0;
|
---|
797 | if (rejectX) hData.velocity = 0;
|
---|
798 |
|
---|
799 | if (hMoved || vMoved) {
|
---|
800 | q->movementStarting();
|
---|
801 | q->viewportMoved();
|
---|
802 | }
|
---|
803 |
|
---|
804 | lastPos = event->pos();
|
---|
805 | }
|
---|
806 |
|
---|
807 | void QDeclarativeFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
---|
808 | {
|
---|
809 | Q_Q(QDeclarativeFlickable);
|
---|
810 | stealMouse = false;
|
---|
811 | q->setKeepMouseGrab(false);
|
---|
812 | pressed = false;
|
---|
813 | if (!lastPosTime.isValid())
|
---|
814 | return;
|
---|
815 |
|
---|
816 | if (QDeclarativeItemPrivate::elapsed(lastPosTime) > 100) {
|
---|
817 | // if we drag then pause before release we should not cause a flick.
|
---|
818 | hData.velocity = 0.0;
|
---|
819 | vData.velocity = 0.0;
|
---|
820 | }
|
---|
821 |
|
---|
822 | vTime = timeline.time();
|
---|
823 | if (qAbs(vData.velocity) > MinimumFlickVelocity && qAbs(event->pos().y() - pressPos.y()) > FlickThreshold)
|
---|
824 | flickY(vData.velocity);
|
---|
825 | else
|
---|
826 | fixupY();
|
---|
827 |
|
---|
828 | if (qAbs(hData.velocity) > MinimumFlickVelocity && qAbs(event->pos().x() - pressPos.x()) > FlickThreshold)
|
---|
829 | flickX(hData.velocity);
|
---|
830 | else
|
---|
831 | fixupX();
|
---|
832 |
|
---|
833 | lastPosTime.invalidate();
|
---|
834 |
|
---|
835 | if (!timeline.isActive())
|
---|
836 | q->movementEnding();
|
---|
837 | }
|
---|
838 |
|
---|
839 | void QDeclarativeFlickable::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
---|
840 | {
|
---|
841 | Q_D(QDeclarativeFlickable);
|
---|
842 | if (d->interactive) {
|
---|
843 | d->handleMousePressEvent(event);
|
---|
844 | event->accept();
|
---|
845 | } else {
|
---|
846 | QDeclarativeItem::mousePressEvent(event);
|
---|
847 | }
|
---|
848 | }
|
---|
849 |
|
---|
850 | void QDeclarativeFlickable::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
---|
851 | {
|
---|
852 | Q_D(QDeclarativeFlickable);
|
---|
853 | if (d->interactive) {
|
---|
854 | d->handleMouseMoveEvent(event);
|
---|
855 | event->accept();
|
---|
856 | } else {
|
---|
857 | QDeclarativeItem::mouseMoveEvent(event);
|
---|
858 | }
|
---|
859 | }
|
---|
860 |
|
---|
861 | void QDeclarativeFlickable::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
---|
862 | {
|
---|
863 | Q_D(QDeclarativeFlickable);
|
---|
864 | if (d->interactive) {
|
---|
865 | d->clearDelayedPress();
|
---|
866 | d->handleMouseReleaseEvent(event);
|
---|
867 | event->accept();
|
---|
868 | ungrabMouse();
|
---|
869 | } else {
|
---|
870 | QDeclarativeItem::mouseReleaseEvent(event);
|
---|
871 | }
|
---|
872 | }
|
---|
873 |
|
---|
874 | void QDeclarativeFlickable::wheelEvent(QGraphicsSceneWheelEvent *event)
|
---|
875 | {
|
---|
876 | Q_D(QDeclarativeFlickable);
|
---|
877 | if (!d->interactive) {
|
---|
878 | QDeclarativeItem::wheelEvent(event);
|
---|
879 | } else if (yflick()) {
|
---|
880 | if (event->delta() > 0)
|
---|
881 | d->vData.velocity = qMax(event->delta() - d->vData.smoothVelocity.value(), qreal(250.0));
|
---|
882 | else
|
---|
883 | d->vData.velocity = qMin(event->delta() - d->vData.smoothVelocity.value(), qreal(-250.0));
|
---|
884 | d->flickingVertically = false;
|
---|
885 | d->flickY(d->vData.velocity);
|
---|
886 | if (d->flickingVertically) {
|
---|
887 | d->vMoved = true;
|
---|
888 | movementStarting();
|
---|
889 | }
|
---|
890 | event->accept();
|
---|
891 | } else if (xflick()) {
|
---|
892 | if (event->delta() > 0)
|
---|
893 | d->hData.velocity = qMax(event->delta() - d->hData.smoothVelocity.value(), qreal(250.0));
|
---|
894 | else
|
---|
895 | d->hData.velocity = qMin(event->delta() - d->hData.smoothVelocity.value(), qreal(-250.0));
|
---|
896 | d->flickingHorizontally = false;
|
---|
897 | d->flickX(d->hData.velocity);
|
---|
898 | if (d->flickingHorizontally) {
|
---|
899 | d->hMoved = true;
|
---|
900 | movementStarting();
|
---|
901 | }
|
---|
902 | event->accept();
|
---|
903 | } else {
|
---|
904 | QDeclarativeItem::wheelEvent(event);
|
---|
905 | }
|
---|
906 | }
|
---|
907 |
|
---|
908 | void QDeclarativeFlickablePrivate::captureDelayedPress(QGraphicsSceneMouseEvent *event)
|
---|
909 | {
|
---|
910 | Q_Q(QDeclarativeFlickable);
|
---|
911 | if (!q->scene() || pressDelay <= 0)
|
---|
912 | return;
|
---|
913 | delayedPressTarget = q->scene()->mouseGrabberItem();
|
---|
914 | delayedPressEvent = new QGraphicsSceneMouseEvent(event->type());
|
---|
915 | delayedPressEvent->setAccepted(false);
|
---|
916 | for (int i = 0x1; i <= 0x10; i <<= 1) {
|
---|
917 | if (event->buttons() & i) {
|
---|
918 | Qt::MouseButton button = Qt::MouseButton(i);
|
---|
919 | delayedPressEvent->setButtonDownPos(button, event->buttonDownPos(button));
|
---|
920 | delayedPressEvent->setButtonDownScenePos(button, event->buttonDownScenePos(button));
|
---|
921 | delayedPressEvent->setButtonDownScreenPos(button, event->buttonDownScreenPos(button));
|
---|
922 | }
|
---|
923 | }
|
---|
924 | delayedPressEvent->setButtons(event->buttons());
|
---|
925 | delayedPressEvent->setButton(event->button());
|
---|
926 | delayedPressEvent->setPos(event->pos());
|
---|
927 | delayedPressEvent->setScenePos(event->scenePos());
|
---|
928 | delayedPressEvent->setScreenPos(event->screenPos());
|
---|
929 | delayedPressEvent->setLastPos(event->lastPos());
|
---|
930 | delayedPressEvent->setLastScenePos(event->lastScenePos());
|
---|
931 | delayedPressEvent->setLastScreenPos(event->lastScreenPos());
|
---|
932 | delayedPressEvent->setModifiers(event->modifiers());
|
---|
933 | delayedPressTimer.start(pressDelay, q);
|
---|
934 | }
|
---|
935 |
|
---|
936 | void QDeclarativeFlickablePrivate::clearDelayedPress()
|
---|
937 | {
|
---|
938 | if (delayedPressEvent) {
|
---|
939 | delayedPressTimer.stop();
|
---|
940 | delete delayedPressEvent;
|
---|
941 | delayedPressEvent = 0;
|
---|
942 | }
|
---|
943 | }
|
---|
944 |
|
---|
945 | void QDeclarativeFlickablePrivate::setRoundedViewportX(qreal x)
|
---|
946 | {
|
---|
947 | contentItem->setX(qRound(x));
|
---|
948 | }
|
---|
949 |
|
---|
950 | void QDeclarativeFlickablePrivate::setRoundedViewportY(qreal y)
|
---|
951 | {
|
---|
952 | contentItem->setY(qRound(y));
|
---|
953 | }
|
---|
954 |
|
---|
955 | void QDeclarativeFlickable::timerEvent(QTimerEvent *event)
|
---|
956 | {
|
---|
957 | Q_D(QDeclarativeFlickable);
|
---|
958 | if (event->timerId() == d->delayedPressTimer.timerId()) {
|
---|
959 | d->delayedPressTimer.stop();
|
---|
960 | if (d->delayedPressEvent) {
|
---|
961 | QDeclarativeItem *grabber = scene() ? qobject_cast<QDeclarativeItem*>(scene()->mouseGrabberItem()) : 0;
|
---|
962 | if (!grabber || grabber != this) {
|
---|
963 | // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
|
---|
964 | // so we reset the grabber
|
---|
965 | if (scene()->mouseGrabberItem() == d->delayedPressTarget)
|
---|
966 | d->delayedPressTarget->ungrabMouse();
|
---|
967 | //Use the event handler that will take care of finding the proper item to propagate the event
|
---|
968 | QApplication::sendEvent(scene(), d->delayedPressEvent);
|
---|
969 | }
|
---|
970 | delete d->delayedPressEvent;
|
---|
971 | d->delayedPressEvent = 0;
|
---|
972 | }
|
---|
973 | }
|
---|
974 | }
|
---|
975 |
|
---|
976 | qreal QDeclarativeFlickable::minYExtent() const
|
---|
977 | {
|
---|
978 | return 0.0;
|
---|
979 | }
|
---|
980 |
|
---|
981 | qreal QDeclarativeFlickable::minXExtent() const
|
---|
982 | {
|
---|
983 | return 0.0;
|
---|
984 | }
|
---|
985 |
|
---|
986 | /* returns -ve */
|
---|
987 | qreal QDeclarativeFlickable::maxXExtent() const
|
---|
988 | {
|
---|
989 | return width() - vWidth();
|
---|
990 | }
|
---|
991 | /* returns -ve */
|
---|
992 | qreal QDeclarativeFlickable::maxYExtent() const
|
---|
993 | {
|
---|
994 | return height() - vHeight();
|
---|
995 | }
|
---|
996 |
|
---|
997 | void QDeclarativeFlickable::viewportMoved()
|
---|
998 | {
|
---|
999 | Q_D(QDeclarativeFlickable);
|
---|
1000 |
|
---|
1001 | qreal prevX = d->lastFlickablePosition.x();
|
---|
1002 | qreal prevY = d->lastFlickablePosition.y();
|
---|
1003 | d->velocityTimeline.clear();
|
---|
1004 | if (d->pressed || d->calcVelocity) {
|
---|
1005 | int elapsed = QDeclarativeItemPrivate::restart(d->velocityTime);
|
---|
1006 | if (elapsed > 0) {
|
---|
1007 | qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / elapsed;
|
---|
1008 | qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / elapsed;
|
---|
1009 | d->velocityTimeline.move(d->hData.smoothVelocity, horizontalVelocity, d->reportedVelocitySmoothing);
|
---|
1010 | d->velocityTimeline.move(d->hData.smoothVelocity, 0, d->reportedVelocitySmoothing);
|
---|
1011 | d->velocityTimeline.move(d->vData.smoothVelocity, verticalVelocity, d->reportedVelocitySmoothing);
|
---|
1012 | d->velocityTimeline.move(d->vData.smoothVelocity, 0, d->reportedVelocitySmoothing);
|
---|
1013 | }
|
---|
1014 | } else {
|
---|
1015 | if (d->timeline.time() > d->vTime) {
|
---|
1016 | qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
|
---|
1017 | qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
|
---|
1018 | d->hData.smoothVelocity.setValue(horizontalVelocity);
|
---|
1019 | d->vData.smoothVelocity.setValue(verticalVelocity);
|
---|
1020 | }
|
---|
1021 | }
|
---|
1022 |
|
---|
1023 | d->lastFlickablePosition = QPointF(d->hData.move.value(), d->vData.move.value());
|
---|
1024 |
|
---|
1025 | d->vTime = d->timeline.time();
|
---|
1026 | d->updateBeginningEnd();
|
---|
1027 | }
|
---|
1028 |
|
---|
1029 | void QDeclarativeFlickable::geometryChanged(const QRectF &newGeometry,
|
---|
1030 | const QRectF &oldGeometry)
|
---|
1031 | {
|
---|
1032 | Q_D(QDeclarativeFlickable);
|
---|
1033 | QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
|
---|
1034 |
|
---|
1035 | bool changed = false;
|
---|
1036 | if (newGeometry.width() != oldGeometry.width()) {
|
---|
1037 | if (xflick())
|
---|
1038 | changed = true;
|
---|
1039 | if (d->hData.viewSize < 0) {
|
---|
1040 | d->contentItem->setWidth(width());
|
---|
1041 | emit contentWidthChanged();
|
---|
1042 | }
|
---|
1043 | // Make sure that we're entirely in view.
|
---|
1044 | if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
|
---|
1045 | int oldDuration = d->fixupDuration;
|
---|
1046 | d->fixupDuration = 0;
|
---|
1047 | d->fixupX();
|
---|
1048 | d->fixupDuration = oldDuration;
|
---|
1049 | }
|
---|
1050 | }
|
---|
1051 | if (newGeometry.height() != oldGeometry.height()) {
|
---|
1052 | if (yflick())
|
---|
1053 | changed = true;
|
---|
1054 | if (d->vData.viewSize < 0) {
|
---|
1055 | d->contentItem->setHeight(height());
|
---|
1056 | emit contentHeightChanged();
|
---|
1057 | }
|
---|
1058 | // Make sure that we're entirely in view.
|
---|
1059 | if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
|
---|
1060 | int oldDuration = d->fixupDuration;
|
---|
1061 | d->fixupDuration = 0;
|
---|
1062 | d->fixupY();
|
---|
1063 | d->fixupDuration = oldDuration;
|
---|
1064 | }
|
---|
1065 | }
|
---|
1066 |
|
---|
1067 | if (changed)
|
---|
1068 | d->updateBeginningEnd();
|
---|
1069 | }
|
---|
1070 |
|
---|
1071 | void QDeclarativeFlickable::cancelFlick()
|
---|
1072 | {
|
---|
1073 | Q_D(QDeclarativeFlickable);
|
---|
1074 | d->timeline.reset(d->hData.move);
|
---|
1075 | d->timeline.reset(d->vData.move);
|
---|
1076 | movementEnding();
|
---|
1077 | }
|
---|
1078 |
|
---|
1079 | void QDeclarativeFlickablePrivate::data_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
|
---|
1080 | {
|
---|
1081 | QGraphicsObject *i = qobject_cast<QGraphicsObject *>(o);
|
---|
1082 | if (i) {
|
---|
1083 | QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(i);
|
---|
1084 | if (static_cast<QDeclarativeItemPrivate*>(d)->componentComplete) {
|
---|
1085 | i->setParentItem(static_cast<QDeclarativeFlickablePrivate*>(prop->data)->contentItem);
|
---|
1086 | } else {
|
---|
1087 | d->setParentItemHelper(static_cast<QDeclarativeFlickablePrivate*>(prop->data)->contentItem, 0, 0);
|
---|
1088 | }
|
---|
1089 | } else {
|
---|
1090 | o->setParent(prop->object);
|
---|
1091 | }
|
---|
1092 | }
|
---|
1093 |
|
---|
1094 | static inline int children_count_helper(QGraphicsObject *object)
|
---|
1095 | {
|
---|
1096 | QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(object);
|
---|
1097 | return d->children.count();
|
---|
1098 | }
|
---|
1099 |
|
---|
1100 | static inline QObject *children_at_helper(QGraphicsObject *object, int index)
|
---|
1101 | {
|
---|
1102 | QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(object);
|
---|
1103 | if (index >= 0 && index < d->children.count())
|
---|
1104 | return d->children.at(index)->toGraphicsObject();
|
---|
1105 | else
|
---|
1106 | return 0;
|
---|
1107 | }
|
---|
1108 |
|
---|
1109 | static inline void children_clear_helper(QGraphicsObject *object)
|
---|
1110 | {
|
---|
1111 | QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(object);
|
---|
1112 | int childCount = d->children.count();
|
---|
1113 | if (static_cast<QDeclarativeItemPrivate*>(d)->componentComplete) {
|
---|
1114 | for (int index = 0 ;index < childCount; index++) {
|
---|
1115 | d->children.at(0)->setParentItem(0);
|
---|
1116 | }
|
---|
1117 | } else {
|
---|
1118 | for (int index = 0 ;index < childCount; index++) {
|
---|
1119 | QGraphicsItemPrivate::get(d->children.at(0))->setParentItemHelper(0, /*newParentVariant=*/0, /*thisPointerVariant=*/0);
|
---|
1120 | }
|
---|
1121 | }
|
---|
1122 |
|
---|
1123 | }
|
---|
1124 |
|
---|
1125 | int QDeclarativeFlickablePrivate::data_count(QDeclarativeListProperty<QObject> *prop)
|
---|
1126 | {
|
---|
1127 | return QDeclarativeItemPrivate::resources_count(prop) +
|
---|
1128 | children_count_helper(static_cast<QDeclarativeFlickablePrivate*>(prop->data)->contentItem);
|
---|
1129 | }
|
---|
1130 |
|
---|
1131 | QObject *QDeclarativeFlickablePrivate::data_at(QDeclarativeListProperty<QObject> *prop, int i)
|
---|
1132 | {
|
---|
1133 | int resourcesCount = QDeclarativeItemPrivate::resources_count(prop);
|
---|
1134 | if (i < resourcesCount)
|
---|
1135 | return QDeclarativeItemPrivate::resources_at(prop, i);
|
---|
1136 | const int j = i - resourcesCount;
|
---|
1137 | QGraphicsObject *contentObject = static_cast<QDeclarativeFlickablePrivate*>(prop->data)->contentItem;
|
---|
1138 | if (j < children_count_helper(contentObject))
|
---|
1139 | return children_at_helper(contentObject, j);
|
---|
1140 | return 0;
|
---|
1141 | }
|
---|
1142 |
|
---|
1143 | void QDeclarativeFlickablePrivate::data_clear(QDeclarativeListProperty<QObject> *prop)
|
---|
1144 | {
|
---|
1145 | QDeclarativeItemPrivate::resources_clear(prop);
|
---|
1146 | QGraphicsObject *contentObject =
|
---|
1147 | static_cast<QDeclarativeFlickablePrivate*>(prop->data)->contentItem;
|
---|
1148 | children_clear_helper(contentObject);
|
---|
1149 | }
|
---|
1150 |
|
---|
1151 | QDeclarativeListProperty<QObject> QDeclarativeFlickable::flickableData()
|
---|
1152 | {
|
---|
1153 | Q_D(QDeclarativeFlickable);
|
---|
1154 | return QDeclarativeListProperty<QObject>(this, (void *)d, QDeclarativeFlickablePrivate::data_append,
|
---|
1155 | QDeclarativeFlickablePrivate::data_count,
|
---|
1156 | QDeclarativeFlickablePrivate::data_at,
|
---|
1157 | QDeclarativeFlickablePrivate::data_clear
|
---|
1158 | );
|
---|
1159 | }
|
---|
1160 |
|
---|
1161 | QDeclarativeListProperty<QGraphicsObject> QDeclarativeFlickable::flickableChildren()
|
---|
1162 | {
|
---|
1163 | Q_D(QDeclarativeFlickable);
|
---|
1164 | return QGraphicsItemPrivate::get(d->contentItem)->childrenList();
|
---|
1165 | }
|
---|
1166 |
|
---|
1167 | /*!
|
---|
1168 | \qmlproperty enumeration Flickable::boundsBehavior
|
---|
1169 | This property holds whether the surface may be dragged
|
---|
1170 | beyond the Fickable's boundaries, or overshoot the
|
---|
1171 | Flickable's boundaries when flicked.
|
---|
1172 |
|
---|
1173 | This enables the feeling that the edges of the view are soft,
|
---|
1174 | rather than a hard physical boundary.
|
---|
1175 |
|
---|
1176 | The \c boundsBehavior can be one of:
|
---|
1177 |
|
---|
1178 | \list
|
---|
1179 | \o Flickable.StopAtBounds - the contents can not be dragged beyond the boundary
|
---|
1180 | of the flickable, and flicks will not overshoot.
|
---|
1181 | \o Flickable.DragOverBounds - the contents can be dragged beyond the boundary
|
---|
1182 | of the Flickable, but flicks will not overshoot.
|
---|
1183 | \o Flickable.DragAndOvershootBounds (default) - the contents can be dragged
|
---|
1184 | beyond the boundary of the Flickable, and can overshoot the
|
---|
1185 | boundary when flicked.
|
---|
1186 | \endlist
|
---|
1187 | */
|
---|
1188 | QDeclarativeFlickable::BoundsBehavior QDeclarativeFlickable::boundsBehavior() const
|
---|
1189 | {
|
---|
1190 | Q_D(const QDeclarativeFlickable);
|
---|
1191 | return d->boundsBehavior;
|
---|
1192 | }
|
---|
1193 |
|
---|
1194 | void QDeclarativeFlickable::setBoundsBehavior(BoundsBehavior b)
|
---|
1195 | {
|
---|
1196 | Q_D(QDeclarativeFlickable);
|
---|
1197 | if (b == d->boundsBehavior)
|
---|
1198 | return;
|
---|
1199 | d->boundsBehavior = b;
|
---|
1200 | emit boundsBehaviorChanged();
|
---|
1201 | }
|
---|
1202 |
|
---|
1203 | /*!
|
---|
1204 | \qmlproperty real Flickable::contentWidth
|
---|
1205 | \qmlproperty real Flickable::contentHeight
|
---|
1206 |
|
---|
1207 | The dimensions of the content (the surface controlled by Flickable).
|
---|
1208 | This should typically be set to the combined size of the items placed in the
|
---|
1209 | Flickable.
|
---|
1210 |
|
---|
1211 | The following snippet shows how these properties are used to display
|
---|
1212 | an image that is larger than the Flickable item itself:
|
---|
1213 |
|
---|
1214 | \snippet doc/src/snippets/declarative/flickable.qml document
|
---|
1215 |
|
---|
1216 | In some cases, the the content dimensions can be automatically set
|
---|
1217 | using the \l {Item::childrenRect.width}{childrenRect.width}
|
---|
1218 | and \l {Item::childrenRect.height}{childrenRect.height} properties.
|
---|
1219 | */
|
---|
1220 | qreal QDeclarativeFlickable::contentWidth() const
|
---|
1221 | {
|
---|
1222 | Q_D(const QDeclarativeFlickable);
|
---|
1223 | return d->hData.viewSize;
|
---|
1224 | }
|
---|
1225 |
|
---|
1226 | void QDeclarativeFlickable::setContentWidth(qreal w)
|
---|
1227 | {
|
---|
1228 | Q_D(QDeclarativeFlickable);
|
---|
1229 | if (d->hData.viewSize == w)
|
---|
1230 | return;
|
---|
1231 | d->hData.viewSize = w;
|
---|
1232 | if (w < 0)
|
---|
1233 | d->contentItem->setWidth(width());
|
---|
1234 | else
|
---|
1235 | d->contentItem->setWidth(w);
|
---|
1236 | // Make sure that we're entirely in view.
|
---|
1237 | if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
|
---|
1238 | int oldDuration = d->fixupDuration;
|
---|
1239 | d->fixupDuration = 0;
|
---|
1240 | d->fixupX();
|
---|
1241 | d->fixupDuration = oldDuration;
|
---|
1242 | }
|
---|
1243 | emit contentWidthChanged();
|
---|
1244 | d->updateBeginningEnd();
|
---|
1245 | }
|
---|
1246 |
|
---|
1247 | qreal QDeclarativeFlickable::contentHeight() const
|
---|
1248 | {
|
---|
1249 | Q_D(const QDeclarativeFlickable);
|
---|
1250 | return d->vData.viewSize;
|
---|
1251 | }
|
---|
1252 |
|
---|
1253 | void QDeclarativeFlickable::setContentHeight(qreal h)
|
---|
1254 | {
|
---|
1255 | Q_D(QDeclarativeFlickable);
|
---|
1256 | if (d->vData.viewSize == h)
|
---|
1257 | return;
|
---|
1258 | d->vData.viewSize = h;
|
---|
1259 | if (h < 0)
|
---|
1260 | d->contentItem->setHeight(height());
|
---|
1261 | else
|
---|
1262 | d->contentItem->setHeight(h);
|
---|
1263 | // Make sure that we're entirely in view.
|
---|
1264 | if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
|
---|
1265 | int oldDuration = d->fixupDuration;
|
---|
1266 | d->fixupDuration = 0;
|
---|
1267 | d->fixupY();
|
---|
1268 | d->fixupDuration = oldDuration;
|
---|
1269 | }
|
---|
1270 | emit contentHeightChanged();
|
---|
1271 | d->updateBeginningEnd();
|
---|
1272 | }
|
---|
1273 |
|
---|
1274 | qreal QDeclarativeFlickable::vWidth() const
|
---|
1275 | {
|
---|
1276 | Q_D(const QDeclarativeFlickable);
|
---|
1277 | if (d->hData.viewSize < 0)
|
---|
1278 | return width();
|
---|
1279 | else
|
---|
1280 | return d->hData.viewSize;
|
---|
1281 | }
|
---|
1282 |
|
---|
1283 | qreal QDeclarativeFlickable::vHeight() const
|
---|
1284 | {
|
---|
1285 | Q_D(const QDeclarativeFlickable);
|
---|
1286 | if (d->vData.viewSize < 0)
|
---|
1287 | return height();
|
---|
1288 | else
|
---|
1289 | return d->vData.viewSize;
|
---|
1290 | }
|
---|
1291 |
|
---|
1292 | bool QDeclarativeFlickable::xflick() const
|
---|
1293 | {
|
---|
1294 | Q_D(const QDeclarativeFlickable);
|
---|
1295 | if (d->flickableDirection == QDeclarativeFlickable::AutoFlickDirection)
|
---|
1296 | return vWidth() != width();
|
---|
1297 | return d->flickableDirection & QDeclarativeFlickable::HorizontalFlick;
|
---|
1298 | }
|
---|
1299 |
|
---|
1300 | bool QDeclarativeFlickable::yflick() const
|
---|
1301 | {
|
---|
1302 | Q_D(const QDeclarativeFlickable);
|
---|
1303 | if (d->flickableDirection == QDeclarativeFlickable::AutoFlickDirection)
|
---|
1304 | return vHeight() != height();
|
---|
1305 | return d->flickableDirection & QDeclarativeFlickable::VerticalFlick;
|
---|
1306 | }
|
---|
1307 |
|
---|
1308 | bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
|
---|
1309 | {
|
---|
1310 | Q_D(QDeclarativeFlickable);
|
---|
1311 | QGraphicsSceneMouseEvent mouseEvent(event->type());
|
---|
1312 | QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
|
---|
1313 |
|
---|
1314 | QGraphicsScene *s = scene();
|
---|
1315 | QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
|
---|
1316 | bool stealThisEvent = d->stealMouse;
|
---|
1317 | if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
|
---|
1318 | mouseEvent.setAccepted(false);
|
---|
1319 | for (int i = 0x1; i <= 0x10; i <<= 1) {
|
---|
1320 | if (event->buttons() & i) {
|
---|
1321 | Qt::MouseButton button = Qt::MouseButton(i);
|
---|
1322 | mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
|
---|
1323 | }
|
---|
1324 | }
|
---|
1325 | mouseEvent.setScenePos(event->scenePos());
|
---|
1326 | mouseEvent.setLastScenePos(event->lastScenePos());
|
---|
1327 | mouseEvent.setPos(mapFromScene(event->scenePos()));
|
---|
1328 | mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
|
---|
1329 |
|
---|
1330 | switch(mouseEvent.type()) {
|
---|
1331 | case QEvent::GraphicsSceneMouseMove:
|
---|
1332 | d->handleMouseMoveEvent(&mouseEvent);
|
---|
1333 | break;
|
---|
1334 | case QEvent::GraphicsSceneMousePress:
|
---|
1335 | if (d->delayedPressEvent)
|
---|
1336 | return false;
|
---|
1337 |
|
---|
1338 | d->handleMousePressEvent(&mouseEvent);
|
---|
1339 | d->captureDelayedPress(event);
|
---|
1340 | stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
|
---|
1341 | break;
|
---|
1342 | case QEvent::GraphicsSceneMouseRelease:
|
---|
1343 | if (d->delayedPressEvent) {
|
---|
1344 | // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
|
---|
1345 | // so we reset the grabber
|
---|
1346 | if (s->mouseGrabberItem() == d->delayedPressTarget)
|
---|
1347 | d->delayedPressTarget->ungrabMouse();
|
---|
1348 | //Use the event handler that will take care of finding the proper item to propagate the event
|
---|
1349 | QApplication::sendEvent(scene(), d->delayedPressEvent);
|
---|
1350 | d->clearDelayedPress();
|
---|
1351 | // We send the release
|
---|
1352 | scene()->sendEvent(s->mouseGrabberItem(), event);
|
---|
1353 | // And the event has been consumed
|
---|
1354 | return true;
|
---|
1355 | }
|
---|
1356 | d->handleMouseReleaseEvent(&mouseEvent);
|
---|
1357 | break;
|
---|
1358 | default:
|
---|
1359 | break;
|
---|
1360 | }
|
---|
1361 | grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
|
---|
1362 | if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) {
|
---|
1363 | d->clearDelayedPress();
|
---|
1364 | grabMouse();
|
---|
1365 | }
|
---|
1366 |
|
---|
1367 | return stealThisEvent || d->delayedPressEvent;
|
---|
1368 | } else if (d->lastPosTime.isValid()) {
|
---|
1369 | d->lastPosTime.invalidate();
|
---|
1370 | }
|
---|
1371 | if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
|
---|
1372 | d->clearDelayedPress();
|
---|
1373 | d->stealMouse = false;
|
---|
1374 | d->pressed = false;
|
---|
1375 | }
|
---|
1376 | return false;
|
---|
1377 | }
|
---|
1378 |
|
---|
1379 | bool QDeclarativeFlickable::sceneEventFilter(QGraphicsItem *i, QEvent *e)
|
---|
1380 | {
|
---|
1381 | Q_D(QDeclarativeFlickable);
|
---|
1382 | if (!isVisible() || !d->interactive)
|
---|
1383 | return QDeclarativeItem::sceneEventFilter(i, e);
|
---|
1384 | switch (e->type()) {
|
---|
1385 | case QEvent::GraphicsSceneMousePress:
|
---|
1386 | case QEvent::GraphicsSceneMouseMove:
|
---|
1387 | case QEvent::GraphicsSceneMouseRelease:
|
---|
1388 | return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
|
---|
1389 | default:
|
---|
1390 | break;
|
---|
1391 | }
|
---|
1392 |
|
---|
1393 | return QDeclarativeItem::sceneEventFilter(i, e);
|
---|
1394 | }
|
---|
1395 |
|
---|
1396 | /*!
|
---|
1397 | \qmlproperty real Flickable::maximumFlickVelocity
|
---|
1398 | This property holds the maximum velocity that the user can flick the view in pixels/second.
|
---|
1399 |
|
---|
1400 | The default is 2000 pixels/s
|
---|
1401 | */
|
---|
1402 | qreal QDeclarativeFlickable::maximumFlickVelocity() const
|
---|
1403 | {
|
---|
1404 | Q_D(const QDeclarativeFlickable);
|
---|
1405 | return d->maxVelocity;
|
---|
1406 | }
|
---|
1407 |
|
---|
1408 | void QDeclarativeFlickable::setMaximumFlickVelocity(qreal v)
|
---|
1409 | {
|
---|
1410 | Q_D(QDeclarativeFlickable);
|
---|
1411 | if (v == d->maxVelocity)
|
---|
1412 | return;
|
---|
1413 | d->maxVelocity = v;
|
---|
1414 | emit maximumFlickVelocityChanged();
|
---|
1415 | }
|
---|
1416 |
|
---|
1417 | /*!
|
---|
1418 | \qmlproperty real Flickable::flickDeceleration
|
---|
1419 | This property holds the rate at which a flick will decelerate.
|
---|
1420 |
|
---|
1421 | The default is 500.
|
---|
1422 | */
|
---|
1423 | qreal QDeclarativeFlickable::flickDeceleration() const
|
---|
1424 | {
|
---|
1425 | Q_D(const QDeclarativeFlickable);
|
---|
1426 | return d->deceleration;
|
---|
1427 | }
|
---|
1428 |
|
---|
1429 | void QDeclarativeFlickable::setFlickDeceleration(qreal deceleration)
|
---|
1430 | {
|
---|
1431 | Q_D(QDeclarativeFlickable);
|
---|
1432 | if (deceleration == d->deceleration)
|
---|
1433 | return;
|
---|
1434 | d->deceleration = deceleration;
|
---|
1435 | emit flickDecelerationChanged();
|
---|
1436 | }
|
---|
1437 |
|
---|
1438 | bool QDeclarativeFlickable::isFlicking() const
|
---|
1439 | {
|
---|
1440 | Q_D(const QDeclarativeFlickable);
|
---|
1441 | return d->flickingHorizontally || d->flickingVertically;
|
---|
1442 | }
|
---|
1443 |
|
---|
1444 | /*!
|
---|
1445 | \qmlproperty bool Flickable::flicking
|
---|
1446 | \qmlproperty bool Flickable::flickingHorizontally
|
---|
1447 | \qmlproperty bool Flickable::flickingVertically
|
---|
1448 |
|
---|
1449 | These properties describe whether the view is currently moving horizontally,
|
---|
1450 | vertically or in either direction, due to the user flicking the view.
|
---|
1451 | */
|
---|
1452 | bool QDeclarativeFlickable::isFlickingHorizontally() const
|
---|
1453 | {
|
---|
1454 | Q_D(const QDeclarativeFlickable);
|
---|
1455 | return d->flickingHorizontally;
|
---|
1456 | }
|
---|
1457 |
|
---|
1458 | bool QDeclarativeFlickable::isFlickingVertically() const
|
---|
1459 | {
|
---|
1460 | Q_D(const QDeclarativeFlickable);
|
---|
1461 | return d->flickingVertically;
|
---|
1462 | }
|
---|
1463 |
|
---|
1464 | /*!
|
---|
1465 | \qmlproperty int Flickable::pressDelay
|
---|
1466 |
|
---|
1467 | This property holds the time to delay (ms) delivering a press to
|
---|
1468 | children of the Flickable. This can be useful where reacting
|
---|
1469 | to a press before a flicking action has undesirable effects.
|
---|
1470 |
|
---|
1471 | If the flickable is dragged/flicked before the delay times out
|
---|
1472 | the press event will not be delivered. If the button is released
|
---|
1473 | within the timeout, both the press and release will be delivered.
|
---|
1474 | */
|
---|
1475 | int QDeclarativeFlickable::pressDelay() const
|
---|
1476 | {
|
---|
1477 | Q_D(const QDeclarativeFlickable);
|
---|
1478 | return d->pressDelay;
|
---|
1479 | }
|
---|
1480 |
|
---|
1481 | void QDeclarativeFlickable::setPressDelay(int delay)
|
---|
1482 | {
|
---|
1483 | Q_D(QDeclarativeFlickable);
|
---|
1484 | if (d->pressDelay == delay)
|
---|
1485 | return;
|
---|
1486 | d->pressDelay = delay;
|
---|
1487 | emit pressDelayChanged();
|
---|
1488 | }
|
---|
1489 |
|
---|
1490 |
|
---|
1491 | bool QDeclarativeFlickable::isMoving() const
|
---|
1492 | {
|
---|
1493 | Q_D(const QDeclarativeFlickable);
|
---|
1494 | return d->movingHorizontally || d->movingVertically;
|
---|
1495 | }
|
---|
1496 |
|
---|
1497 | /*!
|
---|
1498 | \qmlproperty bool Flickable::moving
|
---|
1499 | \qmlproperty bool Flickable::movingHorizontally
|
---|
1500 | \qmlproperty bool Flickable::movingVertically
|
---|
1501 |
|
---|
1502 | These properties describe whether the view is currently moving horizontally,
|
---|
1503 | vertically or in either direction, due to the user either dragging or
|
---|
1504 | flicking the view.
|
---|
1505 | */
|
---|
1506 | bool QDeclarativeFlickable::isMovingHorizontally() const
|
---|
1507 | {
|
---|
1508 | Q_D(const QDeclarativeFlickable);
|
---|
1509 | return d->movingHorizontally;
|
---|
1510 | }
|
---|
1511 |
|
---|
1512 | bool QDeclarativeFlickable::isMovingVertically() const
|
---|
1513 | {
|
---|
1514 | Q_D(const QDeclarativeFlickable);
|
---|
1515 | return d->movingVertically;
|
---|
1516 | }
|
---|
1517 |
|
---|
1518 | void QDeclarativeFlickable::movementStarting()
|
---|
1519 | {
|
---|
1520 | Q_D(QDeclarativeFlickable);
|
---|
1521 | if (d->hMoved && !d->movingHorizontally) {
|
---|
1522 | d->movingHorizontally = true;
|
---|
1523 | emit movingChanged();
|
---|
1524 | emit movingHorizontallyChanged();
|
---|
1525 | if (!d->movingVertically)
|
---|
1526 | emit movementStarted();
|
---|
1527 | }
|
---|
1528 | else if (d->vMoved && !d->movingVertically) {
|
---|
1529 | d->movingVertically = true;
|
---|
1530 | emit movingChanged();
|
---|
1531 | emit movingVerticallyChanged();
|
---|
1532 | if (!d->movingHorizontally)
|
---|
1533 | emit movementStarted();
|
---|
1534 | }
|
---|
1535 | }
|
---|
1536 |
|
---|
1537 | void QDeclarativeFlickable::movementEnding()
|
---|
1538 | {
|
---|
1539 | Q_D(QDeclarativeFlickable);
|
---|
1540 | movementXEnding();
|
---|
1541 | movementYEnding();
|
---|
1542 | d->hData.smoothVelocity.setValue(0);
|
---|
1543 | d->vData.smoothVelocity.setValue(0);
|
---|
1544 | }
|
---|
1545 |
|
---|
1546 | void QDeclarativeFlickable::movementXEnding()
|
---|
1547 | {
|
---|
1548 | Q_D(QDeclarativeFlickable);
|
---|
1549 | if (d->flickingHorizontally) {
|
---|
1550 | d->flickingHorizontally = false;
|
---|
1551 | emit flickingChanged();
|
---|
1552 | emit flickingHorizontallyChanged();
|
---|
1553 | if (!d->flickingVertically)
|
---|
1554 | emit flickEnded();
|
---|
1555 | }
|
---|
1556 | if (!d->pressed && !d->stealMouse) {
|
---|
1557 | if (d->movingHorizontally) {
|
---|
1558 | d->movingHorizontally = false;
|
---|
1559 | d->hMoved = false;
|
---|
1560 | emit movingChanged();
|
---|
1561 | emit movingHorizontallyChanged();
|
---|
1562 | if (!d->movingVertically)
|
---|
1563 | emit movementEnded();
|
---|
1564 | }
|
---|
1565 | }
|
---|
1566 | }
|
---|
1567 |
|
---|
1568 | void QDeclarativeFlickable::movementYEnding()
|
---|
1569 | {
|
---|
1570 | Q_D(QDeclarativeFlickable);
|
---|
1571 | if (d->flickingVertically) {
|
---|
1572 | d->flickingVertically = false;
|
---|
1573 | emit flickingChanged();
|
---|
1574 | emit flickingVerticallyChanged();
|
---|
1575 | if (!d->flickingHorizontally)
|
---|
1576 | emit flickEnded();
|
---|
1577 | }
|
---|
1578 | if (!d->pressed && !d->stealMouse) {
|
---|
1579 | if (d->movingVertically) {
|
---|
1580 | d->movingVertically = false;
|
---|
1581 | d->vMoved = false;
|
---|
1582 | emit movingChanged();
|
---|
1583 | emit movingVerticallyChanged();
|
---|
1584 | if (!d->movingHorizontally)
|
---|
1585 | emit movementEnded();
|
---|
1586 | }
|
---|
1587 | }
|
---|
1588 | }
|
---|
1589 |
|
---|
1590 | void QDeclarativeFlickablePrivate::updateVelocity()
|
---|
1591 | {
|
---|
1592 | Q_Q(QDeclarativeFlickable);
|
---|
1593 | emit q->horizontalVelocityChanged();
|
---|
1594 | emit q->verticalVelocityChanged();
|
---|
1595 | }
|
---|
1596 |
|
---|
1597 | QT_END_NAMESPACE
|
---|