File indexing completed on 2024-04-28 15:32:11

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"