1 /****************************************************************************
\r
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
\r
4 ** All rights reserved.
\r
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
\r
7 ** This file is part of the demonstration applications of the Qt Toolkit.
\r
9 ** $QT_BEGIN_LICENSE:LGPL$
\r
11 ** Licensees holding valid Qt Commercial licenses may use this file in
\r
12 ** accordance with the Qt Commercial License Agreement provided with the
\r
13 ** Software or, alternatively, in accordance with the terms contained in
\r
14 ** a written agreement between you and Nokia.
\r
16 ** GNU Lesser General Public License Usage
\r
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
\r
18 ** General Public License version 2.1 as published by the Free Software
\r
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
\r
20 ** packaging of this file. Please review the following information to
\r
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
\r
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
\r
24 ** In addition, as a special exception, Nokia gives you certain additional
\r
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
\r
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
\r
28 ** GNU General Public License Usage
\r
29 ** Alternatively, this file may be used under the terms of the GNU
\r
30 ** General Public License version 3.0 as published by the Free Software
\r
31 ** Foundation and appearing in the file LICENSE.GPL included in the
\r
32 ** packaging of this file. Please review the following information to
\r
33 ** ensure the GNU General Public License version 3.0 requirements will be
\r
34 ** met: http://www.gnu.org/copyleft/gpl.html.
\r
36 ** If you have questions regarding the use of this file, please contact
\r
37 ** Nokia at qt-info@nokia.com.
\r
40 ****************************************************************************/
\r
42 #include "flickable.h"
\r
47 class FlickableTicker: QObject
\r
50 FlickableTicker(Flickable *scroller) {
\r
51 m_scroller = scroller;
\r
54 void start(int interval) {
\r
55 if (!m_timer.isActive())
\r
56 m_timer.start(interval, this);
\r
64 void timerEvent(QTimerEvent *event) {
\r
70 Flickable *m_scroller;
\r
71 QBasicTimer m_timer;
\r
74 class FlickablePrivate
\r
91 FlickableTicker *ticker;
\r
94 QList<QEvent*> ignoreList;
\r
97 Flickable::Flickable()
\r
99 d = new FlickablePrivate;
\r
100 d->state = FlickablePrivate::Steady;
\r
102 d->ticker = new FlickableTicker(this);
\r
103 d->timeStamp = QTime::currentTime();
\r
107 Flickable::~Flickable()
\r
112 void Flickable::setThreshold(int th)
\r
118 int Flickable::threshold() const
\r
120 return d->threshold;
\r
123 void Flickable::setAcceptMouseClick(QWidget *target)
\r
125 d->target = target;
\r
128 static QPoint deaccelerate(const QPoint &speed, int a = 1, int max = 64)
\r
130 int x = qBound(-max, speed.x(), max);
\r
131 int y = qBound(-max, speed.y(), max);
\r
132 x = (x == 0) ? x : (x > 0) ? qMax(0, x - a) : qMin(0, x + a);
\r
133 y = (y == 0) ? y : (y > 0) ? qMax(0, y - a) : qMin(0, y + a);
\r
134 return QPoint(x, y);
\r
137 void Flickable::handleMousePress(QMouseEvent *event)
\r
141 if (event->button() != Qt::LeftButton)
\r
144 if (d->ignoreList.removeAll(event))
\r
147 switch (d->state) {
\r
149 case FlickablePrivate::Steady:
\r
151 d->state = FlickablePrivate::Pressed;
\r
152 d->pressPos = event->pos();
\r
155 case FlickablePrivate::AutoScroll:
\r
157 d->state = FlickablePrivate::Stop;
\r
158 d->speed = QPoint(0, 0);
\r
159 d->pressPos = event->pos();
\r
160 d->offset = scrollOffset();
\r
169 void Flickable::handleMouseRelease(QMouseEvent *event)
\r
173 if (event->button() != Qt::LeftButton)
\r
176 if (d->ignoreList.removeAll(event))
\r
181 switch (d->state) {
\r
183 case FlickablePrivate::Pressed:
\r
185 d->state = FlickablePrivate::Steady;
\r
187 QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonPress,
\r
188 d->pressPos, Qt::LeftButton,
\r
189 Qt::LeftButton, Qt::NoModifier);
\r
190 QMouseEvent *event2 = new QMouseEvent(*event);
\r
191 d->ignoreList << event1;
\r
192 d->ignoreList << event2;
\r
193 QApplication::postEvent(d->target, event1);
\r
194 QApplication::postEvent(d->target, event2);
\r
198 case FlickablePrivate::ManualScroll:
\r
200 delta = event->pos() - d->pressPos;
\r
201 if (d->timeStamp.elapsed() > 100) {
\r
202 d->timeStamp = QTime::currentTime();
\r
203 d->speed = delta - d->delta;
\r
206 d->offset = scrollOffset();
\r
207 d->pressPos = event->pos();
\r
208 if (d->speed == QPoint(0, 0)) {
\r
209 d->state = FlickablePrivate::Steady;
\r
212 d->state = FlickablePrivate::AutoScroll;
\r
213 d->ticker->start(20);
\r
217 case FlickablePrivate::Stop:
\r
219 d->state = FlickablePrivate::Steady;
\r
220 d->offset = scrollOffset();
\r
228 void Flickable::handleMouseMove(QMouseEvent *event)
\r
232 if (!(event->buttons() & Qt::LeftButton))
\r
235 if (d->ignoreList.removeAll(event))
\r
240 switch (d->state) {
\r
242 case FlickablePrivate::Pressed:
\r
243 case FlickablePrivate::Stop:
\r
244 delta = event->pos() - d->pressPos;
\r
245 if (delta.x() > d->threshold || delta.x() < -d->threshold ||
\r
246 delta.y() > d->threshold || delta.y() < -d->threshold) {
\r
247 d->timeStamp = QTime::currentTime();
\r
248 d->state = FlickablePrivate::ManualScroll;
\r
249 d->delta = QPoint(0, 0);
\r
250 d->pressPos = event->pos();
\r
255 case FlickablePrivate::ManualScroll:
\r
257 delta = event->pos() - d->pressPos;
\r
258 setScrollOffset(d->offset - delta);
\r
259 if (d->timeStamp.elapsed() > 100) {
\r
260 d->timeStamp = QTime::currentTime();
\r
261 d->speed = delta - d->delta;
\r
271 void Flickable::tick()
\r
273 if (d->state == FlickablePrivate:: AutoScroll) {
\r
274 d->speed = deaccelerate(d->speed);
\r
275 setScrollOffset(d->offset - d->speed);
\r
276 d->offset = scrollOffset();
\r
277 if (d->speed == QPoint(0, 0)) {
\r
278 d->state = FlickablePrivate::Steady;
\r