File indexing completed on 2024-04-14 04:02:25

0001 /*
0002     This file is part of the KDE games lskat program
0003     SPDX-FileCopyrightText: 2006 Martin Heni <kde@heni-online.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "pixmapsprite.h"
0009 #include "lskat_debug.h"
0010 
0011 // General includes
0012 #include <math.h>
0013 
0014 // Qt includes
0015 #include <QGraphicsScene>
0016 
0017 // KF includes
0018 #include <KConfig>
0019 #include <KConfigGroup>
0020 
0021 // Constructor for the sprite
0022 PixmapSprite::PixmapSprite(const QString &id, ThemeManager *theme, int advancePeriod, int no, QGraphicsScene *canvas)
0023     : Themable(id, theme), QGraphicsPixmapItem(nullptr)
0024 {
0025     canvas->addItem(this);
0026     hide();
0027 
0028     mAnimationState = Idle;
0029     mAdvancePeriod  = advancePeriod;
0030     mNo             = no;
0031     mCurrentFrame   = 0;
0032     mOffsetStatus   = true;
0033 
0034     if (theme) theme->updateTheme(this);
0035 }
0036 
0037 // Constructor for the sprite
0038 PixmapSprite::PixmapSprite(int advancePeriod, int no, QGraphicsScene *canvas)
0039     :  Themable(), QGraphicsPixmapItem(nullptr)
0040 {
0041     canvas->addItem(this);
0042     hide();
0043 
0044     mAnimationState = Idle;
0045     mAdvancePeriod  = advancePeriod;
0046     mNo             = no;
0047     mCurrentFrame   = 0;
0048     mOffsetStatus   = true;
0049 }
0050 
0051 // Main themable function. Called for any theme change. The sprites needs to
0052 // resize and redraw here.
0053 void PixmapSprite::changeTheme()
0054 {
0055     // Clear data
0056     mFrames.clear();
0057     mHotspots.clear();
0058 
0059     // Get scaling change
0060     double oldscale = this->getScale();
0061     double scale = thememanager()->getScale();
0062     Themable::setScale(scale);
0063 
0064     // Retrieve theme data from configuration
0065     KConfigGroup config = thememanager()->config(id());
0066     double width  = config.readEntry("width", 1.0);
0067     double height = config.readEntry("height", 0.0);
0068     width *= scale;
0069     height *= scale;
0070     QPointF pos = config.readEntry("pos", QPointF(1.0, 1.0));
0071     pos *= scale;
0072     // Set fixed z value?
0073     if (config.hasKey("zValue"))
0074     {
0075         double zValue = config.readEntry("zValue", 0.0);
0076         setZValue(zValue);
0077     }
0078 
0079     // Centering
0080     bool center = config.readEntry("center", false);
0081 
0082     // Animation
0083     mStartFrame      = config.readEntry("start-frame", 0);
0084     mEndFrame        = config.readEntry("end-frame", 0);
0085     mDelay           = config.readEntry("animation-delay", 0);
0086     QString refframe = config.readEntry("ref-frame", QString());
0087 
0088     // Set fixed position or modify current position
0089     if (config.hasKey("pos"))
0090     {
0091         setPos(pos.x(), pos.y());
0092     }
0093     else
0094     {
0095         setPos(x() * scale / oldscale, y() * scale / oldscale);
0096     }
0097 
0098     // SVG graphics
0099     QString svgid = config.readEntry("svgid");
0100     // Read sequence of frame pixmaps when auto ID given
0101     QPixmap pixmap;
0102     if (svgid == QLatin1String("auto"))
0103     {
0104         const int frameCount = mEndFrame - mStartFrame + 1;
0105         mFrames.reserve(frameCount);
0106         mHotspots.reserve(frameCount);
0107         for (int i = mStartFrame; i <= mEndFrame; i++)
0108         {
0109             QString name = QStringLiteral("frame%1").arg(i);
0110             svgid = config.readEntry(name);
0111             if (!refframe.isNull())
0112             {
0113                 pixmap = thememanager()->getPixmap(svgid, refframe, width);
0114             }
0115             else if (config.hasKey("height"))
0116             {
0117                 pixmap = thememanager()->getPixmap(svgid, QSize(int(width), int(height)));
0118             }
0119             else
0120             {
0121                 pixmap = thememanager()->getPixmap(svgid, width);
0122             }
0123             mFrames.append(pixmap);
0124             if (center) mHotspots.append(QPointF(pixmap.width() / 2, pixmap.height() / 2));
0125             else mHotspots.append(QPointF(0.0, 0.0));
0126         }
0127     }
0128     // Read only one named pixmap
0129     else
0130     {
0131         if (config.hasKey("height"))
0132         {
0133             pixmap = thememanager()->getPixmap(svgid, QSize(int(width), int(height)));
0134         }
0135         else
0136         {
0137             pixmap = thememanager()->getPixmap(svgid, width);
0138         }
0139         mFrames.append(pixmap);
0140         if (center) mHotspots.append(QPointF(pixmap.width() / 2, pixmap.height() / 2));
0141         else mHotspots.append(QPointF(0.0, 0.0));
0142     }
0143 
0144     // Set pixmap to sprite
0145     setFrame(mCurrentFrame, true);
0146     update();
0147 }
0148 
0149 // Debug only: Retrieve double value from configuration file
0150 double PixmapSprite::getDoubleValue(const QString &item)
0151 {
0152     KConfigGroup config = thememanager()->config(id());
0153     return config.readEntry(item, 0.0);
0154 }
0155 
0156 // Move the sprite to the given relative position
0157 void PixmapSprite::setPosition(const QPointF &pos)
0158 {
0159     mStart          = pos;
0160     setPos(mStart.x() * getScale(), mStart.y() * getScale());
0161 }
0162 
0163 // Handle the offset status (true: theme offset, false: no offset)
0164 void PixmapSprite::setOffsetStatus(bool status)
0165 {
0166     mOffsetStatus = status;
0167     changeTheme();
0168 }
0169 
0170 // Start or stop a frame animation
0171 void PixmapSprite::setAnimation(bool status)
0172 {
0173     if (status) mAnimationState = Animated;
0174     else mAnimationState = Idle;
0175     mTime           = 0;
0176     setFrame(mStartFrame);
0177 }
0178 
0179 // Specify and start a frame animation
0180 void PixmapSprite::setAnimation(int start, int end, int delay)
0181 {
0182     mDelay          = delay;
0183     mStartFrame     = start;
0184     mEndFrame       = end;
0185     setAnimation(true);
0186 }
0187 
0188 // Set a new bitmap into the sprite. If the number is the same as the
0189 // current one, nothing is done unless forcing is set to true.
0190 void PixmapSprite::setFrame(int no, bool force)
0191 {
0192     if (!force && no == mCurrentFrame) return;
0193     if (no < 0 || no >= mFrames.count()) return;
0194     setPixmap(mFrames.at(no));
0195 
0196     QPoint offset = thememanager()->getOffset();
0197     resetTransform();
0198     if (mOffsetStatus)
0199     {
0200         setTransform(QTransform::fromTranslate(-mHotspots.at(no).x() + offset.x(), -mHotspots.at(no).y() + offset.y()), true);
0201     }
0202     else
0203     {
0204         setTransform(QTransform::fromTranslate(-mHotspots.at(no).x(), -mHotspots.at(no).y()), true);
0205     }
0206     mCurrentFrame = no;
0207     update();
0208 }
0209 
0210 // Standard QGI advance method
0211 void PixmapSprite::advance(int phase)
0212 {
0213     // Ignore phase 0 (collisions)
0214     if (phase == 0)
0215     {
0216         QGraphicsItem::advance(phase);
0217         return;
0218     }
0219 
0220     // Increase time
0221     mTime += mAdvancePeriod;
0222 
0223     // Handle animation
0224     if (mAnimationState == Animated)
0225     {
0226         // Frame delay passed?
0227         if (mTime > mDelay)
0228         {
0229             mTime = 0;
0230             int frame = mCurrentFrame + 1;
0231             if (frame > mEndFrame) setFrame(mStartFrame);
0232             else setFrame(frame);
0233         }
0234     }
0235 
0236     QGraphicsItem::advance(phase);
0237 }