File indexing completed on 2024-10-06 03:45:27

0001 /*
0002     This file is part of the KDE games kwin4 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 
0010 // own
0011 #include "kfourinline_debug.h"
0012 // KF
0013 #include <KConfig>
0014 #include <KConfigGroup>
0015 // Qt
0016 #include <QGraphicsScene>
0017 // Std
0018 #include <cmath>
0019 
0020 // Constructor for the sprite
0021 PixmapSprite::PixmapSprite(const QString &id, ThemeManager *theme, int no, QGraphicsScene *canvas)
0022     : Themeable(id, theme)
0023     , QGraphicsPixmapItem()
0024 {
0025     canvas->addItem(this);
0026     hide();
0027     setAcceptHoverEvents(false);
0028 
0029     mAnimationState = Idle;
0030     mNo = no;
0031     mCurrentFrame = 0;
0032     mOffsetStatus = true;
0033 
0034     if (theme)
0035         theme->updateTheme(this);
0036 }
0037 
0038 // Constructor for the sprite
0039 PixmapSprite::PixmapSprite(int no, QGraphicsScene *canvas)
0040     : Themeable()
0041     , QGraphicsPixmapItem()
0042 {
0043     canvas->addItem(this);
0044     hide();
0045 
0046     mAnimationState = Idle;
0047     mNo = no;
0048     mCurrentFrame = 0;
0049     mOffsetStatus = true;
0050 }
0051 
0052 // Main themeable function. Called for any theme change. The sprites needs to
0053 // resize and redraw here.
0054 void PixmapSprite::changeTheme()
0055 {
0056     // Clear data
0057     mFrames.clear();
0058     mHotspots.clear();
0059 
0060     // Get scaling change
0061     double oldscale = this->getScale();
0062     double scale = thememanager()->getScale();
0063     Themeable::setScale(scale);
0064 
0065     // Retrieve theme data from configuration
0066     KConfigGroup config = thememanager()->config(id());
0067     double width = config.readEntry("width", 1.0);
0068     double height = config.readEntry("height", 0.0);
0069     width *= scale;
0070     height *= scale;
0071     QPointF pos = config.readEntry("pos", QPointF(1.0, 1.0));
0072     pos *= scale;
0073     // Set fixed z value?
0074     if (config.hasKey("zValue")) {
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         setPos(pos.x(), pos.y());
0091     } else {
0092         setPos(x() * scale / oldscale, y() * scale / oldscale);
0093     }
0094 
0095     // SVG graphics
0096     QString svgid = config.readEntry("svgid");
0097     // Read sequence of frame pixmaps when auto ID given
0098     QPixmap pixmap;
0099     if (svgid == QLatin1String("auto")) {
0100         for (int i = mStartFrame; i <= mEndFrame; i++) {
0101             QString name = QStringLiteral("frame%1").arg(i);
0102             svgid = config.readEntry(name);
0103             QSize size;
0104             if (!refframe.isNull()) {
0105                 size = thememanager()->pixmapSize(svgid, refframe, width);
0106             } else if (config.hasKey("height")) {
0107                 size =QSize(int(width), int(height));
0108             } else {
0109                 size = thememanager()->pixmapSize(svgid, width);
0110             }
0111             pixmap = thememanager()->getPixmap(svgid, size);
0112             mFrames.append(pixmap);
0113             if (center)
0114                 mHotspots.append(QPointF(size.width() / 2, size.height() / 2));
0115             else
0116                 mHotspots.append(QPointF(0.0, 0.0));
0117         }
0118     }
0119     // Read only one named pixmap
0120     else {
0121         QSize size;
0122         if (config.hasKey("height")) {
0123             size = QSize(int(width), int(height));
0124         } else {
0125             size = thememanager()->pixmapSize(svgid, width);
0126         }
0127         pixmap = thememanager()->getPixmap(svgid, size);
0128         mFrames.append(pixmap);
0129         if (center)
0130             mHotspots.append(QPointF(size.width() / 2, size.height() / 2));
0131         else
0132             mHotspots.append(QPointF(0.0, 0.0));
0133     }
0134 
0135     // Set theme offset (probably not really necessary here)
0136     QPoint offset = thememanager()->getOffset();
0137     resetTransform();
0138     if (mOffsetStatus)
0139         setTransform(QTransform::fromTranslate(offset.x(), offset.y()), true);
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(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 // Store the logical board coordinates for theme changes
0168 void PixmapSprite::setLogicalPos(QPoint pos)
0169 {
0170     mLPos = pos;
0171 }
0172 
0173 // Retrieve the logical board coordinates for theme changes
0174 QPoint PixmapSprite::logicalPos()
0175 {
0176     return mLPos;
0177 }
0178 
0179 // Start or stop a frame animation
0180 void PixmapSprite::setAnimation(bool status)
0181 {
0182     if (status)
0183         mAnimationState = Animated;
0184     else
0185         mAnimationState = Idle;
0186     mTime.start();
0187     setFrame(mStartFrame);
0188 }
0189 
0190 // Specify and start a frame animation
0191 void PixmapSprite::setAnimation(int start, int end, int delay)
0192 {
0193     mDelay = delay;
0194     mStartFrame = start;
0195     mEndFrame = end;
0196     setAnimation(true);
0197 }
0198 
0199 // Set a new bitmap into the sprite. If the number is the same as the
0200 // current one, nothing is done unless forcing is set to true.
0201 void PixmapSprite::setFrame(int no, bool force)
0202 {
0203     if (!force && no == mCurrentFrame)
0204         return;
0205     if (no < 0 || no >= mFrames.count())
0206         return;
0207     setPixmap(mFrames.at(no));
0208 
0209     QPoint offset = thememanager()->getOffset();
0210 
0211     // Set new item's scene transformation: Hotspot plus global theme offset
0212     resetTransform();
0213     if (mOffsetStatus) {
0214         setTransform(QTransform::fromTranslate(-mHotspots.at(no).x() + offset.x(), -mHotspots.at(no).y() + offset.y()), true);
0215     } else {
0216         setTransform(QTransform::fromTranslate(-mHotspots.at(no).x(), -mHotspots.at(no).y()), true);
0217     }
0218     mCurrentFrame = no;
0219     update();
0220 }
0221 
0222 // Standard QGI advance method
0223 void PixmapSprite::advance(int phase)
0224 {
0225     int elapsed = mTime.elapsed();
0226 
0227     // Ignore phase 0 (collisions)
0228     if (phase == 0) {
0229         QGraphicsItem::advance(phase);
0230         return;
0231     }
0232 
0233     // Handle animation
0234     if (mAnimationState == Animated) {
0235         // Frame delay passed?
0236         int frames = elapsed / mDelay;
0237         int curFrame = frames % (mEndFrame - mStartFrame) + mStartFrame;
0238         setFrame(curFrame);
0239     }
0240 
0241     QGraphicsItem::advance(phase);
0242 }