source: vendor/trolltech/current/src/kernel/qmovie.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 27.3 KB
Line 
1/****************************************************************************
2** $Id: qmovie.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of movie classes
5**
6** Created : 970617
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38// #define QT_SAVE_MOVIE_HACK
39
40#include "qtimer.h"
41#include "qpainter.h"
42#include "qptrlist.h"
43#include "qbitmap.h"
44#include "qmovie.h"
45#include "qfile.h"
46#include "qbuffer.h"
47#include "qobject.h"
48#include "qpixmapcache.h"
49
50#ifndef QT_NO_MOVIE
51
52#ifdef Q_WS_QWS
53#include "qgfx_qws.h"
54#endif
55
56#include "qasyncio.h"
57#include "qasyncimageio.h"
58
59#include <stdlib.h>
60
61/*!
62 \class QMovie qmovie.h
63 \brief The QMovie class provides incremental loading of animations or images, signalling as it progresses.
64
65 \ingroup images
66 \ingroup graphics
67 \ingroup multimedia
68 \mainclass
69
70 The simplest way to display a QMovie is to use a QLabel and
71 QLabel::setMovie().
72
73 A QMovie provides a QPixmap as the framePixmap(); connections can
74 be made via connectResize() and connectUpdate() to receive
75 notification of size and pixmap changes. All decoding is driven
76 by the normal event-processing mechanisms.
77
78 The movie begins playing as soon as the QMovie is created
79 (actually, once control returns to the event loop). When the last
80 frame in the movie has been played, it may loop back to the start
81 if such looping is defined in the input source.
82
83 QMovie objects are explicitly shared. This means that a QMovie
84 copied from another QMovie will be displaying the same frame at
85 all times. If one shared movie pauses, all pause. To make \e
86 independent movies, they must be constructed separately.
87
88 The set of data formats supported by QMovie is determined by the
89 decoder factories that have been installed; the format of the
90 input is determined as the input is decoded.
91
92 The supported formats are MNG (if Qt is configured with MNG
93 support enabled) and GIF (if Qt is configured with GIF support
94 enabled, see qgif.h).
95
96 If Qt is configured to support GIF reading, we are required to
97 state that "The Graphics Interchange Format(c) is the Copyright
98 property of CompuServe Incorporated. GIF(sm) is a Service Mark
99 property of CompuServe Incorporated.
100
101 \warning If you are in a country that recognizes software patents
102 and in which Unisys holds a patent on LZW compression and/or
103 decompression and you want to use GIF, Unisys may require you to
104 license that technology. Such countries include Canada, Japan,
105 the USA, France, Germany, Italy and the UK.
106
107 GIF support may be removed completely in a future version of Qt.
108 We recommend using the MNG or PNG format.
109
110 \img qmovie.png QMovie
111
112 \sa QLabel::setMovie()
113*/
114
115/*!
116 \enum QMovie::Status
117
118 \value SourceEmpty
119 \value UnrecognizedFormat
120 \value Paused
121 \value EndOfFrame
122 \value EndOfLoop
123 \value EndOfMovie
124 \value SpeedChanged
125*/
126
127class QMoviePrivate : public QObject, public QShared,
128 private QDataSink, private QImageConsumer
129{
130 Q_OBJECT
131
132public: // for QMovie
133
134 // Creates a null Private
135 QMoviePrivate();
136
137 // NOTE: The ownership of the QDataSource is transferred to the Private
138 QMoviePrivate(QDataSource* src, QMovie* movie, int bufsize);
139
140 virtual ~QMoviePrivate();
141
142 bool isNull() const;
143
144 // Initialize, possibly to the null state
145 void init(bool fully);
146 void flushBuffer();
147 void updatePixmapFromImage();
148 void updatePixmapFromImage(const QPoint& off, const QRect& area);
149 void showChanges();
150
151 // This as QImageConsumer
152 void changed(const QRect& rect);
153 void end();
154 void preFrameDone(); //util func
155 void frameDone();
156 void frameDone(const QPoint&, const QRect& rect);
157 void restartTimer();
158 void setLooping(int l);
159 void setFramePeriod(int milliseconds);
160 void setSize(int w, int h);
161
162 // This as QDataSink
163 int readyToReceive();
164 void receive(const uchar* b, int bytecount);
165 void eof();
166 void pause();
167
168signals:
169 void sizeChanged(const QSize&);
170 void areaChanged(const QRect&);
171 void dataStatus(int);
172
173public slots:
174 void refresh();
175
176public:
177 QMovie *that;
178 QWidget * display_widget;
179
180 QImageDecoder *decoder;
181
182 // Cyclic buffer
183 int buf_size;
184 uchar *buffer;
185 int buf_r, buf_w, buf_usage;
186
187 int framenumber;
188 int frameperiod;
189 int speed;
190 QTimer *frametimer;
191 int lasttimerinterval;
192 int loop;
193 bool movie_ended;
194 bool dirty_cache;
195 bool waitingForFrameTick;
196 int stepping;
197 QRect changed_area;
198 QRect valid_area;
199 QDataPump *pump;
200 QDataSource *source;
201 QPixmap mypixmap;
202 QBitmap mymask;
203 QColor bg;
204
205 int error;
206 bool empty;
207
208#ifdef QT_SAVE_MOVIE_HACK
209 bool save_image;
210 int image_number;
211#endif
212};
213
214
215QMoviePrivate::QMoviePrivate()
216{
217 dirty_cache = FALSE;
218 buffer = 0;
219 pump = 0;
220 source = 0;
221 decoder = 0;
222 display_widget=0;
223 buf_size = 0;
224 init(FALSE);
225}
226
227// NOTE: The ownership of the QDataSource is transferred to the Private
228QMoviePrivate::QMoviePrivate(QDataSource* src, QMovie* movie, int bufsize) :
229 that(movie),
230 buf_size(bufsize)
231{
232 frametimer = new QTimer(this);
233 pump = src ? new QDataPump(src, this) : 0;
234 QObject::connect(frametimer, SIGNAL(timeout()), this, SLOT(refresh()));
235 dirty_cache = FALSE;
236 source = src;
237 buffer = 0;
238 decoder = 0;
239 speed = 100;
240 display_widget=0;
241 init(TRUE);
242}
243
244QMoviePrivate::~QMoviePrivate()
245{
246 if ( buffer ) // Avoid purify complaint
247 delete [] buffer;
248 delete pump;
249 delete decoder;
250 delete source;
251
252 // Too bad.. but better be safe than sorry
253 if ( dirty_cache )
254 QPixmapCache::clear();
255}
256
257bool QMoviePrivate::isNull() const
258{
259 return !buf_size;
260}
261
262// Initialize. Only actually allocate any space if \a fully is TRUE,
263// otherwise, just enough to be a valid null Private.
264void QMoviePrivate::init(bool fully)
265{
266#ifdef QT_SAVE_MOVIE_HACK
267 save_image = TRUE;
268 image_number = 0;
269#endif
270
271 buf_usage = buf_r = buf_w = 0;
272 if ( buffer ) // Avoid purify complaint
273 delete [] buffer;
274 buffer = fully ? new uchar[buf_size] : 0;
275 if ( buffer )
276 memset( buffer, 0, buf_size );
277
278 delete decoder;
279 decoder = fully ? new QImageDecoder(this) : 0;
280
281#ifdef AVOID_OPEN_FDS
282 if ( source && !source->isOpen() )
283 source->open(IO_ReadOnly);
284#endif
285
286 waitingForFrameTick = FALSE;
287 stepping = -1;
288 framenumber = 0;
289 frameperiod = -1;
290 if (fully) frametimer->stop();
291 lasttimerinterval = -1;
292 changed_area.setRect(0,0,-1,-1);
293 valid_area = changed_area;
294 loop = -1;
295 movie_ended = FALSE;
296 error = 0;
297 empty = TRUE;
298}
299
300void QMoviePrivate::flushBuffer()
301{
302 int used;
303 while (buf_usage && !waitingForFrameTick && stepping != 0 && !error) {
304 used = decoder->decode(buffer + buf_r, QMIN(buf_usage, buf_size - buf_r));
305 if (used <= 0) {
306 if ( used < 0 ) {
307 error = 1;
308 emit dataStatus(QMovie::UnrecognizedFormat);
309 }
310 break;
311 }
312 buf_r = (buf_r + used) % buf_size;
313 buf_usage -= used;
314 }
315
316 // Some formats, like MNG, can make stuff happen without any extra data.
317 // Only do this if the movie hasn't ended, however or we'll never get the end of loop signal.
318 if (!movie_ended) {
319 used = decoder->decode(buffer + buf_r, 0);
320 if (used <= 0) {
321 if ( used < 0 ) {
322 error = 1;
323 emit dataStatus(QMovie::UnrecognizedFormat);
324 }
325 }
326 }
327
328 if (error)
329 frametimer->stop();
330 maybeReady();
331}
332
333void QMoviePrivate::updatePixmapFromImage()
334{
335 if (changed_area.isEmpty()) return;
336 updatePixmapFromImage(QPoint(0,0),changed_area);
337}
338
339void QMoviePrivate::updatePixmapFromImage(const QPoint& off,
340 const QRect& area)
341{
342 // Create temporary QImage to hold the part we want
343 const QImage& gimg = decoder->image();
344 QImage img = gimg.copy(area);
345
346#ifdef QT_SAVE_MOVIE_HACK
347 if ( save_image ) {
348 QString name;
349 name.sprintf("movie%i.ppm",image_number++);
350 gimg.save( name, "PPM" );
351 }
352#endif
353
354 // Resize to size of image
355 if (mypixmap.width() != gimg.width() || mypixmap.height() != gimg.height())
356 mypixmap.resize(gimg.width(), gimg.height());
357
358 // Convert to pixmap and paste that onto myself
359 QPixmap lines;
360
361#ifndef QT_NO_SPRINTF
362 if (!(frameperiod < 0 && loop == -1)) {
363 // its an animation, lets see if we converted
364 // this frame already.
365 QString key;
366 key.sprintf( "%08lx:%04d", ( long )this, framenumber );
367 if ( !QPixmapCache::find( key, lines ) ) {
368 lines.convertFromImage(img, Qt::ColorOnly);
369 QPixmapCache::insert( key, lines );
370 dirty_cache = TRUE;
371 }
372 } else
373#endif
374 {
375 lines.convertFromImage(img, Qt::ColorOnly);
376 }
377
378 if (bg.isValid()) {
379 QPainter p;
380 p.begin(&mypixmap);
381 p.fillRect(area, bg);
382 p.drawPixmap(area, lines);
383 p.end();
384 } else {
385 if (gimg.hasAlphaBuffer()) {
386 // Resize to size of image
387 if (mymask.isNull()) {
388 mymask.resize(gimg.width(), gimg.height());
389 mymask.fill( Qt::color1 );
390 }
391 }
392 mypixmap.setMask(QBitmap()); // Remove reference to my mask
393 copyBlt( &mypixmap, area.left(), area.top(),
394 &lines, off.x(), off.y(), area.width(), area.height() );
395 }
396
397#ifdef Q_WS_QWS
398 if(display_widget) {
399 QGfx * mygfx=display_widget->graphicsContext();
400 if(mygfx) {
401 double xscale,yscale;
402 xscale=display_widget->width();
403 yscale=display_widget->height();
404 xscale=xscale/((double)mypixmap.width());
405 yscale=yscale/((double)mypixmap.height());
406 double xh,yh;
407 xh=xscale*((double)area.left());
408 yh=yscale*((double)area.top());
409 mygfx->setSource(&mypixmap);
410 mygfx->setAlphaType(QGfx::IgnoreAlpha);
411 mygfx->stretchBlt(0,0,display_widget->width(),
412 display_widget->height(),mypixmap.width(),
413 mypixmap.height());
414 delete mygfx;
415 }
416 }
417#endif
418}
419
420void QMoviePrivate::showChanges()
421{
422 if (changed_area.isValid()) {
423 updatePixmapFromImage();
424
425 valid_area = valid_area.unite(changed_area);
426 emit areaChanged(changed_area);
427
428 changed_area.setWidth(-1); // make empty
429 }
430}
431
432// Private as QImageConsumer
433void QMoviePrivate::changed(const QRect& rect)
434{
435 if (!frametimer->isActive())
436 frametimer->start(0);
437 changed_area = changed_area.unite(rect);
438}
439
440void QMoviePrivate::end()
441{
442 movie_ended = TRUE;
443}
444
445void QMoviePrivate::preFrameDone()
446{
447 if (stepping > 0) {
448 stepping--;
449 if (!stepping) {
450 frametimer->stop();
451 emit dataStatus( QMovie::Paused );
452 }
453 } else {
454 waitingForFrameTick = TRUE;
455 restartTimer();
456 }
457}
458void QMoviePrivate::frameDone()
459{
460 preFrameDone();
461 showChanges();
462 emit dataStatus(QMovie::EndOfFrame);
463 framenumber++;
464}
465void QMoviePrivate::frameDone(const QPoint& p,
466 const QRect& rect)
467{
468 preFrameDone();
469 const QImage& gimg = decoder->image();
470 if (framenumber==0)
471 emit sizeChanged(gimg.size());
472 valid_area = valid_area.unite(QRect(p,rect.size()));
473 updatePixmapFromImage(p,rect);
474 emit areaChanged(QRect(p,rect.size()));
475 emit dataStatus(QMovie::EndOfFrame);
476 framenumber++;
477}
478
479void QMoviePrivate::restartTimer()
480{
481 if (speed > 0) {
482 int i = frameperiod >= 0 ? frameperiod * 100/speed : 0;
483 if ( i != lasttimerinterval || !frametimer->isActive() ) {
484 lasttimerinterval = i;
485 frametimer->start( i );
486 }
487 } else {
488 frametimer->stop();
489 }
490}
491
492void QMoviePrivate::setLooping(int nloops)
493{
494 if (loop == -1) { // Only if we don't already know how many loops!
495 if (source && source->rewindable()) {
496 source->enableRewind(TRUE);
497 loop = nloops;
498 } else {
499 // Cannot loop from this source
500 loop = -2;
501 }
502 }
503}
504
505void QMoviePrivate::setFramePeriod(int milliseconds)
506{
507 // Animation: only show complete frame
508 frameperiod = milliseconds;
509 if (stepping<0 && frameperiod >= 0) restartTimer();
510}
511
512void QMoviePrivate::setSize(int w, int h)
513{
514 if (mypixmap.width() != w || mypixmap.height() != h) {
515 mypixmap.resize(w, h);
516 emit sizeChanged(QSize(w, h));
517 }
518}
519
520
521// Private as QDataSink
522
523int QMoviePrivate::readyToReceive()
524{
525 // Could pre-fill buffer, but more efficient to just leave the
526 // data back at the source.
527 return (waitingForFrameTick || !stepping || buf_usage || error)
528 ? 0 : buf_size;
529}
530
531void QMoviePrivate::receive(const uchar* b, int bytecount)
532{
533 if ( bytecount ) empty = FALSE;
534
535 while (bytecount && !waitingForFrameTick && stepping != 0) {
536 int used = decoder->decode(b, bytecount);
537 if (used<=0) {
538 if ( used < 0 ) {
539 error = 1;
540 emit dataStatus(QMovie::UnrecognizedFormat);
541 }
542 break;
543 }
544 b+=used;
545 bytecount-=used;
546 }
547
548 // Append unused to buffer
549 while (bytecount--) {
550 buffer[buf_w] = *b++;
551 buf_w = (buf_w+1)%buf_size;
552 buf_usage++;
553 }
554}
555
556void QMoviePrivate::eof()
557{
558 if ( !movie_ended )
559 return;
560
561 if ( empty )
562 emit dataStatus(QMovie::SourceEmpty);
563
564#ifdef QT_SAVE_MOVIE_HACK
565 save_image = FALSE;
566#endif
567
568 emit dataStatus(QMovie::EndOfLoop);
569
570 if (loop >= 0) {
571 if (loop) {
572 loop--;
573 if (!loop) return;
574 }
575 delete decoder;
576 decoder = new QImageDecoder(this);
577 source->rewind();
578 framenumber = 0;
579 movie_ended = FALSE;
580 } else {
581 delete decoder;
582 decoder = 0;
583 if ( buffer ) // Avoid purify complaint
584 delete [] buffer;
585 buffer = 0;
586 emit dataStatus(QMovie::EndOfMovie);
587#ifdef AVOID_OPEN_FDS
588 if ( source )
589 source->close();
590#endif
591 }
592}
593
594void QMoviePrivate::pause()
595{
596 if ( stepping ) {
597 stepping = 0;
598 frametimer->stop();
599 emit dataStatus( QMovie::Paused );
600 }
601}
602
603void QMoviePrivate::refresh()
604{
605 if (!decoder) {
606 frametimer->stop();
607 return;
608 }
609
610 if (frameperiod < 0 && loop == -1) {
611 // Only show changes if probably not an animation
612 showChanges();
613 }
614
615 if (!buf_usage) {
616 frametimer->stop();
617 }
618
619 waitingForFrameTick = FALSE;
620 flushBuffer();
621}
622
623///////////////// End of Private /////////////////
624
625
626
627
628
629/*!
630 Constructs a null QMovie. The only interesting thing to do with
631 such a movie is to assign another movie to it.
632
633 \sa isNull()
634*/
635QMovie::QMovie()
636{
637 d = new QMoviePrivate();
638}
639
640/*!
641 Constructs a QMovie with an external data source. You should later
642 call pushData() to send incoming animation data to the movie.
643
644 The \a bufsize argument sets the maximum amount of data the movie
645 will transfer from the data source per event loop. The lower this
646 value, the better interleaved the movie playback will be with
647 other event processing, but the slower the overall processing will
648 be.
649
650 \sa pushData()
651*/
652QMovie::QMovie(int bufsize)
653{
654 d = new QMoviePrivate(0, this, bufsize);
655}
656
657/*!
658 Returns the maximum amount of data that can currently be pushed
659 into the movie by a call to pushData(). This is affected by the
660 initial buffer size, but varies as the movie plays and data is
661 consumed.
662*/
663int QMovie::pushSpace() const
664{
665 return d->readyToReceive();
666}
667
668/*!
669 Pushes \a length bytes from \a data into the movie. \a length must
670 be no more than the amount returned by pushSpace() since the
671 previous call to pushData().
672*/
673void QMovie::pushData(const uchar* data, int length)
674{
675 d->receive(data,length);
676}
677
678#ifdef Q_WS_QWS // ##### Temporary performance experiment
679/*!
680 \internal
681*/
682void QMovie::setDisplayWidget(QWidget * w)
683{
684 d->display_widget=w;
685}
686#endif
687
688/*!
689 Constructs a QMovie that reads an image sequence from the given
690 data source, \a src. The source must be allocated dynamically,
691 because QMovie will take ownership of it and will destroy it when
692 the movie is destroyed. The movie starts playing as soon as event
693 processing continues.
694
695 The \a bufsize argument sets the maximum amount of data the movie
696 will transfer from the data source per event loop. The lower this
697 value, the better interleaved the movie playback will be with
698 other event processing, but the slower the overall processing will
699 be.
700*/
701QMovie::QMovie(QDataSource* src, int bufsize)
702{
703 d = new QMoviePrivate(src, this, bufsize);
704}
705
706/*!
707 Constructs a QMovie that reads an image sequence from the file, \a
708 fileName.
709
710 The \a bufsize argument sets the maximum amount of data the movie
711 will transfer from the data source per event loop. The lower this
712 value, the better interleaved the movie playback will be with
713 other event processing, but the slower the overall processing will
714 be.
715*/
716QMovie::QMovie(const QString &fileName, int bufsize)
717{
718 QFile* file = new QFile(fileName);
719 if ( !fileName.isEmpty() )
720 file->open(IO_ReadOnly);
721 d = new QMoviePrivate(new QIODeviceSource(file, bufsize), this, bufsize);
722}
723
724/*!
725 Constructs a QMovie that reads an image sequence from the byte
726 array, \a data.
727
728 The \a bufsize argument sets the maximum amount of data the movie
729 will transfer from the data source per event loop. The lower this
730 value, the better interleaved the movie playback will be with
731 other event processing, but the slower the overall processing will
732 be.
733*/
734QMovie::QMovie(QByteArray data, int bufsize)
735{
736 QBuffer* buffer = new QBuffer(data);
737 buffer->open(IO_ReadOnly);
738 d = new QMoviePrivate(new QIODeviceSource(buffer, bufsize), this, bufsize);
739}
740
741/*!
742 Constructs a movie that uses the same data as movie \a movie.
743 QMovies use explicit sharing, so operations on the copy will
744 affect both.
745*/
746QMovie::QMovie(const QMovie& movie)
747{
748 d = movie.d;
749 d->ref();
750}
751
752/*!
753 Destroys the QMovie. If this is the last reference to the data of
754 the movie, the data is deallocated.
755*/
756QMovie::~QMovie()
757{
758 if (d->deref()) delete d;
759}
760
761/*!
762 Returns TRUE if the movie is null; otherwise returns FALSE.
763*/
764bool QMovie::isNull() const
765{
766 return d->isNull();
767}
768
769/*!
770 Makes this movie use the same data as movie \a movie. QMovies use
771 explicit sharing.
772*/
773QMovie& QMovie::operator=(const QMovie& movie)
774{
775 movie.d->ref();
776 if (d->deref()) delete d;
777 d = movie.d;
778 return *this;
779}
780
781
782/*!
783 Sets the background color of the pixmap to \a c. If the background
784 color isValid(), the pixmap will never have a mask because the
785 background color will be used in transparent regions of the image.
786
787 \sa backgroundColor()
788*/
789void QMovie::setBackgroundColor(const QColor& c)
790{
791 d->bg = c;
792}
793
794/*!
795 Returns the background color of the movie set by
796 setBackgroundColor().
797*/
798const QColor& QMovie::backgroundColor() const
799{
800 return d->bg;
801}
802
803/*!
804 Returns the area of the pixmap for which pixels have been
805 generated.
806*/
807const QRect& QMovie::getValidRect() const
808{
809 return d->valid_area;
810}
811
812/*!
813 Returns the current frame of the movie, as a QPixmap. It is not
814 generally useful to keep a copy of this pixmap. It is better to
815 keep a copy of the QMovie and get the framePixmap() only when
816 needed for drawing.
817
818 \sa frameImage()
819*/
820const QPixmap& QMovie::framePixmap() const
821{
822 return d->mypixmap;
823}
824
825/*!
826 Returns the current frame of the movie, as a QImage. It is not
827 generally useful to keep a copy of this image. Also note that you
828 must not call this function if the movie is finished(), since by
829 then the image will not be available.
830
831 \sa framePixmap()
832*/
833const QImage& QMovie::frameImage() const
834{
835 return d->decoder->image();
836}
837
838/*!
839 Returns the number of steps remaining after a call to step(). If
840 the movie is paused, steps() returns 0. If it's running normally
841 or is finished, steps() returns a negative number.
842*/
843int QMovie::steps() const
844{
845 return d->stepping;
846}
847
848/*!
849 Returns the number of times EndOfFrame has been emitted since the
850 start of the current loop of the movie. Thus, before any
851 EndOfFrame has been emitted the value will be 0; within slots
852 processing the first signal, frameNumber() will be 1, and so on.
853*/
854int QMovie::frameNumber() const { return d->framenumber; }
855
856/*!
857 Returns TRUE if the image is paused; otherwise returns FALSE.
858*/
859bool QMovie::paused() const
860{
861 return d->stepping == 0;
862}
863
864/*!
865 Returns TRUE if the image is no longer playing: this happens when
866 all loops of all frames are complete; otherwise returns FALSE.
867*/
868bool QMovie::finished() const
869{
870 return !d->decoder;
871}
872
873/*!
874 Returns TRUE if the image is not single-stepping, not paused, and
875 not finished; otherwise returns FALSE.
876*/
877bool QMovie::running() const
878{
879 return d->stepping<0 && d->decoder;
880}
881
882/*!
883 Pauses the progress of the animation.
884
885 \sa unpause()
886*/
887void QMovie::pause()
888{
889 d->pause();
890}
891
892/*!
893 Unpauses the progress of the animation.
894
895 \sa pause()
896*/
897void QMovie::unpause()
898{
899 if ( d->stepping >= 0 ) {
900 if (d->isNull())
901 return;
902 d->stepping = -1;
903 d->restartTimer();
904 }
905}
906
907/*!
908 \overload
909
910 Steps forward, showing \a steps frames, and then pauses.
911*/
912void QMovie::step(int steps)
913{
914 if (d->isNull())
915 return;
916 d->stepping = steps;
917 d->frametimer->start(0);
918 d->waitingForFrameTick = FALSE; // Full speed ahead!
919}
920
921/*!
922 Steps forward 1 frame and then pauses.
923*/
924void QMovie::step()
925{
926 step(1);
927}
928
929/*!
930 Rewinds the movie to the beginning. If the movie has not been
931 paused, it begins playing again.
932*/
933void QMovie::restart()
934{
935 if (d->isNull())
936 return;
937 if (d->source->rewindable()) {
938 d->source->enableRewind(TRUE);
939 d->source->rewind();
940 int s = d->stepping;
941 d->init(TRUE);
942 if ( s>0 )
943 step(s);
944 else if ( s==0 )
945 pause();
946 }
947}
948
949/*!
950 Returns the movie's play speed as a percentage. The default is 100
951 percent.
952
953 \sa setSpeed()
954*/
955int QMovie::speed() const
956{
957 return d->speed;
958}
959
960/*!
961 Sets the movie's play speed as a percentage, to \a percent. This
962 is a percentage of the speed dictated by the input data format.
963 The default is 100 percent.
964*/
965void QMovie::setSpeed(int percent)
966{
967 int oldspeed = d->speed;
968 if ( oldspeed != percent && percent >= 0 ) {
969 d->speed = percent;
970 // Restart timer only if really needed
971 if (d->stepping < 0) {
972 if ( !percent || !oldspeed // To or from zero
973 || oldspeed*4 / percent > 4 // More than 20% slower
974 || percent*4 / oldspeed > 4 // More than 20% faster
975 )
976 d->restartTimer();
977 }
978 }
979}
980
981/*!
982 Connects the \a{receiver}'s \a member of type \c{void member(const
983 QSize&)} so that it is signalled when the movie changes size.
984
985 Note that due to the explicit sharing of QMovie objects, these
986 connections persist until they are explicitly disconnected with
987 disconnectResize() or until \e every shared copy of the movie is
988 deleted.
989*/
990void QMovie::connectResize(QObject* receiver, const char *member)
991{
992 QObject::connect(d, SIGNAL(sizeChanged(const QSize&)), receiver, member);
993}
994
995/*!
996 Disconnects the \a{receiver}'s \a member (or all members if \a
997 member is zero) that were previously connected by connectResize().
998*/
999void QMovie::disconnectResize(QObject* receiver, const char *member)
1000{
1001 QObject::disconnect(d, SIGNAL(sizeChanged(const QSize&)), receiver, member);
1002}
1003
1004/*!
1005 Connects the \a{receiver}'s \a member of type \c{void member(const
1006 QRect&)} so that it is signalled when an area of the framePixmap()
1007 has changed since the previous frame.
1008
1009 Note that due to the explicit sharing of QMovie objects, these
1010 connections persist until they are explicitly disconnected with
1011 disconnectUpdate() or until \e every shared copy of the movie is
1012 deleted.
1013*/
1014void QMovie::connectUpdate(QObject* receiver, const char *member)
1015{
1016 QObject::connect(d, SIGNAL(areaChanged(const QRect&)), receiver, member);
1017}
1018
1019/*!
1020 Disconnects the \a{receiver}'s \a member (or all members if \q
1021 member is zero) that were previously connected by connectUpdate().
1022*/
1023void QMovie::disconnectUpdate(QObject* receiver, const char *member)
1024{
1025 QObject::disconnect(d, SIGNAL(areaChanged(const QRect&)), receiver, member);
1026}
1027
1028/*!
1029 Connects the \a{receiver}'s \a member, of type \c{void
1030 member(int)} so that it is signalled when the movie changes
1031 status. The status codes are negative for errors and positive for
1032 information.
1033
1034 \table
1035 \header \i Status Code \i Meaning
1036 \row \i QMovie::SourceEmpty
1037 \i signalled if the input cannot be read.
1038 \row \i QMovie::UnrecognizedFormat
1039 \i signalled if the input data is unrecognized.
1040 \row \i QMovie::Paused
1041 \i signalled when the movie is paused by a call to paused()
1042 or by after \link step() stepping \endlink pauses.
1043 \row \i QMovie::EndOfFrame
1044 \i signalled at end-of-frame after any update and Paused signals.
1045 \row \i QMovie::EndOfLoop
1046 \i signalled at end-of-loop, after any update signals,
1047 EndOfFrame - but before EndOfMovie.
1048 \row \i QMovie::EndOfMovie
1049 \i signalled when the movie completes and is not about to loop.
1050 \endtable
1051
1052 More status messages may be added in the future, so a general test
1053 for errors would test for negative.
1054
1055 Note that due to the explicit sharing of QMovie objects, these
1056 connections persist until they are explicitly disconnected with
1057 disconnectStatus() or until \e every shared copy of the movie is
1058 deleted.
1059*/
1060void QMovie::connectStatus(QObject* receiver, const char *member)
1061{
1062 QObject::connect(d, SIGNAL(dataStatus(int)), receiver, member);
1063}
1064
1065/*!
1066 Disconnects the \a{receiver}'s \a member (or all members if \a
1067 member is zero) that were previously connected by connectStatus().
1068*/
1069void QMovie::disconnectStatus(QObject* receiver, const char *member)
1070{
1071 QObject::disconnect(d, SIGNAL(dataStatus(int)), receiver, member);
1072}
1073
1074
1075#include "qmovie.moc"
1076
1077#endif // QT_NO_MOVIE
Note: See TracBrowser for help on using the repository browser.