File indexing completed on 2023-12-03 04:14:50

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 "thememanager.h"
0009 
0010 // own
0011 #include "kfourinline_debug.h"
0012 #include "kwin4global.h"
0013 // KF
0014 #include <KConfigGroup>
0015 #include <KLocalizedString>
0016 // Qt
0017 #include <QImage>
0018 #include <QPainter>
0019 #include <QPixmap>
0020 #include <QRectF>
0021 #include <QStandardPaths>
0022 
0023 // Constructor for the theme manager
0024 ThemeManager::ThemeManager(const QString &themefile, QObject *parent, int initialSize)
0025     : QObject(parent)
0026     , mRenderer()
0027     , mConfig()
0028 {
0029     mScale = initialSize;
0030     mAspectRatio = 1.0;
0031     mThemeFileChanged = false;
0032     updateTheme(themefile);
0033 }
0034 
0035 ThemeManager::~ThemeManager()
0036 {
0037     delete mConfig;
0038     delete mRenderer;
0039 }
0040 
0041 // Register an object with the manager
0042 void ThemeManager::registerTheme(Themeable *ob)
0043 {
0044     // We want to make sure that we draw the items registered last, first.
0045     mObjects.prepend(ob);
0046 }
0047 
0048 // Unregister an object from the manager
0049 void ThemeManager::unregisterTheme(Themeable *ob)
0050 {
0051     mObjects.removeAll(ob);
0052 }
0053 
0054 // Check whether the theme is alright
0055 int ThemeManager::checkTheme()
0056 {
0057     // Check theme
0058     if (mRenderer == nullptr)
0059         return 1;
0060     return 0; // Ok
0061 }
0062 
0063 // Check the reason of the theme change (rescale or new theme)
0064 bool ThemeManager::themefileChanged()
0065 {
0066     return mThemeFileChanged;
0067 }
0068 
0069 // Force an refresh of the theme object given
0070 void ThemeManager::updateTheme(Themeable *ob)
0071 {
0072     ob->changeTheme();
0073 }
0074 
0075 // Update the theme file and refresh all registered objects. Used
0076 // to really change the theme.
0077 void ThemeManager::updateTheme(const QString &themefile)
0078 {
0079     mThemeFileChanged = true;
0080 
0081     // Empty cache
0082     mPixmapCache.clear();
0083 
0084     // Process dirs
0085     QString rcfile = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("grafix/") + themefile);
0086     qCDebug(KFOURINLINE_LOG) << "ThemeManager LOAD with theme " << rcfile;
0087 
0088     // Read config and SVG file for theme
0089     delete mConfig;
0090     mConfig = new KConfig(rcfile, KConfig::NoGlobals);
0091     QString svgfile = config(QStringLiteral("general")).readEntry("svgfile");
0092     svgfile = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("grafix/") + svgfile);
0093     qCDebug(KFOURINLINE_LOG) << "Reading SVG master file  =" << svgfile;
0094     mAspectRatio = config(QStringLiteral("general")).readEntry("aspect-ratio", 1.0);
0095     qCDebug(KFOURINLINE_LOG) << "Aspect ratio =" << mAspectRatio;
0096     mColorNamePlayer[0] = i18nc("Player 0 color", config(QStringLiteral("general")).readEntry("colorNamePlayer0").toUtf8().constData());
0097     qCDebug(KFOURINLINE_LOG) << "Player 0 color name =" << mColorNamePlayer[0];
0098     mColorNamePlayer[1] = i18nc("Player 1 color", config(QStringLiteral("general")).readEntry("colorNamePlayer1").toUtf8().constData());
0099     qCDebug(KFOURINLINE_LOG) << "Player 1 color name =" << mColorNamePlayer[1];
0100 
0101     delete mRenderer;
0102     mRenderer = new QSvgRenderer(this);
0103     bool result = mRenderer->load(svgfile);
0104     if (!result) {
0105         delete mRenderer;
0106         mRenderer = nullptr;
0107         qCCritical(KFOURINLINE_LOG) << "Cannot open file" << svgfile;
0108     }
0109     qCDebug(KFOURINLINE_LOG) << "Renderer" << mRenderer << " =" << result;
0110 
0111     // Notify all theme objects of a change
0112     for (Themeable *object : std::as_const(mObjects)) {
0113         object->changeTheme();
0114     }
0115 }
0116 
0117 // Rescale the theme. Call all registered objects so that they can refresh.
0118 void ThemeManager::rescale(int scale, QPoint offset)
0119 {
0120     if (global_debug > 0)
0121         qCDebug(KFOURINLINE_LOG) << "THEMEMANAGER::Rescaling theme to " << scale << " offset to " << offset;
0122 
0123     mThemeFileChanged = false;
0124 
0125     if (global_debug > 1) {
0126         if (scale == mScale)
0127             qCDebug(KFOURINLINE_LOG) << " No scale change to" << scale << ". If this happens too often it is BAD";
0128     }
0129     // if (scale==mScale) return;
0130     mScale = scale;
0131     mOffset = offset;
0132 
0133     for (Themeable *object : std::as_const(mObjects)) {
0134         object->changeTheme();
0135     }
0136 }
0137 
0138 // Retrieve the theme's scale
0139 double ThemeManager::getScale()
0140 {
0141     return (double)mScale;
0142 }
0143 
0144 // Retrieve the theme offset
0145 QPoint ThemeManager::getOffset()
0146 {
0147     return mOffset;
0148 }
0149 
0150 // Retrieve the current theme configuration file.
0151 KConfigGroup ThemeManager::config(const QString &id)
0152 {
0153     KConfigGroup grp = mConfig->group(id);
0154     return grp;
0155 }
0156 
0157 // Get a pixmap when its size is given (this can distort the image)
0158 const QPixmap ThemeManager::getPixmap(const QString &svgid, QSize size)
0159 {
0160     if (size.width() < 1 || size.height() < 1)
0161         qCCritical(KFOURINLINE_LOG) << "ThemeManager::getPixmap Cannot create svgid ID " << svgid << " with zero size" << size;
0162 
0163     QPixmap pixmap;
0164 
0165     //  Cached pixmap?
0166     if (mPixmapCache.contains(svgid)) {
0167         pixmap = mPixmapCache[svgid];
0168         if (pixmap.size() == size) {
0169             return pixmap;
0170         }
0171     }
0172 
0173     // Create new image
0174     QImage image(size, QImage::Format_ARGB32_Premultiplied);
0175     image.fill(0);
0176     QPainter p(&image);
0177     mRenderer->render(&p, svgid);
0178     p.end();
0179     pixmap = QPixmap::fromImage(image);
0180     if (pixmap.isNull())
0181         qCCritical(KFOURINLINE_LOG) << "ThemeManager::getPixmap Cannot load svgid ID " << svgid;
0182 
0183     // Cache image
0184     mPixmapCache[svgid] = pixmap;
0185 
0186     return pixmap;
0187 }
0188 
0189 // Get a pixmap when only width is given (this keeps the aspect ratio)
0190 const QPixmap ThemeManager::getPixmap(const QString &svgid, double width)
0191 {
0192     QRectF rect = mRenderer->boundsOnElement(svgid);
0193     double factor = width / rect.width();
0194     QSize size = QSize(int(width), int(rect.height() * factor));
0195     return getPixmap(svgid, size);
0196 }
0197 
0198 // Get a pixmap with original properties and a scale factor given with respect to
0199 // another SVG item.
0200 const QPixmap ThemeManager::getPixmap(const QString &svgid, const QString &svgref, double refwidth)
0201 {
0202     QRectF refrect = mRenderer->boundsOnElement(svgref);
0203     QRectF rect = mRenderer->boundsOnElement(svgid);
0204     double factor = refwidth / refrect.width();
0205     QSize size = QSize(int(rect.width() * factor), int(rect.height() * factor));
0206     return getPixmap(svgid, size);
0207 }
0208 
0209 // ========================== Themeable interface ===============================
0210 
0211 // Constructs a themeable interface
0212 Themeable::Themeable()
0213 {
0214     mScale = 1.0;
0215     mThemeManager = nullptr;
0216 }
0217 
0218 // Constructs a themeable interface given its id and the master theme manager.
0219 // This automatically registers the object with the manager.
0220 Themeable::Themeable(const QString &id, ThemeManager *thememanager)
0221 {
0222     mScale = 1.0;
0223     mId = id;
0224     mThemeManager = thememanager;
0225     if (!thememanager)
0226         return;
0227     thememanager->registerTheme(this);
0228 }
0229 
0230 // Destructs the themeable object
0231 Themeable::~Themeable()
0232 {
0233     if (mThemeManager)
0234         mThemeManager->unregisterTheme(this);
0235 }
0236 
0237 #include "moc_thememanager.cpp"