File indexing completed on 2024-10-06 06:47:17

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 <QApplication>
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     const qreal dpr = qApp->devicePixelRatio();
0164     size *= dpr;
0165 
0166     //  Cached pixmap?
0167     if (mPixmapCache.contains(svgid)) {
0168         const QPixmap pixmap = mPixmapCache[svgid];
0169         if (pixmap.size() == size) {
0170             return pixmap;
0171         }
0172     }
0173 
0174     // Create new image
0175     QPixmap pixmap(size);
0176     pixmap.fill(Qt::transparent);
0177     QPainter p(&pixmap);
0178     mRenderer->render(&p, svgid);
0179     p.end();
0180     pixmap.setDevicePixelRatio(dpr);
0181     if (pixmap.isNull())
0182         qCCritical(KFOURINLINE_LOG) << "ThemeManager::getPixmap Cannot load svgid ID " << svgid;
0183 
0184     // Cache image
0185     mPixmapCache[svgid] = pixmap;
0186 
0187     return pixmap;
0188 }
0189 
0190 // Get the size when only width is given (this keeps the aspect ratio)
0191 QSize ThemeManager::pixmapSize(const QString &svgid, double width) const
0192 {
0193     QRectF rect = mRenderer->boundsOnElement(svgid);
0194     double factor = width / rect.width();
0195     return QSize(int(width), int(rect.height() * factor));
0196 }
0197 
0198 // Get the size with original properties and a scale factor given with respect to
0199 // another SVG item.
0200 QSize ThemeManager::pixmapSize(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     return QSize(int(rect.width() * factor), int(rect.height() * factor));
0206 }
0207 
0208 // ========================== Themeable interface ===============================
0209 
0210 // Constructs a themeable interface
0211 Themeable::Themeable()
0212 {
0213     mScale = 1.0;
0214     mThemeManager = nullptr;
0215 }
0216 
0217 // Constructs a themeable interface given its id and the master theme manager.
0218 // This automatically registers the object with the manager.
0219 Themeable::Themeable(const QString &id, ThemeManager *thememanager)
0220 {
0221     mScale = 1.0;
0222     mId = id;
0223     mThemeManager = thememanager;
0224     if (!thememanager)
0225         return;
0226     thememanager->registerTheme(this);
0227 }
0228 
0229 // Destructs the themeable object
0230 Themeable::~Themeable()
0231 {
0232     if (mThemeManager)
0233         mThemeManager->unregisterTheme(this);
0234 }
0235 
0236 #include "moc_thememanager.cpp"