File indexing completed on 2023-10-01 08:05: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         for (int i = mStartFrame; i <= mEndFrame; i++)
0105         {
0106             QString name = QStringLiteral("frame%1").arg(i);
0107             svgid = config.readEntry(name);
0108             if (!refframe.isNull())
0109             {
0110                 pixmap = thememanager()->getPixmap(svgid, refframe, width);
0111             }
0112             else if (config.hasKey("height"))
0113             {
0114                 pixmap = thememanager()->getPixmap(svgid, QSize(int(width), int(height)));
0115             }
0116             else
0117             {
0118                 pixmap = thememanager()->getPixmap(svgid, width);
0119             }
0120             mFrames.append(pixmap);
0121             if (center) mHotspots.append(QPointF(pixmap.width() / 2, pixmap.height() / 2));
0122             else mHotspots.append(QPointF(0.0, 0.0));
0123         }
0124     }
0125     // Read only one named pixmap
0126     else
0127     {
0128         if (config.hasKey("height"))
0129         {
0130             pixmap = thememanager()->getPixmap(svgid, QSize(int(width), int(height)));
0131         }
0132         else
0133         {
0134             pixmap = thememanager()->getPixmap(svgid, width);
0135         }
0136         mFrames.append(pixmap);
0137         if (center) mHotspots.append(QPointF(pixmap.width() / 2, pixmap.height() / 2));
0138         else mHotspots.append(QPointF(0.0, 0.0));
0139     }
0140 
0141     // Set pixmap to sprite
0142     setFrame(mCurrentFrame, true);
0143     update();
0144 }
0145 
0146 // Debug only: Retrieve double value from configuration file
0147 double PixmapSprite::getDoubleValue(const QString &item)
0148 {
0149     KConfigGroup config = thememanager()->config(id());
0150     return config.readEntry(item, 0.0);
0151 }
0152 
0153 // Move the sprite to the given relative position
0154 void PixmapSprite::setPosition(const QPointF &pos)
0155 {
0156     mStart          = pos;
0157     setPos(mStart.x() * getScale(), mStart.y() * getScale());
0158 }
0159 
0160 // Handle the offset status (true: theme offset, false: no offset)
0161 void PixmapSprite::setOffsetStatus(bool status)
0162 {
0163     mOffsetStatus = status;
0164     changeTheme();
0165 }
0166 
0167 // Start or stop a frame animation
0168 void PixmapSprite::setAnimation(bool status)
0169 {
0170     if (status) mAnimationState = Animated;
0171     else mAnimationState = Idle;
0172     mTime           = 0;
0173     setFrame(mStartFrame);
0174 }
0175 
0176 // Specify and start a frame animation
0177 void PixmapSprite::setAnimation(int start, int end, int delay)
0178 {
0179     mDelay          = delay;
0180     mStartFrame     = start;
0181     mEndFrame       = end;
0182     setAnimation(true);
0183 }
0184 
0185 // Set a new bitmap into the sprite. If the number is the same as the
0186 // current one, nothing is done unless forcing is set to true.
0187 void PixmapSprite::setFrame(int no, bool force)
0188 {
0189     if (!force && no == mCurrentFrame) return;
0190     if (no < 0 || no >= mFrames.count()) return;
0191     setPixmap(mFrames.at(no));
0192 
0193     QPoint offset = thememanager()->getOffset();
0194     resetTransform();
0195     if (mOffsetStatus)
0196     {
0197         setTransform(QTransform::fromTranslate(-mHotspots.at(no).x() + offset.x(), -mHotspots.at(no).y() + offset.y()), true);
0198     }
0199     else
0200     {
0201         setTransform(QTransform::fromTranslate(-mHotspots.at(no).x(), -mHotspots.at(no).y()), true);
0202     }
0203     mCurrentFrame = no;
0204     update();
0205 }
0206 
0207 // Standard QGI advance method
0208 void PixmapSprite::advance(int phase)
0209 {
0210     // Ignore phase 0 (collisions)
0211     if (phase == 0)
0212     {
0213         QGraphicsItem::advance(phase);
0214         return;
0215     }
0216 
0217     // Increase time
0218     mTime += mAdvancePeriod;
0219 
0220     // Handle animation
0221     if (mAnimationState == Animated)
0222     {
0223         // Frame delay passed?
0224         if (mTime > mDelay)
0225         {
0226             mTime = 0;
0227             int frame = mCurrentFrame + 1;
0228             if (frame > mEndFrame) setFrame(mStartFrame);
0229             else setFrame(frame);
0230         }
0231     }
0232 
0233     QGraphicsItem::advance(phase);
0234 }