]> cloud.milkyroute.net Git - dolphin.git/blob - src/panels/information/pixmapviewer.cpp
Merge branch 'release/20.08' into master
[dolphin.git] / src / panels / information / pixmapviewer.cpp
1 /*
2 * SPDX-FileCopyrightText: 2006 Peter Penz <peter.penz19@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "pixmapviewer.h"
8
9 #include <KIconLoader>
10
11 #include <QImageReader>
12 #include <QMovie>
13 #include <QPainter>
14 #include <QStyle>
15
16 PixmapViewer::PixmapViewer(QWidget* parent, Transition transition) :
17 QWidget(parent),
18 m_animatedImage(nullptr),
19 m_transition(transition),
20 m_animationStep(0),
21 m_sizeHint(),
22 m_hasAnimatedImage(false)
23 {
24 setMinimumWidth(KIconLoader::SizeEnormous);
25 setMinimumHeight(KIconLoader::SizeEnormous);
26
27 m_animation.setDuration(150);
28 m_animation.setCurveShape(QTimeLine::LinearCurve);
29
30 if (m_transition != NoTransition) {
31 connect(&m_animation, &QTimeLine::valueChanged, this, QOverload<>::of(&PixmapViewer::update));
32 connect(&m_animation, &QTimeLine::finished, this, &PixmapViewer::checkPendingPixmaps);
33 }
34 }
35
36 PixmapViewer::~PixmapViewer()
37 {
38 }
39
40 void PixmapViewer::setPixmap(const QPixmap& pixmap)
41 {
42 if (pixmap.isNull()) {
43 return;
44 }
45
46 // Avoid flicker with static pixmap if an animated image is running
47 if (m_animatedImage && m_animatedImage->state() == QMovie::Running) {
48 return;
49 }
50
51 if ((m_transition != NoTransition) && (m_animation.state() == QTimeLine::Running)) {
52 m_pendingPixmaps.enqueue(pixmap);
53 if (m_pendingPixmaps.count() > 5) {
54 // don't queue more than 5 pixmaps
55 m_pendingPixmaps.takeFirst();
56 }
57 return;
58 }
59
60 m_oldPixmap = m_pixmap.isNull() ? pixmap : m_pixmap;
61 m_pixmap = pixmap;
62 update();
63
64 const bool animateTransition = (m_transition != NoTransition) &&
65 (m_pixmap.size() != m_oldPixmap.size());
66 if (animateTransition) {
67 m_animation.start();
68 } else if (m_hasAnimatedImage) {
69 // If there is no transition animation but an animatedImage
70 // and it is not already running, start animating now
71 if (m_animatedImage->state() != QMovie::Running) {
72 m_animatedImage->setScaledSize(m_pixmap.size());
73 m_animatedImage->start();
74 }
75 }
76 }
77
78 void PixmapViewer::setSizeHint(const QSize& size)
79 {
80 if (m_animatedImage && size != m_sizeHint) {
81 m_animatedImage->stop();
82 }
83
84 m_sizeHint = size;
85 updateGeometry();
86 }
87
88 QSize PixmapViewer::sizeHint() const
89 {
90 return m_sizeHint;
91 }
92
93 void PixmapViewer::setAnimatedImageFileName(const QString &fileName)
94 {
95 if (!m_animatedImage) {
96 m_animatedImage = new QMovie(this);
97 connect(m_animatedImage, &QMovie::frameChanged, this, &PixmapViewer::updateAnimatedImageFrame);
98 }
99
100 if (m_animatedImage->fileName() != fileName) {
101 m_animatedImage->stop();
102 m_animatedImage->setFileName(fileName);
103 }
104
105 m_hasAnimatedImage = m_animatedImage->isValid() && (m_animatedImage->frameCount() > 1);
106 }
107
108
109 QString PixmapViewer::animatedImageFileName() const
110 {
111 if (!m_hasAnimatedImage) {
112 return QString();
113 }
114 return m_animatedImage->fileName();
115 }
116
117 void PixmapViewer::paintEvent(QPaintEvent* event)
118 {
119 QWidget::paintEvent(event);
120
121 QPainter painter(this);
122
123 if (m_transition != NoTransition || (m_hasAnimatedImage && m_animatedImage->state() != QMovie::Running)) {
124 const float value = m_animation.currentValue();
125 const int scaledWidth = static_cast<int>((m_oldPixmap.width() * (1.0 - value)) + (m_pixmap.width() * value));
126 const int scaledHeight = static_cast<int>((m_oldPixmap.height() * (1.0 - value)) + (m_pixmap.height() * value));
127
128 const bool useOldPixmap = (m_transition == SizeTransition) &&
129 (m_oldPixmap.width() > m_pixmap.width());
130 const QPixmap& largePixmap = useOldPixmap ? m_oldPixmap : m_pixmap;
131 if (!largePixmap.isNull()) {
132 const QPixmap scaledPixmap = largePixmap.scaled(scaledWidth,
133 scaledHeight,
134 Qt::IgnoreAspectRatio,
135 Qt::FastTransformation);
136
137 style()->drawItemPixmap(&painter, rect(), Qt::AlignCenter, scaledPixmap);
138 }
139 } else {
140 style()->drawItemPixmap(&painter, rect(), Qt::AlignCenter, m_pixmap);
141 }
142 }
143
144 void PixmapViewer::checkPendingPixmaps()
145 {
146 if (!m_pendingPixmaps.isEmpty()) {
147 QPixmap pixmap = m_pendingPixmaps.dequeue();
148 m_oldPixmap = m_pixmap.isNull() ? pixmap : m_pixmap;
149 m_pixmap = pixmap;
150 update();
151 m_animation.start();
152 } else if (m_hasAnimatedImage) {
153 m_animatedImage->setScaledSize(m_pixmap.size());
154 m_animatedImage->start();
155 } else {
156 m_oldPixmap = m_pixmap;
157 }
158 }
159
160 void PixmapViewer::updateAnimatedImageFrame()
161 {
162 Q_ASSERT (m_animatedImage);
163
164 m_pixmap = m_animatedImage->currentPixmap();
165 update();
166 }
167
168 void PixmapViewer::stopAnimatedImage()
169 {
170 if (m_hasAnimatedImage) {
171 m_animatedImage->stop();
172 m_hasAnimatedImage = false;
173 }
174 }
175
176 bool PixmapViewer::isAnimatedMimeType(const QString &mimeType)
177 {
178 const QList<QByteArray> imageFormats = QImageReader::imageFormatsForMimeType(mimeType.toUtf8());
179 return std::any_of(imageFormats.begin(), imageFormats.end(),
180 [](const QByteArray &format){ return QMovie::supportedFormats().contains(format); });
181 }