diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/gui/image/qmovie.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/gui/image/qmovie.cpp')
-rw-r--r-- | src/gui/image/qmovie.cpp | 1081 |
1 files changed, 1081 insertions, 0 deletions
diff --git a/src/gui/image/qmovie.cpp b/src/gui/image/qmovie.cpp new file mode 100644 index 0000000..ca69cab --- /dev/null +++ b/src/gui/image/qmovie.cpp @@ -0,0 +1,1081 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QMovie + + \brief The QMovie class is a convenience class for playing movies + with QImageReader. + + \ingroup multimedia + + First, create a QMovie object by passing either the name of a file or a + pointer to a QIODevice containing an animated image format to QMovie's + constructor. You can call isValid() to check if the image data is valid, + before starting the movie. To start the movie, call start(). QMovie will + enter \l Running state, and emit started() and stateChanged(). To get the + current state of the movie, call state(). + + To display the movie in your application, you can pass your QMovie object + to QLabel::setMovie(). Example: + + \snippet doc/src/snippets/code/src_gui_image_qmovie.cpp 0 + + Whenever a new frame is available in the movie, QMovie will emit + updated(). If the size of the frame changes, resized() is emitted. You can + call currentImage() or currentPixmap() to get a copy of the current + frame. When the movie is done, QMovie emits finished(). If any error + occurs during playback (i.e, the image file is corrupt), QMovie will emit + error(). + + You can control the speed of the movie playback by calling setSpeed(), + which takes the percentage of the original speed as an argument. Pause the + movie by calling setPaused(true). QMovie will then enter \l Paused state + and emit stateChanged(). If you call setPaused(false), QMovie will reenter + \l Running state and start the movie again. To stop the movie, call + stop(). + + Certain animation formats allow you to set the background color. You can + call setBackgroundColor() to set the color, or backgroundColor() to + retrieve the current background color. + + currentFrameNumber() returns the sequence number of the current frame. The + first frame in the animation has the sequence number 0. frameCount() + returns the total number of frames in the animation, if the image format + supports this. You can call loopCount() to get the number of times the + movie should loop before finishing. nextFrameDelay() returns the number of + milliseconds the current frame should be displayed. + + QMovie can be instructed to cache frames of an animation by calling + setCacheMode(). + + Call supportedFormats() for a list of formats that QMovie supports. + + \sa QLabel, QImageReader, {Movie Example} +*/ + +/*! \enum QMovie::MovieState + + This enum describes the different states of QMovie. + + \value NotRunning The movie is not running. This is QMovie's initial + state, and the state it enters after stop() has been called or the movie + is finished. + + \value Paused The movie is paused, and QMovie stops emitting updated() or + resized(). This state is entered after calling pause() or + setPaused(true). The current frame number it kept, and the movie will + continue with the next frame when unpause() or setPaused(false) is called. + + \value Running The movie is running. +*/ + +/*! \enum QMovie::CacheMode + + This enum describes the different cache modes of QMovie. + + \value CacheNone No frames are cached (the default). + + \value CacheAll All frames are cached. +*/ + +/*! \fn void QMovie::started() + + This signal is emitted after QMovie::start() has been called, and QMovie + has entered QMovie::Running state. +*/ + +/*! \fn void QMovie::resized(const QSize &size) + + This signal is emitted when the current frame has been resized to \a + size. This effect is sometimes used in animations as an alternative to + replacing the frame. You can call currentImage() or currentPixmap() to get a + copy of the updated frame. +*/ + +/*! \fn void QMovie::updated(const QRect &rect) + + This signal is emitted when the rect \a rect in the current frame has been + updated. You can call currentImage() or currentPixmap() to get a copy of the + updated frame. +*/ + +/*! \fn void QMovie::frameChanged(int frameNumber) + \since 4.1 + + This signal is emitted when the frame number has changed to + \a frameNumber. You can call currentImage() or currentPixmap() to get a + copy of the frame. +*/ + +/*! + \fn void QMovie::stateChanged(QMovie::MovieState state) + + This signal is emitted every time the state of the movie changes. The new + state is specified by \a state. + + \sa QMovie::state() +*/ + +/*! \fn void QMovie::error(QImageReader::ImageReaderError error) + + This signal is emitted by QMovie when the error \a error occurred during + playback. QMovie will stop the movie, and enter QMovie::NotRunning state. +*/ + +/*! \fn void QMovie::finished() + + This signal is emitted when the movie has finished. + + \sa QMovie::stop() +*/ + +#include "qglobal.h" + +#ifndef QT_NO_MOVIE + +#include "qmovie.h" +#include "qimage.h" +#include "qimagereader.h" +#include "qpixmap.h" +#include "qrect.h" +#include "qdatetime.h" +#include "qtimer.h" +#include "qpair.h" +#include "qmap.h" +#include "qlist.h" +#include "qbuffer.h" +#include "qdir.h" +#include "private/qobject_p.h" + +#define QMOVIE_INVALID_DELAY -1 + +QT_BEGIN_NAMESPACE + +class QFrameInfo +{ +public: + QPixmap pixmap; + int delay; + bool endMark; + inline QFrameInfo(bool endMark) + : pixmap(QPixmap()), delay(QMOVIE_INVALID_DELAY), endMark(endMark) + { } + + inline QFrameInfo() + : pixmap(QPixmap()), delay(QMOVIE_INVALID_DELAY), endMark(false) + { } + + inline QFrameInfo(const QPixmap &pixmap, int delay) + : pixmap(pixmap), delay(delay), endMark(false) + { } + + inline bool isValid() + { + return endMark || !(pixmap.isNull() && (delay == QMOVIE_INVALID_DELAY)); + } + + inline bool isEndMarker() + { return endMark; } + + static inline QFrameInfo endMarker() + { return QFrameInfo(true); } +}; + +class QMoviePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QMovie) + +public: + QMoviePrivate(QMovie *qq); + bool isDone(); + bool next(); + int speedAdjustedDelay(int delay) const; + bool isValid() const; + bool jumpToFrame(int frameNumber); + int frameCount() const; + bool jumpToNextFrame(); + QFrameInfo infoForFrame(int frameNumber); + void reset(); + + inline void enterState(QMovie::MovieState newState) { + movieState = newState; + emit q_func()->stateChanged(newState); + } + + // private slots + void _q_loadNextFrame(); + void _q_loadNextFrame(bool starting); + + QImageReader *reader; + int speed; + QMovie::MovieState movieState; + QRect frameRect; + QPixmap currentPixmap; + int currentFrameNumber; + int nextFrameNumber; + int greatestFrameNumber; + int nextDelay; + int playCounter; + qint64 initialDevicePos; + QMovie::CacheMode cacheMode; + bool haveReadAll; + bool isFirstIteration; + QMap<int, QFrameInfo> frameMap; + QString absoluteFilePath; + + QTimer nextImageTimer; +}; + +/*! \internal + */ +QMoviePrivate::QMoviePrivate(QMovie *qq) + : reader(0), speed(100), movieState(QMovie::NotRunning), + currentFrameNumber(-1), nextFrameNumber(0), greatestFrameNumber(-1), + nextDelay(0), playCounter(-1), + cacheMode(QMovie::CacheNone), haveReadAll(false), isFirstIteration(true) +{ + q_ptr = qq; + nextImageTimer.setSingleShot(true); +} + +/*! \internal + */ +void QMoviePrivate::reset() +{ + nextImageTimer.stop(); + if (reader->device()) + initialDevicePos = reader->device()->pos(); + currentFrameNumber = -1; + nextFrameNumber = 0; + greatestFrameNumber = -1; + nextDelay = 0; + playCounter = -1; + haveReadAll = false; + isFirstIteration = true; + frameMap.clear(); +} + +/*! \internal + */ +bool QMoviePrivate::isDone() +{ + return (playCounter == 0); +} + +/*! + \internal + + Given the original \a delay, this function returns the + actual number of milliseconds to delay according to + the current speed. E.g. if the speed is 200%, the + result will be half of the original delay. +*/ +int QMoviePrivate::speedAdjustedDelay(int delay) const +{ + return int( (qint64(delay) * qint64(100) ) / qint64(speed) ); +} + +/*! + \internal + + Returns the QFrameInfo for the given \a frameNumber. + + If the frame number is invalid, an invalid QFrameInfo is + returned. + + If the end of the animation has been reached, a + special end marker QFrameInfo is returned. + +*/ +QFrameInfo QMoviePrivate::infoForFrame(int frameNumber) +{ + if (frameNumber < 0) + return QFrameInfo(); // Invalid + + if (haveReadAll && (frameNumber > greatestFrameNumber)) { + if (frameNumber == greatestFrameNumber+1) + return QFrameInfo::endMarker(); + return QFrameInfo(); // Invalid + } + + if (cacheMode == QMovie::CacheNone) { + if (frameNumber != currentFrameNumber+1) { + // Non-sequential frame access + if (!reader->jumpToImage(frameNumber)) { + if (frameNumber == 0) { + // Special case: Attempt to "rewind" so we can loop + // ### This could be implemented as QImageReader::rewind() + if (reader->device()->isSequential()) + return QFrameInfo(); // Invalid + QString fileName = reader->fileName(); + QByteArray format = reader->format(); + QIODevice *device = reader->device(); + QColor bgColor = reader->backgroundColor(); + QSize scaledSize = reader->scaledSize(); + delete reader; + if (fileName.isEmpty()) + reader = new QImageReader(device, format); + else + reader = new QImageReader(absoluteFilePath, format); + reader->canRead(); // Provoke a device->open() call + reader->device()->seek(initialDevicePos); + reader->setBackgroundColor(bgColor); + reader->setScaledSize(scaledSize); + } else { + return QFrameInfo(); // Invalid + } + } + } + if (reader->canRead()) { + // reader says we can read. Attempt to actually read image + QImage anImage = reader->read(); + if (anImage.isNull()) { + // Reading image failed. + return QFrameInfo(); // Invalid + } + if (frameNumber > greatestFrameNumber) + greatestFrameNumber = frameNumber; + QPixmap aPixmap = QPixmap::fromImage(anImage); + int aDelay = reader->nextImageDelay(); + return QFrameInfo(aPixmap, aDelay); + } else { + // We've read all frames now. Return an end marker + haveReadAll = true; + return QFrameInfo::endMarker(); + } + } + + // CacheMode == CacheAll + if (frameNumber > greatestFrameNumber) { + // Frame hasn't been read from file yet. Try to do it + for (int i = greatestFrameNumber + 1; i <= frameNumber; ++i) { + if (reader->canRead()) { + // reader says we can read. Attempt to actually read image + QImage anImage = reader->read(); + if (anImage.isNull()) { + // Reading image failed. + return QFrameInfo(); // Invalid + } + greatestFrameNumber = i; + QPixmap aPixmap = QPixmap::fromImage(anImage); + int aDelay = reader->nextImageDelay(); + QFrameInfo info(aPixmap, aDelay); + // Cache it! + frameMap.insert(i, info); + if (i == frameNumber) { + return info; + } + } else { + // We've read all frames now. Return an end marker + haveReadAll = true; + return QFrameInfo::endMarker(); + } + } + } + // Return info for requested (cached) frame + return frameMap.value(frameNumber); +} + +/*! + \internal + + Attempts to advance the animation to the next frame. + If successful, currentFrameNumber, currentPixmap and + nextDelay are updated accordingly, and true is returned. + Otherwise, false is returned. + When false is returned, isDone() can be called to + determine whether the animation ended gracefully or + an error occurred when reading the frame. +*/ +bool QMoviePrivate::next() +{ + QTime time; + time.start(); + QFrameInfo info = infoForFrame(nextFrameNumber); + if (!info.isValid()) + return false; + if (info.isEndMarker()) { + // We reached the end of the animation. + if (isFirstIteration) { + if (nextFrameNumber == 0) { + // No frames could be read at all (error). + return false; + } + // End of first iteration. Initialize play counter + playCounter = reader->loopCount(); + isFirstIteration = false; + } + // Loop as appropriate + if (playCounter != 0) { + if (playCounter != -1) // Infinite? + playCounter--; // Nope + nextFrameNumber = 0; + return next(); + } + // Loop no more. Done + return false; + } + // Image and delay OK, update internal state + currentFrameNumber = nextFrameNumber++; + QSize scaledSize = reader->scaledSize(); + if (scaledSize.isValid() && (scaledSize != info.pixmap.size())) + currentPixmap = QPixmap::fromImage( info.pixmap.toImage().scaled(scaledSize) ); + else + currentPixmap = info.pixmap; + nextDelay = speedAdjustedDelay(info.delay); + // Adjust delay according to the time it took to read the frame + int processingTime = time.elapsed(); + if (processingTime > nextDelay) + nextDelay = 0; + else + nextDelay = nextDelay - processingTime; + return true; +} + +/*! \internal + */ +void QMoviePrivate::_q_loadNextFrame() +{ + _q_loadNextFrame(false); +} + +void QMoviePrivate::_q_loadNextFrame(bool starting) +{ + Q_Q(QMovie); + if (next()) { + if (starting && movieState == QMovie::NotRunning) { + enterState(QMovie::Running); + emit q->started(); + } + + if (frameRect.size() != currentPixmap.rect().size()) { + frameRect = currentPixmap.rect(); + emit q->resized(frameRect.size()); + } + + emit q->updated(frameRect); + emit q->frameChanged(currentFrameNumber); + + if (movieState == QMovie::Running) + nextImageTimer.start(nextDelay); + } else { + // Could not read another frame + if (!isDone()) { + emit q->error(reader->error()); + } + + // Graceful finish + if (movieState != QMovie::Paused) { + nextFrameNumber = 0; + isFirstIteration = true; + playCounter = -1; + enterState(QMovie::NotRunning); + emit q->finished(); + } + } +} + +/*! + \internal +*/ +bool QMoviePrivate::isValid() const +{ + return (greatestFrameNumber >= 0) // have we seen valid data + || reader->canRead(); // or does the reader see valid data +} + +/*! + \internal +*/ +bool QMoviePrivate::jumpToFrame(int frameNumber) +{ + if (frameNumber < 0) + return false; + if (currentFrameNumber == frameNumber) + return true; + nextFrameNumber = frameNumber; + if (movieState == QMovie::Running) + nextImageTimer.stop(); + _q_loadNextFrame(); + return (nextFrameNumber == currentFrameNumber+1); +} + +/*! + \internal +*/ +int QMoviePrivate::frameCount() const +{ + int result; + if ((result = reader->imageCount()) != 0) + return result; + if (haveReadAll) + return greatestFrameNumber+1; + return 0; // Don't know +} + +/*! + \internal +*/ +bool QMoviePrivate::jumpToNextFrame() +{ + return jumpToFrame(currentFrameNumber+1); +} + +/*! + Constructs a QMovie object, passing the \a parent object to QObject's + constructor. + + \sa setFileName(), setDevice(), setFormat() + */ +QMovie::QMovie(QObject *parent) + : QObject(*new QMoviePrivate(this), parent) +{ + Q_D(QMovie); + d->reader = new QImageReader; + connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); +} + +/*! + Constructs a QMovie object. QMovie will use read image data from \a + device, which it assumes is open and readable. If \a format is not empty, + QMovie will use the image format \a format for decoding the image + data. Otherwise, QMovie will attempt to guess the format. + + The \a parent object is passed to QObject's constructor. + */ +QMovie::QMovie(QIODevice *device, const QByteArray &format, QObject *parent) + : QObject(*new QMoviePrivate(this), parent) +{ + Q_D(QMovie); + d->reader = new QImageReader(device, format); + d->initialDevicePos = device->pos(); + connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); +} + +/*! + Constructs a QMovie object. QMovie will use read image data from \a + fileName. If \a format is not empty, QMovie will use the image format \a + format for decoding the image data. Otherwise, QMovie will attempt to + guess the format. + + The \a parent object is passed to QObject's constructor. + */ +QMovie::QMovie(const QString &fileName, const QByteArray &format, QObject *parent) + : QObject(*new QMoviePrivate(this), parent) +{ + Q_D(QMovie); + d->absoluteFilePath = QDir(fileName).absolutePath(); + d->reader = new QImageReader(fileName, format); + if (d->reader->device()) + d->initialDevicePos = d->reader->device()->pos(); + connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); +} + +/*! + Destructs the QMovie object. +*/ +QMovie::~QMovie() +{ + Q_D(QMovie); + delete d->reader; +} + +/*! + Sets the current device to \a device. QMovie will read image data from + this device when the movie is running. + + \sa device(), setFormat() +*/ +void QMovie::setDevice(QIODevice *device) +{ + Q_D(QMovie); + d->reader->setDevice(device); + d->reset(); +} + +/*! + Returns the device QMovie reads image data from. If no device has + currently been assigned, 0 is returned. + + \sa setDevice(), fileName() +*/ +QIODevice *QMovie::device() const +{ + Q_D(const QMovie); + return d->reader->device(); +} + +/*! + Sets the name of the file that QMovie reads image data from, to \a + fileName. + + \sa fileName(), setDevice(), setFormat() +*/ +void QMovie::setFileName(const QString &fileName) +{ + Q_D(QMovie); + d->absoluteFilePath = QDir(fileName).absolutePath(); + d->reader->setFileName(fileName); + d->reset(); +} + +/*! + Returns the name of the file that QMovie reads image data from. If no file + name has been assigned, or if the assigned device is not a file, an empty + QString is returned. + + \sa setFileName(), device() +*/ +QString QMovie::fileName() const +{ + Q_D(const QMovie); + return d->reader->fileName(); +} + +/*! + Sets the format that QMovie will use when decoding image data, to \a + format. By default, QMovie will attempt to guess the format of the image + data. + + You can call supportedFormats() for the full list of formats + QMovie supports. + + \sa QImageReader::supportedImageFormats() +*/ +void QMovie::setFormat(const QByteArray &format) +{ + Q_D(QMovie); + d->reader->setFormat(format); +} + +/*! + Returns the format that QMovie uses when decoding image data. If no format + has been assigned, an empty QByteArray() is returned. + + \sa setFormat() +*/ +QByteArray QMovie::format() const +{ + Q_D(const QMovie); + return d->reader->format(); +} + +/*! + For image formats that support it, this function sets the background color + to \a color. + + \sa backgroundColor() +*/ +void QMovie::setBackgroundColor(const QColor &color) +{ + Q_D(QMovie); + d->reader->setBackgroundColor(color); +} + +/*! + Returns the background color of the movie. If no background color has been + assigned, an invalid QColor is returned. + + \sa setBackgroundColor() +*/ +QColor QMovie::backgroundColor() const +{ + Q_D(const QMovie); + return d->reader->backgroundColor(); +} + +/*! + Returns the current state of QMovie. + + \sa MovieState, stateChanged() +*/ +QMovie::MovieState QMovie::state() const +{ + Q_D(const QMovie); + return d->movieState; +} + +/*! + Returns the rect of the last frame. If no frame has yet been updated, an + invalid QRect is returned. + + \sa currentImage(), currentPixmap() +*/ +QRect QMovie::frameRect() const +{ + Q_D(const QMovie); + return d->frameRect; +} + +/*! \fn QImage QMovie::framePixmap() const + + Use currentPixmap() instead. +*/ + +/*! \fn void QMovie::pause() + + Use setPaused(true) instead. +*/ + +/*! \fn void QMovie::unpause() + + Use setPaused(false) instead. +*/ + +/*! + Returns the current frame as a QPixmap. + + \sa currentImage(), updated() +*/ +QPixmap QMovie::currentPixmap() const +{ + Q_D(const QMovie); + return d->currentPixmap; +} + +/*! \fn QImage QMovie::frameImage() const + + Use currentImage() instead. +*/ + +/*! + Returns the current frame as a QImage. + + \sa currentPixmap(), updated() +*/ +QImage QMovie::currentImage() const +{ + Q_D(const QMovie); + return d->currentPixmap.toImage(); +} + +/*! + Returns true if the movie is valid (e.g., the image data is readable and + the image format is supported); otherwise returns false. +*/ +bool QMovie::isValid() const +{ + Q_D(const QMovie); + return d->isValid(); +} + +/*! \fn bool QMovie::running() const + + Use state() instead. +*/ + +/*! \fn bool QMovie::isNull() const + + Use isValid() instead. +*/ + +/*! \fn int QMovie::frameNumber() const + + Use currentFrameNumber() instead. +*/ + +/*! \fn bool QMovie::paused() const + + Use state() instead. +*/ + +/*! \fn bool QMovie::finished() const + + Use state() instead. +*/ + +/*! \fn void QMovie::restart() + + Use stop() and start() instead. +*/ + +/*! + \fn void QMovie::step() + + Use jumpToNextFrame() instead. +*/ + +/*! + Returns the number of frames in the movie. + + Certain animation formats do not support this feature, in which + case 0 is returned. +*/ +int QMovie::frameCount() const +{ + Q_D(const QMovie); + return d->frameCount(); +} + +/*! + Returns the number of milliseconds QMovie will wait before updating the + next frame in the animation. +*/ +int QMovie::nextFrameDelay() const +{ + Q_D(const QMovie); + return d->nextDelay; +} + +/*! + Returns the sequence number of the current frame. The number of the first + frame in the movie is 0. +*/ +int QMovie::currentFrameNumber() const +{ + Q_D(const QMovie); + return d->currentFrameNumber; +} + +/*! + Jumps to the next frame. Returns true on success; otherwise returns false. +*/ +bool QMovie::jumpToNextFrame() +{ + Q_D(QMovie); + return d->jumpToNextFrame(); +} + +/*! + Jumps to frame number \a frameNumber. Returns true on success; otherwise + returns false. +*/ +bool QMovie::jumpToFrame(int frameNumber) +{ + Q_D(QMovie); + return d->jumpToFrame(frameNumber); +} + +/*! + Returns the number of times the movie will loop before it finishes. + If the movie will only play once (no looping), loopCount returns 0. + If the movie loops forever, loopCount returns -1. + + Note that, if the image data comes from a sequential device (e.g. a + socket), QMovie can only loop the movie if the cacheMode is set to + QMovie::CacheAll. +*/ +int QMovie::loopCount() const +{ + Q_D(const QMovie); + return d->reader->loopCount(); +} + +/*! + If \a paused is true, QMovie will enter \l Paused state and emit + stateChanged(Paused); otherwise it will enter \l Running state and emit + stateChanged(Running). + + \sa state() +*/ +void QMovie::setPaused(bool paused) +{ + Q_D(QMovie); + if (paused) { + if (d->movieState == NotRunning) + return; + d->enterState(Paused); + d->nextImageTimer.stop(); + } else { + if (d->movieState == Running) + return; + d->enterState(Running); + d->nextImageTimer.start(nextFrameDelay()); + } +} + +/*! + \property QMovie::speed + \brief the movie's speed + + The speed is measured in percentage of the original movie speed. + The default speed is 100%. + Example: + + \snippet doc/src/snippets/code/src_gui_image_qmovie.cpp 1 +*/ +void QMovie::setSpeed(int percentSpeed) +{ + Q_D(QMovie); + d->speed = percentSpeed; +} + +int QMovie::speed() const +{ + Q_D(const QMovie); + return d->speed; +} + +/*! + Starts the movie. QMovie will enter \l Running state, and start emitting + updated() and resized() as the movie progresses. + + If QMovie is in the \l Paused state, this function is equivalent + to calling setPaused(false). If QMovie is already in the \l + Running state, this function does nothing. + + \sa stop(), setPaused() +*/ +void QMovie::start() +{ + Q_D(QMovie); + if (d->movieState == NotRunning) { + d->_q_loadNextFrame(true); + } else if (d->movieState == Paused) { + setPaused(false); + } +} + +/*! + Stops the movie. QMovie enters \l NotRunning state, and stops emitting + updated() and resized(). If start() is called again, the movie will + restart from the beginning. + + If QMovie is already in the \l NotRunning state, this function + does nothing. + + \sa start(), setPaused() +*/ +void QMovie::stop() +{ + Q_D(QMovie); + if (d->movieState == NotRunning) + return; + d->enterState(NotRunning); + d->nextImageTimer.stop(); + d->nextFrameNumber = 0; +} + +/*! + \since 4.1 + + Returns the scaled size of frames. + + \sa QImageReader::scaledSize() +*/ +QSize QMovie::scaledSize() +{ + Q_D(QMovie); + return d->reader->scaledSize(); +} + +/*! + \since 4.1 + + Sets the scaled frame size to \a size. + + \sa QImageReader::setScaledSize() +*/ +void QMovie::setScaledSize(const QSize &size) +{ + Q_D(QMovie); + d->reader->setScaledSize(size); +} + +/*! + \since 4.1 + + Returns the list of image formats supported by QMovie. + + \sa QImageReader::supportedImageFormats() +*/ +QList<QByteArray> QMovie::supportedFormats() +{ + QList<QByteArray> list = QImageReader::supportedImageFormats(); + QMutableListIterator<QByteArray> it(list); + QBuffer buffer; + buffer.open(QIODevice::ReadOnly); + while (it.hasNext()) { + QImageReader reader(&buffer, it.next()); + if (!reader.supportsAnimation()) + it.remove(); + } + return list; +} + +/*! + \property QMovie::cacheMode + \brief the movie's cache mode + + Caching frames can be useful when the underlying animation format handler + that QMovie relies on to decode the animation data does not support + jumping to particular frames in the animation, or even "rewinding" the + animation to the beginning (for looping). Furthermore, if the image data + comes from a sequential device, it is not possible for the underlying + animation handler to seek back to frames whose data has already been read + (making looping altogether impossible). + + To aid in such situations, a QMovie object can be instructed to cache the + frames, at the added memory cost of keeping the frames in memory for the + lifetime of the object. + + By default, this property is set to \l CacheNone. + + \sa QMovie::CacheMode +*/ + +QMovie::CacheMode QMovie::cacheMode() const +{ + Q_D(const QMovie); + return d->cacheMode; +} + +void QMovie::setCacheMode(CacheMode cacheMode) +{ + Q_D(QMovie); + d->cacheMode = cacheMode; +} + +/*! + \internal +*/ +QMovie::CacheMode QMovie::cacheMode() +{ + Q_D(QMovie); + return d->cacheMode; +} + +QT_END_NAMESPACE + +#include "moc_qmovie.cpp" + +#endif // QT_NO_MOVIE |