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"