diff --git a/src/panels/information/informationpanelcontent.cpp b/src/panels/information/informationpanelcontent.cpp --- a/src/panels/information/informationpanelcontent.cpp +++ b/src/panels/information/informationpanelcontent.cpp @@ -162,8 +162,8 @@ m_item = item; refreshMetaData(); + refreshPreview(); } - refreshPreview(); } void InformationPanelContent::refreshPreview() @@ -174,6 +174,8 @@ m_previewJob->kill(); } + m_preview->stopAnimatedImage(); + setNameLabelText(m_item.text()); if (InformationPanelSettings::previewsShown()) { @@ -215,9 +217,14 @@ this, &InformationPanelContent::showIcon); const QString mimeType = m_item.mimetype(); - const bool isVideo = mimeType.startsWith(QLatin1String("video/")); + const bool isAnimatedImage = m_preview->animatedMimeTypes().contains(mimeType); + const bool isVideo = mimeType.startsWith(QLatin1String("video/")) && !isAnimatedImage; const bool usePhonon = mimeType.startsWith(QLatin1String("audio/")) || isVideo; + if (isAnimatedImage) { + m_preview->setAnimatedImageFileName(itemUrl.toLocalFile()); + } + if (usePhonon) { if (InformationPanelSettings::previewsAutoPlay() && isVideo) { @@ -238,6 +245,7 @@ } } } else { + m_preview->stopAnimatedImage(); m_preview->hide(); m_phononWidget->hide(); } @@ -265,6 +273,8 @@ m_previewJob->kill(); } + m_preview->stopAnimatedImage(); + m_preview->setPixmap( QIcon::fromTheme(QStringLiteral("dialog-information")).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous) ); @@ -319,7 +329,6 @@ const QPixmap& pixmap) { m_outdatedPreviewTimer->stop(); - Q_UNUSED(item); QPixmap p = pixmap; KIconLoader::global()->drawOverlays(item.overlays(), p, KIconLoader::Desktop); diff --git a/src/panels/information/pixmapviewer.h b/src/panels/information/pixmapviewer.h --- a/src/panels/information/pixmapviewer.h +++ b/src/panels/information/pixmapviewer.h @@ -26,6 +26,7 @@ #include class QPaintEvent; +class QMovie; /** * @brief Widget which shows a pixmap centered inside the boundaries. @@ -73,15 +74,28 @@ void setSizeHint(const QSize& size); QSize sizeHint() const override; + void setAnimatedImageFileName(const QString& fileName); + QString animatedImageFileName() const; + + bool hasAnimatedImage(); + void stopAnimatedImage(); + + /** + * Returns the list of supported mimetypes that can be animated + */ + static const QStringList animatedMimeTypes(); + protected: void paintEvent(QPaintEvent* event) override; private Q_SLOTS: void checkPendingPixmaps(); + void updateAnimatedImageFrame(); private: QPixmap m_pixmap; QPixmap m_oldPixmap; + QMovie* m_animatedImage; QQueue m_pendingPixmaps; QTimeLine m_animation; Transition m_transition; diff --git a/src/panels/information/pixmapviewer.cpp b/src/panels/information/pixmapviewer.cpp --- a/src/panels/information/pixmapviewer.cpp +++ b/src/panels/information/pixmapviewer.cpp @@ -23,9 +23,11 @@ #include #include +#include PixmapViewer::PixmapViewer(QWidget* parent, Transition transition) : QWidget(parent), + m_animatedImage(nullptr), m_transition(transition), m_animationStep(0), m_sizeHint() @@ -65,10 +67,17 @@ m_pixmap = pixmap; update(); - const bool animate = (m_transition != NoTransition) && - (m_pixmap.size() != m_oldPixmap.size()); - if (animate) { + const bool animateTransition = (m_transition != NoTransition) && + (m_pixmap.size() != m_oldPixmap.size()); + if (animateTransition) { m_animation.start(); + } else if (hasAnimatedImage()) { + // If there is no transition animation but an animatedImage + // and it is not already running, start animating now + if (m_animatedImage->state() != QMovie::Running) { + m_animatedImage->setScaledSize(m_pixmap.size()); + m_animatedImage->start(); + } } } @@ -83,13 +92,40 @@ return m_sizeHint; } +void PixmapViewer::setAnimatedImageFileName(const QString &fileName) +{ + if (!m_animatedImage) { + m_animatedImage = new QMovie(this); + connect(m_animatedImage, &QMovie::frameChanged, this, &PixmapViewer::updateAnimatedImageFrame); + } + + if (m_animatedImage->fileName() != fileName) { + m_animatedImage->stop(); + m_animatedImage->setFileName(fileName); + } +} + + +QString PixmapViewer::animatedImageFileName() const +{ + if (!m_animatedImage) { + return QString(); + } + return m_animatedImage->fileName(); +} + +bool PixmapViewer::hasAnimatedImage() +{ + return (m_animatedImage && m_animatedImage->isValid() && m_animatedImage->frameCount() > 1); +} + void PixmapViewer::paintEvent(QPaintEvent* event) { QWidget::paintEvent(event); QPainter painter(this); - if (m_transition != NoTransition) { + if (m_transition != NoTransition || (m_animatedImage && m_animatedImage->state() != QMovie::Running)) { const float value = m_animation.currentValue(); const int scaledWidth = static_cast((m_oldPixmap.width() * (1.0 - value)) + (m_pixmap.width() * value)); const int scaledHeight = static_cast((m_oldPixmap.height() * (1.0 - value)) + (m_pixmap.height() * value)); @@ -118,8 +154,34 @@ m_pixmap = pixmap; update(); m_animation.start(); + } else if (hasAnimatedImage()) { + m_animatedImage->setScaledSize(m_pixmap.size()); + m_animatedImage->start(); } else { m_oldPixmap = m_pixmap; } } +void PixmapViewer::updateAnimatedImageFrame() +{ + Q_ASSERT (m_animatedImage); + + m_pixmap = m_animatedImage->currentPixmap(); + update(); +} + +void PixmapViewer::stopAnimatedImage() +{ + if (m_animatedImage) { + m_animatedImage->stop(); + delete m_animatedImage; + m_animatedImage = nullptr; + } +} + +const QStringList PixmapViewer::animatedMimeTypes() +{ + return QStringList() << QStringLiteral("image/gif") + << QStringLiteral("image/webp") + << QStringLiteral("video/x-mng"); +}