]> cloud.milkyroute.net Git - dolphin.git/blob - src/panels/information/pixmapviewer.cpp
Add explicit moc includes to sources for moc-covered headers
[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.setEasingCurve(QEasingCurve::Linear);
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) && (m_pixmap.size() != m_oldPixmap.size());
65 if (animateTransition) {
66 m_animation.start();
67 } else if (m_hasAnimatedImage) {
68 // If there is no transition animation but an animatedImage
69 // and it is not already running, start animating now
70 if (m_animatedImage->state() != QMovie::Running) {
71 m_animatedImage->setScaledSize(m_pixmap.size());
72 m_animatedImage->start();
73 }
74 }
75 }
76
77 void PixmapViewer::setSizeHint(const QSize &size)
78 {
79 if (m_animatedImage && size != m_sizeHint) {
80 m_animatedImage->stop();
81 }
82
83 m_sizeHint = size;
84 updateGeometry();
85 }
86
87 QSize PixmapViewer::sizeHint() const
88 {
89 return m_sizeHint;
90 }
91
92 void PixmapViewer::setAnimatedImageFileName(const QString &fileName)
93 {
94 if (!m_animatedImage) {
95 m_animatedImage = new QMovie(this);
96 connect(m_animatedImage, &QMovie::frameChanged, this, &PixmapViewer::updateAnimatedImageFrame);
97 }
98
99 if (m_animatedImage->fileName() != fileName) {
100 m_animatedImage->stop();
101 m_animatedImage->setFileName(fileName);
102 }
103
104 m_hasAnimatedImage = m_animatedImage->isValid() && (m_animatedImage->frameCount() > 1);
105 }
106
107 QString PixmapViewer::animatedImageFileName() const
108 {
109 if (!m_hasAnimatedImage) {
110 return QString();
111 }
112 return m_animatedImage->fileName();
113 }
114
115 void PixmapViewer::paintEvent(QPaintEvent *event)
116 {
117 QWidget::paintEvent(event);
118
119 QPainter painter(this);
120
121 if (m_transition != NoTransition || (m_hasAnimatedImage && m_animatedImage->state() != QMovie::Running)) {
122 const float value = m_animation.currentValue();
123 const int scaledWidth = static_cast<int>((m_oldPixmap.width() * (1.0 - value)) + (m_pixmap.width() * value));
124 const int scaledHeight = static_cast<int>((m_oldPixmap.height() * (1.0 - value)) + (m_pixmap.height() * value));
125
126 const bool useOldPixmap = (m_transition == SizeTransition) && (m_oldPixmap.width() > m_pixmap.width());
127 const QPixmap &largePixmap = useOldPixmap ? m_oldPixmap : m_pixmap;
128 if (!largePixmap.isNull()) {
129 const QPixmap scaledPixmap = largePixmap.scaled(scaledWidth, scaledHeight, Qt::IgnoreAspectRatio, Qt::FastTransformation);
130
131 style()->drawItemPixmap(&painter, rect(), Qt::AlignCenter, scaledPixmap);
132 }
133 } else if (!m_pixmap.isNull()) {
134 style()->drawItemPixmap(&painter, rect(), Qt::AlignCenter, m_pixmap);
135 }
136 }
137
138 void PixmapViewer::checkPendingPixmaps()
139 {
140 if (!m_pendingPixmaps.isEmpty()) {
141 QPixmap pixmap = m_pendingPixmaps.dequeue();
142 m_oldPixmap = m_pixmap.isNull() ? pixmap : m_pixmap;
143 m_pixmap = pixmap;
144 update();
145 m_animation.start();
146 } else if (m_hasAnimatedImage) {
147 m_animatedImage->setScaledSize(m_pixmap.size());
148 m_animatedImage->start();
149 } else {
150 m_oldPixmap = m_pixmap;
151 }
152 }
153
154 void PixmapViewer::updateAnimatedImageFrame()
155 {
156 Q_ASSERT(m_animatedImage);
157
158 m_pixmap = m_animatedImage->currentPixmap();
159 update();
160 }
161
162 void PixmapViewer::stopAnimatedImage()
163 {
164 if (m_hasAnimatedImage) {
165 m_animatedImage->stop();
166 m_hasAnimatedImage = false;
167 }
168 }
169
170 bool PixmapViewer::isAnimatedMimeType(const QString &mimeType)
171 {
172 const QList<QByteArray> imageFormats = QImageReader::imageFormatsForMimeType(mimeType.toUtf8());
173 return std::any_of(imageFormats.begin(), imageFormats.end(), [](const QByteArray &format) {
174 return QMovie::supportedFormats().contains(format);
175 });
176 }
177
178 #include "moc_pixmapviewer.cpp"