File indexing completed on 2025-02-16 13:11:48
0001 /* 0002 SPDX-FileCopyrightText: 2009 Sebastian Trueg <trueg@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "kpixmapsequenceoverlaypainter.h" 0008 #include "kpixmapsequence.h" 0009 0010 #include <QCoreApplication> 0011 #include <QEvent> 0012 #include <QPainter> 0013 #include <QPointer> 0014 #include <QRect> 0015 #include <QTimer> 0016 #include <QWidget> 0017 0018 class KPixmapSequenceOverlayPainterPrivate 0019 { 0020 public: 0021 void init(KPixmapSequenceOverlayPainter *p); 0022 void timeout(); 0023 void paintFrame(); 0024 0025 KPixmapSequence &sequence(); 0026 0027 QRect pixmapRect(); 0028 0029 KPixmapSequence m_sequence; 0030 QPointer<QWidget> m_widget; 0031 Qt::Alignment m_alignment; 0032 QPoint m_offset; 0033 QRect m_rect; 0034 0035 QTimer m_timer; 0036 int m_counter; 0037 0038 bool m_started; 0039 0040 KPixmapSequenceOverlayPainter *q; 0041 }; 0042 0043 void KPixmapSequenceOverlayPainterPrivate::init(KPixmapSequenceOverlayPainter *p) 0044 { 0045 q = p; 0046 m_widget = nullptr; 0047 m_alignment = Qt::AlignCenter; 0048 m_started = false; 0049 q->setInterval(200); 0050 QObject::connect(&m_timer, &QTimer::timeout, q, [this]() { 0051 timeout(); 0052 }); 0053 } 0054 0055 void KPixmapSequenceOverlayPainterPrivate::timeout() 0056 { 0057 if (sequence().isEmpty()) { 0058 return; 0059 } 0060 ++m_counter; 0061 m_counter %= sequence().frameCount(); 0062 if (m_widget) { 0063 m_widget->update(pixmapRect()); 0064 } 0065 } 0066 0067 void KPixmapSequenceOverlayPainterPrivate::paintFrame() 0068 { 0069 if (m_counter >= sequence().frameCount()) { 0070 return; 0071 } 0072 QPainter p(m_widget); 0073 p.drawPixmap(pixmapRect(), sequence().frameAt(m_counter), QRect(QPoint(0, 0), sequence().frameSize())); 0074 } 0075 0076 KPixmapSequence &KPixmapSequenceOverlayPainterPrivate::sequence() 0077 { 0078 return m_sequence; 0079 } 0080 0081 QRect KPixmapSequenceOverlayPainterPrivate::pixmapRect() 0082 { 0083 QRect rect(m_rect); 0084 if (!rect.isValid()) { 0085 rect = m_widget->rect(); 0086 } 0087 0088 QPoint pos(rect.topLeft()); 0089 if (m_alignment & Qt::AlignHCenter) { 0090 pos.setX(rect.center().x() - (sequence().frameSize().width() / 2)); 0091 } else if (m_alignment & Qt::AlignRight) { 0092 pos.setX(rect.right() - sequence().frameSize().width()); 0093 } 0094 0095 if (m_alignment & Qt::AlignVCenter) { 0096 pos.setY(rect.center().y() - (sequence().frameSize().height() / 2)); 0097 } else if (m_alignment & Qt::AlignBottom) { 0098 pos.setY(rect.bottom() - sequence().frameSize().height()); 0099 } 0100 0101 pos += m_offset; 0102 0103 return QRect(pos, sequence().frameSize()); 0104 } 0105 0106 KPixmapSequenceOverlayPainter::KPixmapSequenceOverlayPainter(QObject *parent) 0107 : QObject(parent) 0108 , d(new KPixmapSequenceOverlayPainterPrivate) 0109 { 0110 d->init(this); 0111 } 0112 0113 KPixmapSequenceOverlayPainter::KPixmapSequenceOverlayPainter(const KPixmapSequence &seq, QObject *parent) 0114 : QObject(parent) 0115 , d(new KPixmapSequenceOverlayPainterPrivate) 0116 { 0117 d->init(this); 0118 d->m_sequence = seq; 0119 } 0120 0121 KPixmapSequenceOverlayPainter::~KPixmapSequenceOverlayPainter() 0122 { 0123 stop(); 0124 } 0125 0126 KPixmapSequence KPixmapSequenceOverlayPainter::sequence() const 0127 { 0128 return d->sequence(); 0129 } 0130 0131 int KPixmapSequenceOverlayPainter::interval() const 0132 { 0133 return d->m_timer.interval(); 0134 } 0135 0136 QRect KPixmapSequenceOverlayPainter::rect() const 0137 { 0138 if (d->m_rect.isValid()) { 0139 return d->m_rect; 0140 } else if (d->m_widget) { 0141 return d->m_widget->rect(); 0142 } else { 0143 return QRect(); 0144 } 0145 } 0146 0147 Qt::Alignment KPixmapSequenceOverlayPainter::alignment() const 0148 { 0149 return d->m_alignment; 0150 } 0151 0152 QPoint KPixmapSequenceOverlayPainter::offset() const 0153 { 0154 return d->m_offset; 0155 } 0156 0157 void KPixmapSequenceOverlayPainter::setSequence(const KPixmapSequence &seq) 0158 { 0159 bool restart = d->m_started; 0160 stop(); 0161 d->m_sequence = seq; 0162 if (restart) { 0163 start(); 0164 } 0165 } 0166 0167 void KPixmapSequenceOverlayPainter::setInterval(int msecs) 0168 { 0169 d->m_timer.setInterval(msecs); 0170 } 0171 0172 void KPixmapSequenceOverlayPainter::setWidget(QWidget *w) 0173 { 0174 stop(); 0175 d->m_widget = w; 0176 } 0177 0178 void KPixmapSequenceOverlayPainter::setRect(const QRect &rect) 0179 { 0180 bool restart = d->m_started; 0181 stop(); 0182 d->m_rect = rect; 0183 if (restart) { 0184 start(); 0185 } 0186 } 0187 0188 void KPixmapSequenceOverlayPainter::setAlignment(Qt::Alignment align) 0189 { 0190 bool restart = d->m_started; 0191 stop(); 0192 d->m_alignment = align; 0193 if (restart) { 0194 start(); 0195 } 0196 } 0197 0198 void KPixmapSequenceOverlayPainter::setOffset(const QPoint &offset) 0199 { 0200 bool restart = d->m_started; 0201 stop(); 0202 d->m_offset = offset; 0203 if (restart) { 0204 start(); 0205 } 0206 } 0207 0208 void KPixmapSequenceOverlayPainter::start() 0209 { 0210 if (d->m_widget) { 0211 stop(); 0212 0213 d->m_counter = 0; 0214 d->m_started = true; 0215 d->m_widget->installEventFilter(this); 0216 if (d->m_widget->isVisible()) { 0217 d->m_timer.start(); 0218 d->m_widget->update(d->pixmapRect()); 0219 } 0220 } 0221 } 0222 0223 void KPixmapSequenceOverlayPainter::stop() 0224 { 0225 d->m_timer.stop(); 0226 if (d->m_widget && d->m_started) { 0227 d->m_started = false; 0228 d->m_widget->removeEventFilter(this); 0229 d->m_widget->update(d->pixmapRect()); 0230 } 0231 } 0232 0233 bool KPixmapSequenceOverlayPainter::eventFilter(QObject *obj, QEvent *event) 0234 { 0235 if (obj == d->m_widget) { 0236 switch (event->type()) { 0237 case QEvent::Paint: 0238 // make sure we paint after everyone else including other event filters 0239 obj->removeEventFilter(this); // don't recourse... 0240 QCoreApplication::sendEvent(obj, event); 0241 d->paintFrame(); 0242 obj->installEventFilter(this); // catch on... 0243 return true; 0244 break; 0245 case QEvent::Hide: 0246 d->m_timer.stop(); 0247 break; 0248 case QEvent::Show: 0249 if (d->m_started) { 0250 d->m_timer.start(); 0251 d->m_widget->update(d->pixmapRect()); 0252 } 0253 break; 0254 default: 0255 break; 0256 } 0257 } 0258 0259 return false; 0260 } 0261 0262 #include "moc_kpixmapsequenceoverlaypainter.cpp"