8#include <QtGui/qguiapplication.h>
9#include <QtQml/qqmlinfo.h>
10#include <QtQml/qqmlfile.h>
11#include <QtQml/qqmlengine.h>
12#include <QtGui/qmovie.h>
13#if QT_CONFIG(qml_network)
14#include <QtNetwork/qnetworkrequest.h>
15#include <QtNetwork/qnetworkreply.h>
20QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine)
25 int current = movie->currentFrameNumber();
26 if (!frameMap.contains(current)) {
28 QQuickPixmap *pixmap =
nullptr;
29 if (engine && !movie->fileName().isEmpty()) {
30 requestedUrl.setUrl(QString::fromUtf8(
"quickanimatedimage://%1#%2x%3#%4")
31 .arg(movie->fileName())
32 .arg(movie->scaledSize().width())
33 .arg(movie->scaledSize().height())
36 if (!requestedUrl.isEmpty()) {
37 if (QQuickPixmap::isCached(requestedUrl, QRect(), QSize(), 0, QQuickImageProviderOptions()))
38 pixmap =
new QQuickPixmap(engine, requestedUrl);
40 pixmap =
new QQuickPixmap(requestedUrl, movie->currentImage());
42 pixmap =
new QQuickPixmap;
43 pixmap->setImage(movie->currentImage());
45 frameMap.insert(current, pixmap);
48 return frameMap.value(current);
59 Q_Q(QQuickAnimatedImage);
60 const int targetFrame = (finishBehavior == QQuickAnimatedImage::FinishAtInitialFrame)
62 : qMax(movie->frameCount() - 1, 0);
65 movie->jumpToFrame(targetFrame);
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
119
120
121
122
123
124
125
126
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
149 : QQuickImage(*(
new QQuickAnimatedImagePrivate), parent)
151 connect(
this, &QQuickImageBase::cacheChanged,
this, &QQuickAnimatedImage::onCacheChanged);
152 connect(
this, &QQuickImageBase::currentFrameChanged,
this, &QQuickAnimatedImage::frameChanged);
153 connect(
this, &QQuickImageBase::currentFrameChanged,
this, &QQuickAnimatedImage::currentFrameChanged);
154 connect(
this, &QQuickImageBase::frameCountChanged,
this, &QQuickAnimatedImage::frameCountChanged);
157QQuickAnimatedImage::~QQuickAnimatedImage()
159 Q_D(QQuickAnimatedImage);
160#if QT_CONFIG(qml_network)
162 d->reply->deleteLater();
169
170
171
172
173
174
176bool QQuickAnimatedImage::isPaused()
const
178 Q_D(
const QQuickAnimatedImage);
181 return d->movie->state()==QMovie::Paused;
184void QQuickAnimatedImage::setPaused(
bool pause)
186 Q_D(QQuickAnimatedImage);
187 if (pause == d->paused)
191 emit pausedChanged();
193 d->movie->setPaused(pause);
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
215bool QQuickAnimatedImage::isPlaying()
const
217 Q_D(
const QQuickAnimatedImage);
220 return d->movie->state()!=QMovie::NotRunning;
223void QQuickAnimatedImage::setPlaying(
bool play)
225 Q_D(QQuickAnimatedImage);
226 if (play == d->playing)
230 emit playingChanged();
237 d->lastFrameNumber = 0;
245
246
247
248
249
250
251
252
253
254int QQuickAnimatedImage::currentFrame()
const
256 Q_D(
const QQuickAnimatedImage);
258 return d->presetCurrentFrame;
259 return d->movie->currentFrameNumber();
262void QQuickAnimatedImage::setCurrentFrame(
int frame)
264 Q_D(QQuickAnimatedImage);
266 d->presetCurrentFrame = frame;
272 d->lastFrameNumber = frame;
273 d->movie->jumpToFrame(frame);
276int QQuickAnimatedImage::frameCount()
const
278 Q_D(
const QQuickAnimatedImage);
281 return d->movie->frameCount();
285
286
287
288
289
290
291
292
293qreal QQuickAnimatedImage::speed()
const
295 Q_D(
const QQuickAnimatedImage);
299void QQuickAnimatedImage::setSpeed(qreal speed)
301 Q_D(QQuickAnimatedImage);
302 if (d->speed != speed) {
305 d->movie->setSpeed(qRound(speed * 100.0));
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326int QQuickAnimatedImage::loops()
const
328 Q_D(
const QQuickAnimatedImage);
332void QQuickAnimatedImage::setLoops(
int loops)
334 Q_D(QQuickAnimatedImage);
335 if (loops < 0 && loops != Infinite) {
336 qmlWarning(
this) <<
"Loops must be AnimatedImage.Infinite, 0, or a positive integer, got"
340 if (d->loops == loops)
344 if (loops == 0 && d->movie && d->movie->state() != QMovie::NotRunning)
349
350
351
352
353
354
355
356
357
358
359
360
361
364
365
366
367
368
369
370
371
372QQuickAnimatedImage::FinishBehavior QQuickAnimatedImage::finishBehavior()
const
374 Q_D(
const QQuickAnimatedImage);
375 return d->finishBehavior;
378void QQuickAnimatedImage::setFinishBehavior(FinishBehavior behavior)
380 Q_D(QQuickAnimatedImage);
381 if (d->finishBehavior == behavior)
383 d->finishBehavior = behavior;
384 emit finishBehaviorChanged();
387void QQuickAnimatedImage::setSource(
const QUrl &url)
389 Q_D(QQuickAnimatedImage);
394 d->lastFrameNumber = 0;
396#if QT_CONFIG(qml_network)
398 d->reply->deleteLater();
403 d->setImage(QImage());
404 d->oldPlaying = isPlaying();
405 d->setMovie(
nullptr);
407 emit sourceChanged(d->url);
409 if (isComponentComplete())
413void QQuickAnimatedImage::load()
415 Q_D(QQuickAnimatedImage);
417 if (d->url.isEmpty()) {
420 d->setImage(QImage());
421 if (sourceSize() != d->oldSourceSize) {
422 d->oldSourceSize = sourceSize();
423 emit sourceSizeChanged();
427 if (isPlaying() != d->oldPlaying)
428 emit playingChanged();
430 const qreal targetDevicePixelRatio = d->effectiveDevicePixelRatio();
431 d->devicePixelRatio = 1.0;
433 const auto context = qmlContext(
this);
434 QUrl loadUrl = context ? context->resolvedUrl(d->url) : d->url;
435 const QUrl resolvedUrl = loadUrl;
436 resolve2xLocalFile(resolvedUrl, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
437 QString lf = QQmlFile::urlToLocalFileOrQrc(loadUrl);
442 d->setMovie(
new QMovie(lf));
443 movieRequestFinished();
445#if QT_CONFIG(qml_network)
449 d->setStatus(Loading);
451 QNetworkRequest req(d->url);
452 req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute,
true);
454 d->reply = qmlEngine(
this)->networkAccessManager()->get(req);
455 connect(d->reply, &QNetworkReply::finished,
this, &QQuickAnimatedImage::movieRequestFinished);
456 connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(requestProgress(qint64,qint64)));
462void QQuickAnimatedImage::movieRequestFinished()
464 Q_D(QQuickAnimatedImage);
466#if QT_CONFIG(qml_network)
468 auto movie =
new QMovie(d->reply);
472 d->reply->disconnect(
this);
473 d->reply->setParent(movie);
480 if (!d->movie || !d->movie->isValid()) {
481 const QQmlContext *context = qmlContext(
this);
482 qmlWarning(
this) <<
"Error Reading Animated Image File "
483 << (context ? context->resolvedUrl(d->url) : d->url).toString();
484 d->setMovie(
nullptr);
486 d->setImage(QImage());
487 if (sourceSize() != d->oldSourceSize) {
488 d->oldSourceSize = sourceSize();
489 emit sourceSizeChanged();
495 if (isPlaying() != d->oldPlaying)
496 emit playingChanged();
500 connect(d->movie, &QMovie::stateChanged,
this, &QQuickAnimatedImage::playingStatusChanged);
501 connect(d->movie, &QMovie::frameChanged,
this, &QQuickAnimatedImage::movieUpdate);
502 connect(d->movie, &QMovie::finished,
this, &QQuickAnimatedImage::onMovieFinished);
504 d->movie->setCacheMode(QMovie::CacheAll);
505 d->movie->setSpeed(qRound(d->speed * 100.0));
509 bool pausedAtStart = d->paused;
510 if (d->movie && d->playing && d->loops != 0)
512 if (d->movie && pausedAtStart)
513 d->movie->setPaused(
true);
514 if (d->movie && (d->paused || !d->playing || d->loops == 0)) {
515 d->movie->jumpToFrame(d->presetCurrentFrame);
516 d->presetCurrentFrame = 0;
519 QQuickPixmap *pixmap = d->infoForCurrentFrame(qmlEngine(
this));
521 d->setPixmap(*pixmap);
522 if (sourceSize() != d->oldSourceSize) {
523 d->oldSourceSize = sourceSize();
524 emit sourceSizeChanged();
530 if (isPlaying() != d->oldPlaying)
531 emit playingChanged();
534void QQuickAnimatedImage::movieUpdate()
536 Q_D(QQuickAnimatedImage);
542 int currentFrame = d->movie->currentFrameNumber();
544 if (currentFrame < d->lastFrameNumber && d->lastFrameNumber > 0) {
546 if (d->loops != Infinite && d->currentLoop >= d->loops) {
547 d->handleLoopCompletion();
551 currentFrame = d->movie->currentFrameNumber();
554 d->lastFrameNumber = currentFrame;
555 d->setPixmap(*d->infoForCurrentFrame(qmlEngine(
this)));
556 emit QQuickImageBase::currentFrameChanged();
560void QQuickAnimatedImage::playingStatusChanged()
562 Q_D(QQuickAnimatedImage);
564 if ((d->movie->state() != QMovie::NotRunning) != d->playing) {
565 d->playing = (d->movie->state() != QMovie::NotRunning);
566 emit playingChanged();
568 if ((d->movie->state() == QMovie::Paused) != d->paused) {
569 d->paused = (d->movie->state() == QMovie::Paused);
570 emit pausedChanged();
575
576
577
578
579
580
581
582
583
584
586void QQuickAnimatedImage::onMovieFinished()
588 Q_D(QQuickAnimatedImage);
590 if (d->movie->frameCount() <= 1)
592 if (d->loops == Infinite || d->currentLoop < d->loops) {
594 d->lastFrameNumber = 0;
597 d->handleLoopCompletion();
601void QQuickAnimatedImage::onCacheChanged()
603 Q_D(QQuickAnimatedImage);
607 d->movie->setCacheMode(QMovie::CacheNone);
610 d->movie->setCacheMode(QMovie::CacheAll);
614void QQuickAnimatedImage::componentComplete()
616 QQuickItem::componentComplete();
625 Q_Q(QQuickAnimatedImage);
626 const int oldFrameCount = q->frameCount();
630 movie->deleteLater();
637 movie->setScaledSize(sourcesize);
639 if (oldFrameCount != q->frameCount())
640 emit q->frameCountChanged();
645#include "moc_qquickanimatedimage_p.cpp"
void handleLoopCompletion()
void setMovie(QMovie *movie)
Combined button and popup list for selecting options.