source: trunk/demos/embedded/flickable/flickable.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 7.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the demonstration applications 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 [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "flickable.h"
43
44#include <QtCore>
45#include <QtGui>
46
47class FlickableTicker: QObject
48{
49public:
50 FlickableTicker(Flickable *scroller) {
51 m_scroller = scroller;
52 }
53
54 void start(int interval) {
55 if (!m_timer.isActive())
56 m_timer.start(interval, this);
57 }
58
59 void stop() {
60 m_timer.stop();
61 }
62
63protected:
64 void timerEvent(QTimerEvent *event) {
65 Q_UNUSED(event);
66 m_scroller->tick();
67 }
68
69private:
70 Flickable *m_scroller;
71 QBasicTimer m_timer;
72};
73
74class FlickablePrivate
75{
76public:
77 typedef enum {
78 Steady,
79 Pressed,
80 ManualScroll,
81 AutoScroll,
82 Stop
83 } State;
84
85 State state;
86 int threshold;
87 QPoint pressPos;
88 QPoint offset;
89 QPoint delta;
90 QPoint speed;
91 FlickableTicker *ticker;
92 QTime timeStamp;
93 QWidget *target;
94 QList<QEvent*> ignoreList;
95};
96
97Flickable::Flickable()
98{
99 d = new FlickablePrivate;
100 d->state = FlickablePrivate::Steady;
101 d->threshold = 10;
102 d->ticker = new FlickableTicker(this);
103 d->timeStamp = QTime::currentTime();
104 d->target = 0;
105}
106
107Flickable::~Flickable()
108{
109 delete d;
110}
111
112void Flickable::setThreshold(int th)
113{
114 if (th >= 0)
115 d->threshold = th;
116}
117
118int Flickable::threshold() const
119{
120 return d->threshold;
121}
122
123void Flickable::setAcceptMouseClick(QWidget *target)
124{
125 d->target = target;
126}
127
128static QPoint deaccelerate(const QPoint &speed, int a = 1, int max = 64)
129{
130 int x = qBound(-max, speed.x(), max);
131 int y = qBound(-max, speed.y(), max);
132 x = (x == 0) ? x : (x > 0) ? qMax(0, x - a) : qMin(0, x + a);
133 y = (y == 0) ? y : (y > 0) ? qMax(0, y - a) : qMin(0, y + a);
134 return QPoint(x, y);
135}
136
137void Flickable::handleMousePress(QMouseEvent *event)
138{
139 event->ignore();
140
141 if (event->button() != Qt::LeftButton)
142 return;
143
144 if (d->ignoreList.removeAll(event))
145 return;
146
147 switch (d->state) {
148
149 case FlickablePrivate::Steady:
150 event->accept();
151 d->state = FlickablePrivate::Pressed;
152 d->pressPos = event->pos();
153 break;
154
155 case FlickablePrivate::AutoScroll:
156 event->accept();
157 d->state = FlickablePrivate::Stop;
158 d->speed = QPoint(0, 0);
159 d->pressPos = event->pos();
160 d->offset = scrollOffset();
161 d->ticker->stop();
162 break;
163
164 default:
165 break;
166 }
167}
168
169void Flickable::handleMouseRelease(QMouseEvent *event)
170{
171 event->ignore();
172
173 if (event->button() != Qt::LeftButton)
174 return;
175
176 if (d->ignoreList.removeAll(event))
177 return;
178
179 QPoint delta;
180
181 switch (d->state) {
182
183 case FlickablePrivate::Pressed:
184 event->accept();
185 d->state = FlickablePrivate::Steady;
186 if (d->target) {
187 QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonPress,
188 d->pressPos, Qt::LeftButton,
189 Qt::LeftButton, Qt::NoModifier);
190 QMouseEvent *event2 = new QMouseEvent(*event);
191 d->ignoreList << event1;
192 d->ignoreList << event2;
193 QApplication::postEvent(d->target, event1);
194 QApplication::postEvent(d->target, event2);
195 }
196 break;
197
198 case FlickablePrivate::ManualScroll:
199 event->accept();
200 delta = event->pos() - d->pressPos;
201 if (d->timeStamp.elapsed() > 100) {
202 d->timeStamp = QTime::currentTime();
203 d->speed = delta - d->delta;
204 d->delta = delta;
205 }
206 d->offset = scrollOffset();
207 d->pressPos = event->pos();
208 if (d->speed == QPoint(0, 0)) {
209 d->state = FlickablePrivate::Steady;
210 } else {
211 d->speed /= 4;
212 d->state = FlickablePrivate::AutoScroll;
213 d->ticker->start(20);
214 }
215 break;
216
217 case FlickablePrivate::Stop:
218 event->accept();
219 d->state = FlickablePrivate::Steady;
220 d->offset = scrollOffset();
221 break;
222
223 default:
224 break;
225 }
226}
227
228void Flickable::handleMouseMove(QMouseEvent *event)
229{
230 event->ignore();
231
232 if (!(event->buttons() & Qt::LeftButton))
233 return;
234
235 if (d->ignoreList.removeAll(event))
236 return;
237
238 QPoint delta;
239
240 switch (d->state) {
241
242 case FlickablePrivate::Pressed:
243 case FlickablePrivate::Stop:
244 delta = event->pos() - d->pressPos;
245 if (delta.x() > d->threshold || delta.x() < -d->threshold ||
246 delta.y() > d->threshold || delta.y() < -d->threshold) {
247 d->timeStamp = QTime::currentTime();
248 d->state = FlickablePrivate::ManualScroll;
249 d->delta = QPoint(0, 0);
250 d->pressPos = event->pos();
251 event->accept();
252 }
253 break;
254
255 case FlickablePrivate::ManualScroll:
256 event->accept();
257 delta = event->pos() - d->pressPos;
258 setScrollOffset(d->offset - delta);
259 if (d->timeStamp.elapsed() > 100) {
260 d->timeStamp = QTime::currentTime();
261 d->speed = delta - d->delta;
262 d->delta = delta;
263 }
264 break;
265
266 default:
267 break;
268 }
269}
270
271void Flickable::tick()
272{
273 if (d->state == FlickablePrivate:: AutoScroll) {
274 d->speed = deaccelerate(d->speed);
275 setScrollOffset(d->offset - d->speed);
276 d->offset = scrollOffset();
277 if (d->speed == QPoint(0, 0)) {
278 d->state = FlickablePrivate::Steady;
279 d->ticker->stop();
280 }
281 } else {
282 d->ticker->stop();
283 }
284}
Note: See TracBrowser for help on using the repository browser.