source: psi/trunk/libpsi/iconset/anim.cpp@ 59

Last change on this file since 59 was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 7.7 KB
Line 
1/*
2 * anim.cpp - class for handling animations
3 * Copyright (C) 2003 Michail Pishchagin
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include "anim.h"
22#include "iconset.h"
23
24#include <qobject.h>
25#include <qasyncimageio.h>
26#include <qptrvector.h>
27#include <qtimer.h>
28#include <qapplication.h>
29
30#include "psimng.h"
31
32/*!
33 \class Anim
34 \brief Class for handling animations
35
36 Anim is a class that can load animations. Generally, it looks like
37 QMovie but it loads animations in one pass and stores it in memory.
38
39 Each frame of Anim is stored as Impix.
40*/
41
42//! \if _hide_doc_
43class Anim::Private : public QObject, public QShared, private QImageConsumer
44{
45 Q_OBJECT
46public:
47 QImageDecoder *decoder;
48 QTimer *frametimer;
49
50 bool empty;
51 bool paused;
52
53 int speed;
54 int lasttimerinterval, frameperiod;
55
56 int looping, loop;
57
58 class Frame {
59 public:
60 Frame(Impix *i, int p)
61 {
62 impix = i;
63 period = p;
64 }
65 ~Frame()
66 {
67 delete impix;
68 }
69 Frame(const Frame &from)
70 {
71 impix = new Impix( *from.impix );
72 period = from.period;
73 }
74
75 Impix *impix;
76 int period;
77 };
78
79 QPtrVector<Frame> frames;
80 int frame;
81
82public:
83 void init()
84 {
85 frames.setAutoDelete(true);
86
87 frametimer = new QTimer(this);
88 QObject::connect(frametimer, SIGNAL(timeout()), this, SLOT(refresh()));
89
90 speed = 120;
91 lasttimerinterval = -1;
92 frameperiod = 120;
93
94 looping = 0; // MNG movies doesn't contain loop flag?
95 loop = 0;
96 frame = 0;
97 paused = true;
98 }
99
100 Private()
101 {
102 init();
103 }
104
105 Private(const Private &from)
106 : QObject(), QShared(), QImageConsumer()
107 {
108 init();
109
110 speed = from.speed;
111 lasttimerinterval = from.lasttimerinterval;
112 frameperiod = from.frameperiod;
113 looping = from.looping;
114 loop = from.loop;
115 frame = from.frame;
116 paused = from.paused;
117
118 for ( uint i = 0; i < from.frames.count(); i++ ) {
119 frames.resize ( frames.count()+1 );
120 frames.insert ( frames.count(), new Frame( *from.frames[i] ) );
121 }
122
123 if ( !paused )
124 unpause();
125 }
126
127 Private(const QByteArray ba)
128 {
129 init();
130
131 qApp->lock();
132 decoder = new QImageDecoder(this);
133
134 uchar *buf = reinterpret_cast<uchar *>(ba.data());
135 int bytecount = ba.count();
136 bool finished = false;
137 while ( bytecount && !finished ) {
138 // if you want decent MNG support, please do initPsiMngIO() (../psipng/psimng.h)
139
140 // TODO: what number of cycles require MNG movies for normal display?
141 //for (int i = 0; i < 10; i++) { // the more is counter, more frames MNG animation will give :)
142 //int used = decoder->decode(buf, !i ? bytecount : 0);
143 int used = decoder->decode(buf, bytecount);
144 if ( used < 0 ) {
145 qWarning("Anim::loadAnim(): Unrecognized Format error");
146 finished = true;
147 break;
148 }
149 buf += used;
150 bytecount -= used;
151 //}
152 }
153
154 delete decoder;
155 qApp->unlock();
156 //qWarning("Anim:: %d frames", numFrames());
157 }
158
159 ~Private()
160 {
161 if ( frametimer )
162 delete frametimer;
163 }
164
165 void pause()
166 {
167 paused = true;
168 frametimer->stop();
169 }
170
171 void unpause()
172 {
173 paused = false;
174 restartTimer();
175 }
176
177 void restart()
178 {
179 frame = 0;
180 if ( !paused )
181 restartTimer();
182 }
183
184 int numFrames() const
185 {
186 return frames.count();
187 }
188
189 void restartTimer()
190 {
191 if ( !paused && speed > 0 ) {
192 frameperiod = frames[frame]->period;
193 int i = frameperiod >= 0 ? frameperiod * 100/speed : 0;
194 if ( i != lasttimerinterval || !frametimer->isActive() ) {
195 lasttimerinterval = i;
196 frametimer->start( i );
197 }
198 } else {
199 frametimer->stop();
200 }
201 }
202
203 // QImageConsumer
204 void end()
205 {
206 }
207
208 void changed(const QRect &)
209 {
210 }
211
212 void frameDone()
213 {
214 frames.resize ( frames.count()+1 );
215 frames.insert ( frames.count(), new Frame(new Impix( decoder->image() ), frameperiod) );
216 }
217
218 void frameDone(const QPoint &, const QRect &)
219 {
220 frameDone();
221 }
222
223 void setLooping(int l)
224 {
225 looping = l;
226 }
227
228 void setFramePeriod(int period)
229 {
230 frameperiod = period;
231 }
232
233 void setSize(int, int)
234 {
235 }
236
237signals:
238 void areaChanged();
239
240public slots:
241 void refresh()
242 {
243 frame++;
244 if ( frame >= numFrames() ) {
245 frame = 0;
246
247 loop++;
248 if ( looping && loop >= looping ) {
249 frame = numFrames() - 1;
250 pause();
251 restart();
252 }
253 }
254
255 emit areaChanged();
256 restartTimer();
257 }
258};
259//! \endif
260
261//!
262//! Creates an empty animation.
263Anim::Anim()
264{
265 d = new Private();
266}
267
268//!
269//! Creates animation from QByteArray \a data.
270Anim::Anim(const QByteArray &data)
271{
272 d = new Private(data);
273}
274
275//!
276//! Creates shared copy of Anim \a anim.
277Anim::Anim(const Anim &anim)
278{
279 d = anim.d;
280 d->ref();
281}
282
283//!
284//! Deletes animation.
285Anim::~Anim()
286{
287 if ( d->deref() )
288 delete d;
289}
290
291//!
292//! Returns QPixmap of current frame.
293const QPixmap &Anim::framePixmap() const
294{
295 return d->frames[d->frame]->impix->pixmap();
296}
297
298//!
299//! Returns QImage of current frame.
300const QImage &Anim::frameImage() const
301{
302 return d->frames[d->frame]->impix->image();
303}
304
305//!
306//! Returns Impix of current frame.
307const Impix &Anim::frameImpix() const
308{
309 return *d->frames[d->frame]->impix;
310}
311
312//!
313//! Returns total number of frames in animation.
314int Anim::numFrames() const
315{
316 return d->frames.count();
317}
318
319//!
320//! Returns the number of current animation frame.
321int Anim::framenumber() const
322{
323 return d->frame;
324}
325
326//!
327//! Returns Impix of animation frame number \a n.
328const Impix &Anim::frame(int n) const
329{
330 return *d->frames[n]->impix;
331}
332
333//!
334//! Returns \c true if numFrames() == 0 and \c false otherwise.
335bool Anim::isNull() const
336{
337 return !numFrames();
338}
339
340//!
341//! Returns \c true when animation is paused.
342bool Anim::paused() const
343{
344 return d->paused;
345}
346
347//!
348//! Continues the animation playback.
349void Anim::unpause()
350{
351 if ( !isNull() && paused() )
352 d->unpause();
353}
354
355//!
356//! Pauses the animation.
357void Anim::pause()
358{
359 if ( !isNull() && !paused() )
360 d->pause();
361}
362
363//!
364//! Starts animation from the very beginning.
365void Anim::restart()
366{
367 if ( !isNull() )
368 d->restart();
369}
370
371/*!
372 Connects internal signal with specified slot \a member of object \a receiver, which
373 is emitted when animation changes its frame.
374
375 \code
376 class MyObject : public QObject {
377 Q_OBJECT
378 // ...
379 public slots:
380 void animUpdated();
381 // ...
382 void foo (Anim *anim) {
383 anim->connectUpdate( this, SLOT(animUpdated()) );
384 }
385 }
386 \endcode
387
388 \sa disconnectUpdate()
389*/
390void Anim::connectUpdate(QObject *receiver, const char *member)
391{
392 QObject::connect(d, SIGNAL(areaChanged()), receiver, member);
393}
394
395//!
396//! Disconnects slot \a member, which was prevously connected with connectUpdate().
397//! \sa connectUpdate()
398void Anim::disconnectUpdate(QObject *receiver, const char *member)
399{
400 QObject::disconnect(d, SIGNAL(areaChanged()), receiver, member);
401}
402
403Anim Anim::copy() const
404{
405 Anim anim( *this );
406 anim.d->deref();
407 anim.d = new Private( *this->d );
408
409 return anim;
410}
411
412void Anim::detach()
413{
414 if ( d->count > 1 )
415 *this = copy();
416}
417
418//!
419//! Strips the first animation frame, if there is more than one frame.
420void Anim::stripFirstFrame()
421{
422 if ( numFrames() > 1 ) {
423 QPtrVector<Private::Frame> frames;
424 for ( uint i = 1; i < d->frames.count(); i++ ) {
425 frames.resize ( frames.count()+1 );
426 frames.insert ( frames.count(), new Private::Frame( *d->frames[i] ) );
427 }
428
429 d->frames.clear();
430 d->frames = frames;
431
432 if ( !paused() )
433 restart();
434 }
435}
436
437#include "anim.moc"
Note: See TracBrowser for help on using the repository browser.