1/*
2 SPDX-FileCopyrightText: 2009 Sebastian Trueg <trueg@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6
7#include "kpixmapsequenceoverlaypainter.h"
8#include "kpixmapsequence.h"
9
10#include <QCoreApplication>
11#include <QEvent>
12#include <QPainter>
13#include <QPointer>
14#include <QRect>
15#include <QTimer>
16#include <QWidget>
17
18class KPixmapSequenceOverlayPainterPrivate
19{
20public:
21 void init(KPixmapSequenceOverlayPainter *p);
22 void timeout();
23 void paintFrame();
24
25 KPixmapSequence &sequence();
26
27 QRect pixmapRect();
28
29 KPixmapSequence m_sequence;
30 QPointer<QWidget> m_widget;
31 Qt::Alignment m_alignment;
32 QPoint m_offset;
33 QRect m_rect;
34
35 QTimer m_timer;
36 int m_counter;
37
38 bool m_started;
39
40 KPixmapSequenceOverlayPainter *q;
41};
42
43void KPixmapSequenceOverlayPainterPrivate::init(KPixmapSequenceOverlayPainter *p)
44{
45 q = p;
46 m_widget = nullptr;
47 m_alignment = Qt::AlignCenter;
48 m_started = false;
49 q->setInterval(200);
50 QObject::connect(sender: &m_timer, signal: &QTimer::timeout, context: q, slot: [this]() {
51 timeout();
52 });
53}
54
55void KPixmapSequenceOverlayPainterPrivate::timeout()
56{
57 if (sequence().isEmpty()) {
58 return;
59 }
60 ++m_counter;
61 m_counter %= sequence().frameCount();
62 if (m_widget) {
63 m_widget->update(pixmapRect());
64 }
65}
66
67void KPixmapSequenceOverlayPainterPrivate::paintFrame()
68{
69 if (m_counter >= sequence().frameCount()) {
70 return;
71 }
72 QPainter p(m_widget);
73 p.drawPixmap(targetRect: pixmapRect(), pixmap: sequence().frameAt(index: m_counter), sourceRect: QRect(QPoint(0, 0), sequence().frameSize()));
74}
75
76KPixmapSequence &KPixmapSequenceOverlayPainterPrivate::sequence()
77{
78 return m_sequence;
79}
80
81QRect KPixmapSequenceOverlayPainterPrivate::pixmapRect()
82{
83 QRect rect(m_rect);
84 if (!rect.isValid()) {
85 rect = m_widget->rect();
86 }
87
88 QPoint pos(rect.topLeft());
89 if (m_alignment & Qt::AlignHCenter) {
90 pos.setX(rect.center().x() - (sequence().frameSize().width() / 2));
91 } else if (m_alignment & Qt::AlignRight) {
92 pos.setX(rect.right() - sequence().frameSize().width());
93 }
94
95 if (m_alignment & Qt::AlignVCenter) {
96 pos.setY(rect.center().y() - (sequence().frameSize().height() / 2));
97 } else if (m_alignment & Qt::AlignBottom) {
98 pos.setY(rect.bottom() - sequence().frameSize().height());
99 }
100
101 pos += m_offset;
102
103 return QRect(pos, sequence().frameSize());
104}
105
106KPixmapSequenceOverlayPainter::KPixmapSequenceOverlayPainter(QObject *parent)
107 : QObject(parent)
108 , d(new KPixmapSequenceOverlayPainterPrivate)
109{
110 d->init(p: this);
111}
112
113KPixmapSequenceOverlayPainter::KPixmapSequenceOverlayPainter(const KPixmapSequence &seq, QObject *parent)
114 : QObject(parent)
115 , d(new KPixmapSequenceOverlayPainterPrivate)
116{
117 d->init(p: this);
118 d->m_sequence = seq;
119}
120
121KPixmapSequenceOverlayPainter::~KPixmapSequenceOverlayPainter()
122{
123 stop();
124}
125
126KPixmapSequence KPixmapSequenceOverlayPainter::sequence() const
127{
128 return d->sequence();
129}
130
131int KPixmapSequenceOverlayPainter::interval() const
132{
133 return d->m_timer.interval();
134}
135
136QRect KPixmapSequenceOverlayPainter::rect() const
137{
138 if (d->m_rect.isValid()) {
139 return d->m_rect;
140 } else if (d->m_widget) {
141 return d->m_widget->rect();
142 } else {
143 return QRect();
144 }
145}
146
147Qt::Alignment KPixmapSequenceOverlayPainter::alignment() const
148{
149 return d->m_alignment;
150}
151
152QPoint KPixmapSequenceOverlayPainter::offset() const
153{
154 return d->m_offset;
155}
156
157void KPixmapSequenceOverlayPainter::setSequence(const KPixmapSequence &seq)
158{
159 bool restart = d->m_started;
160 stop();
161 d->m_sequence = seq;
162 if (restart) {
163 start();
164 }
165}
166
167void KPixmapSequenceOverlayPainter::setInterval(int msecs)
168{
169 d->m_timer.setInterval(msecs);
170}
171
172void KPixmapSequenceOverlayPainter::setWidget(QWidget *w)
173{
174 stop();
175 d->m_widget = w;
176}
177
178void KPixmapSequenceOverlayPainter::setRect(const QRect &rect)
179{
180 bool restart = d->m_started;
181 stop();
182 d->m_rect = rect;
183 if (restart) {
184 start();
185 }
186}
187
188void KPixmapSequenceOverlayPainter::setAlignment(Qt::Alignment align)
189{
190 bool restart = d->m_started;
191 stop();
192 d->m_alignment = align;
193 if (restart) {
194 start();
195 }
196}
197
198void KPixmapSequenceOverlayPainter::setOffset(const QPoint &offset)
199{
200 bool restart = d->m_started;
201 stop();
202 d->m_offset = offset;
203 if (restart) {
204 start();
205 }
206}
207
208void KPixmapSequenceOverlayPainter::start()
209{
210 if (d->m_widget) {
211 stop();
212
213 d->m_counter = 0;
214 d->m_started = true;
215 d->m_widget->installEventFilter(filterObj: this);
216 if (d->m_widget->isVisible()) {
217 d->m_timer.start();
218 d->m_widget->update(d->pixmapRect());
219 }
220 }
221}
222
223void KPixmapSequenceOverlayPainter::stop()
224{
225 d->m_timer.stop();
226 if (d->m_widget && d->m_started) {
227 d->m_started = false;
228 d->m_widget->removeEventFilter(obj: this);
229 d->m_widget->update(d->pixmapRect());
230 }
231}
232
233bool KPixmapSequenceOverlayPainter::eventFilter(QObject *obj, QEvent *event)
234{
235 if (obj == d->m_widget) {
236 switch (event->type()) {
237 case QEvent::Paint:
238 // make sure we paint after everyone else including other event filters
239 obj->removeEventFilter(obj: this); // don't recourse...
240 QCoreApplication::sendEvent(receiver: obj, event);
241 d->paintFrame();
242 obj->installEventFilter(filterObj: this); // catch on...
243 return true;
244 break;
245 case QEvent::Hide:
246 d->m_timer.stop();
247 break;
248 case QEvent::Show:
249 if (d->m_started) {
250 d->m_timer.start();
251 d->m_widget->update(d->pixmapRect());
252 }
253 break;
254 default:
255 break;
256 }
257 }
258
259 return false;
260}
261
262#include "moc_kpixmapsequenceoverlaypainter.cpp"
263

source code of kwidgetsaddons/src/kpixmapsequenceoverlaypainter.cpp