KWidgetsAddons

kanimatedbutton.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
4 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
5 SPDX-FileCopyrightText: 2008 Pino Toscano <pino@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-only
8*/
9
10#include <kanimatedbutton.h>
11
12#include <QImageReader>
13#include <QMovie>
14#include <QPainter>
15#include <QPixmap>
16#include <QTimer>
17
18class KAnimatedButtonPrivate
19{
20public:
21 KAnimatedButtonPrivate(KAnimatedButton *qq)
22 : q(qq)
23 {
24 }
25
26 void updateIcons();
27 void updateCurrentIcon();
28 void movieFrameChanged(int number);
29 void movieFinished();
30 void timerUpdate();
31
32 KAnimatedButton *const q;
33 QMovie *movie = nullptr;
34
35 int frames;
36 int current_frame;
37 QPixmap pixmap;
38 QTimer timer;
39 QString icon_path;
40 QList<QPixmap *> framesCache; // We keep copies of each frame so that
41 // the icon code can properly cache them in QPixmapCache,
42 // and not fill it up with dead copies
43};
44
46 : QToolButton(parent)
47 , d(new KAnimatedButtonPrivate(this))
48{
49 connect(&d->timer, &QTimer::timeout, this, [this]() {
50 d->timerUpdate();
51 });
52}
53
55{
56 d->timer.stop();
57 qDeleteAll(d->framesCache);
58 delete d->movie;
59}
60
62{
63 if (d->movie) {
64 d->movie->start();
65 } else {
66 d->current_frame = 0;
67 d->timer.start(50);
68 }
69}
70
72{
73 if (d->movie) {
74 d->movie->stop();
75 d->movie->jumpToFrame(0);
76 d->movieFrameChanged(0);
77 } else {
78 d->current_frame = 0;
79 d->timer.stop();
80 d->updateCurrentIcon();
81 }
82}
83
85{
86 if (d->icon_path == path) {
87 return;
88 }
89
90 d->timer.stop();
91 d->icon_path = path;
92 d->updateIcons();
93}
94
95QString KAnimatedButton::animationPath() const
96{
97 return d->icon_path;
98}
99
100void KAnimatedButtonPrivate::timerUpdate()
101{
102 if (!q->isVisible()) {
103 return;
104 }
105
106 current_frame++;
107 if (current_frame == frames) {
108 current_frame = 0;
109 }
110
111 updateCurrentIcon();
112}
113
114void KAnimatedButtonPrivate::updateCurrentIcon()
115{
116 if (pixmap.isNull()) {
117 return;
118 }
119
120 QPixmap *frame = framesCache[current_frame];
121 if (!frame) {
122 const int icon_size = qMin(pixmap.width(), pixmap.height());
123 const int row_size = pixmap.width() / icon_size;
124 const int row = current_frame / row_size;
125 const int column = current_frame % row_size;
126 frame = new QPixmap(icon_size, icon_size);
127 frame->fill(Qt::transparent);
128 QPainter p(frame);
129 p.drawPixmap(QPoint(0, 0), pixmap, QRect(column * icon_size, row * icon_size, icon_size, icon_size));
130 p.end();
131 framesCache[current_frame] = frame;
132 }
133
134 q->setIcon(QIcon(*frame));
135}
136
137void KAnimatedButtonPrivate::movieFrameChanged(int number)
138{
139 Q_UNUSED(number);
140 q->setIcon(QIcon(movie->currentPixmap()));
141}
142
143void KAnimatedButtonPrivate::movieFinished()
144{
145 // if not running, make it loop
146 if (movie->state() == QMovie::NotRunning) {
147 movie->start();
148 }
149}
150
151void KAnimatedButtonPrivate::updateIcons()
152{
153 pixmap = QPixmap();
154 QMovie *newMovie = nullptr;
155 QImageReader reader(icon_path);
156 if (QMovie::supportedFormats().contains(reader.format())) {
157 newMovie = new QMovie(icon_path);
158 frames = 0;
160 QObject::connect(newMovie, &QMovie::frameChanged, q, [this](int value) {
161 movieFrameChanged(value);
162 });
163 QObject::connect(newMovie, &QMovie::finished, q, [this] {
164 movieFinished();
165 });
166 } else {
167 const QPixmap pix(icon_path);
168 if (pix.isNull()) {
169 return;
170 }
171
172 const int icon_size = qMin(pix.width(), pix.height());
173 if ((pix.height() % icon_size != 0) || (pix.width() % icon_size != 0)) {
174 return;
175 }
176
177 frames = (pix.height() / icon_size) * (pix.width() / icon_size);
178 pixmap = pix;
179 }
180
181 current_frame = 0;
182 qDeleteAll(framesCache);
183 framesCache.fill(nullptr);
184 framesCache.resize(frames);
185 delete movie;
186 movie = newMovie;
187
188 if (movie) {
189 movie->jumpToFrame(0);
190 movieFrameChanged(0);
191 } else {
192 updateCurrentIcon();
193 }
194}
195
196#include "moc_kanimatedbutton.cpp"
An extended version of QToolButton which can display an animation.
~KAnimatedButton() override
Destructor.
void stop()
Stops the animation.
void start()
Starts the animation from frame 1.
KAnimatedButton(QWidget *parent=nullptr)
Construct an animated tool button.
void setAnimationPath(const QString &path)
Sets the path to the file which contains the animation to load.
void setIcon(const QIcon &icon)
QList< T > & fill(parameter_type value, qsizetype size)
void resize(qsizetype size)
void setCacheMode(CacheMode mode)
QPixmap currentPixmap() const const
void finished()
void frameChanged(int frameNumber)
bool jumpToFrame(int frameNumber)
void start()
MovieState state() const const
QList< QByteArray > supportedFormats()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
void fill(const QColor &color)
int height() const const
bool isNull() const const
int width() const const
transparent
void timeout()
bool isVisible() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:43 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.