File indexing completed on 2023-10-01 08:05:26
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 // General includes 0009 // #include <typeinfo> 0010 0011 // Own include 0012 #include "thememanager.h" 0013 0014 // Qt includes 0015 #include <QImage> 0016 #include <QPixmap> 0017 #include <QPainter> 0018 #include <QRectF> 0019 0020 // KF includes 0021 #include <KConfigGroup> 0022 0023 // Local includes 0024 #include "lskat_debug.h" 0025 #include "lskatglobal.h" 0026 #include "deck.h" 0027 #include "fromlibkdegames/cardcache.h" 0028 0029 // SVG id for accessing the backside of a card 0030 #define CARDBACK_SVGID "back" 0031 0032 //convenience methods for converting to KCardInfo enums 0033 KCardInfo convertToKCardInfo(CardDeck::Suite suite, CardDeck::CardType card) 0034 { 0035 KCardInfo::Suit s; 0036 KCardInfo::Card c; 0037 switch(card) 0038 { 0039 case CardDeck::Ace: 0040 c = KCardInfo::Ace; 0041 break; 0042 case CardDeck::Eight: 0043 c = KCardInfo::Eight; 0044 break; 0045 case CardDeck::King: 0046 c = KCardInfo::King; 0047 break; 0048 case CardDeck::Nine: 0049 c = KCardInfo::Nine; 0050 break; 0051 case CardDeck::Ten: 0052 c = KCardInfo::Ten; 0053 break; 0054 case CardDeck::Jack: 0055 c = KCardInfo::Jack; 0056 break; 0057 case CardDeck::Seven: 0058 c = KCardInfo::Seven; 0059 break; 0060 case CardDeck::Queen: 0061 c = KCardInfo::Queen; 0062 break; 0063 } 0064 switch(suite) 0065 { 0066 case CardDeck::Heart: 0067 s = KCardInfo::Heart; 0068 break; 0069 case CardDeck::Club: 0070 s = KCardInfo::Club; 0071 break; 0072 case CardDeck::Diamond: 0073 s = KCardInfo::Diamond; 0074 break; 0075 case CardDeck::Spade: 0076 s = KCardInfo::Spade; 0077 break; 0078 default: 0079 s = KCardInfo::None; 0080 break; 0081 } 0082 return KCardInfo(s, c); 0083 } 0084 0085 // Constructor for the theme manager 0086 ThemeManager::ThemeManager(const QString &cardTheme, 0087 const QString &themefile, QObject *parent, int initialSize) 0088 : QObject(parent), mRenderer(nullptr), mConfig(nullptr), mCardTheme(cardTheme), 0089 mScale(initialSize), mAspectRatio(1.0), mCardAspectRatio(1.0) 0090 { 0091 mCardCache = new KCardCache(); 0092 0093 // updateTheme(themefile); 0094 updateCardTheme(themefile, cardTheme); 0095 } 0096 0097 ThemeManager::~ThemeManager() 0098 { 0099 delete mConfig; 0100 delete mCardCache; 0101 } 0102 0103 // Register an object with the manager 0104 void ThemeManager::registerTheme(Themable *ob) 0105 { 0106 mObjects[ob] = 1; 0107 } 0108 0109 // Unregister an object from the manager 0110 void ThemeManager::unregisterTheme(Themable *ob) 0111 { 0112 mObjects.remove(ob); 0113 } 0114 0115 // Check whether the theme is alright 0116 int ThemeManager::checkTheme() 0117 { 0118 // Check theme 0119 if (mRenderer == nullptr) return 1; 0120 return 0; // OK 0121 } 0122 0123 // Force an refresh of the theme object given 0124 void ThemeManager::updateTheme(Themable *ob) 0125 { 0126 ob->changeTheme(); 0127 } 0128 0129 // Update card deck and card set 0130 void ThemeManager::updateCardTheme(const QString &cardTheme) 0131 { 0132 updateCardTheme(mThemeFile, cardTheme); 0133 } 0134 0135 // Update card deck and card set 0136 void ThemeManager::updateCardTheme(const QString &themefile, const QString &cardTheme) 0137 { 0138 if (global_debug > 1) 0139 { 0140 qCDebug(LSKAT_LOG) << "ThemeManager Pixmap cards: "; 0141 qCDebug(LSKAT_LOG) << " Card theme =" << cardTheme; 0142 } 0143 0144 // Cards 0145 mCardTheme = cardTheme; 0146 mCardCache->setDeckName(mCardTheme); 0147 0148 mCardCache->setSize(QSize()); 0149 0150 updateTheme(themefile); 0151 } 0152 0153 // Update the theme file and refresh all registered objects. Used 0154 // to really change the theme. 0155 void ThemeManager::updateTheme(const QString &themefile) 0156 { 0157 // Empty cache 0158 mPixmapCache.clear(); 0159 mThemeFile = themefile; 0160 0161 // Process dirs 0162 QString rcfile = QStandardPaths::locate(QStandardPaths::AppDataLocation, "grafix/" + themefile); 0163 if (global_debug > 0) qCDebug(LSKAT_LOG) << "ThemeManager LOAD with theme " << rcfile; 0164 0165 // Read config and SVG file for theme 0166 delete mConfig; 0167 mConfig = new KConfig(rcfile, KConfig::NoGlobals); 0168 QString svgfile = config(QStringLiteral("general")).readEntry("svgfile"); 0169 svgfile = QStandardPaths::locate(QStandardPaths::AppDataLocation, "grafix/" + svgfile); 0170 if (global_debug > 0) qCDebug(LSKAT_LOG) << "Reading SVG master file =" << svgfile; 0171 0172 mAspectRatio = config(QStringLiteral("general")).readEntry("aspect-ratio", 1.0); 0173 mCardAspectRatio = config(QStringLiteral("general")).readEntry("card-aspect-ratio", 1.0); 0174 if (global_debug > 0) qCDebug(LSKAT_LOG) << "Aspect ration =" << mAspectRatio << "Cards aspect=" << mCardAspectRatio; 0175 0176 delete mRenderer; 0177 mRenderer = new QSvgRenderer(this); 0178 bool result = mRenderer->load(svgfile); 0179 if (!result) 0180 { 0181 mRenderer = nullptr; 0182 qCCritical(LSKAT_LOG) << "Cannot open file" << svgfile; 0183 } 0184 0185 // Notify all theme objects of a change 0186 QHashIterator<Themable *, int> it(mObjects); 0187 while (it.hasNext()) 0188 { 0189 it.next(); 0190 Themable *ob = it.key(); 0191 ob->changeTheme(); 0192 } 0193 } 0194 0195 // Rescale the theme. Call all registered objects so that they can refresh. 0196 void ThemeManager::rescale(int scale, QPoint offset) 0197 { 0198 if (global_debug > 1) 0199 { 0200 if (scale == mScale) 0201 qCDebug(LSKAT_LOG) << "No scale change to" << scale << "If this happens too often it is BAD"; 0202 } 0203 //if (scale == mScale) return; 0204 mScale = scale; 0205 mOffset = offset; 0206 if (global_debug > 1) qCDebug(LSKAT_LOG) << "THEMEMANAGER:: Rescale to " << scale << " offset to " << offset; 0207 0208 QHashIterator<Themable *, int> it(mObjects); 0209 while (it.hasNext()) 0210 { 0211 it.next(); 0212 Themable *ob = it.key(); 0213 ob->changeTheme(); 0214 } 0215 } 0216 0217 // Retrieve the theme's scale 0218 double ThemeManager::getScale() 0219 { 0220 return (double)mScale; 0221 } 0222 0223 // Retrieve the theme offset 0224 QPoint ThemeManager::getOffset() 0225 { 0226 return mOffset; 0227 } 0228 0229 // Retrieve the current theme configuration file. 0230 KConfigGroup ThemeManager::config(const QString &id) 0231 { 0232 KConfigGroup grp = mConfig->group(id); 0233 return grp; 0234 } 0235 0236 // Get the pixmap for a card , given suite, type and the desired card width in pixel 0237 const QPixmap ThemeManager::getCard(int suite, int cardtype, double width) 0238 { 0239 KCardInfo info = convertToKCardInfo(CardDeck::Suite(suite), CardDeck::CardType(cardtype)); 0240 QSize s(int(width), int(width / mCardAspectRatio)); 0241 0242 if (s != mCardCache->size()) 0243 { 0244 mCardCache->setSize(s); 0245 QMetaObject::invokeMethod(this, "loadCardsInBackground", Qt::QueuedConnection); 0246 } 0247 0248 QPixmap pix = mCardCache->frontside(info); 0249 return pix; 0250 } 0251 0252 // Get the pixmap for a card back, given the desired card width in pixel 0253 const QPixmap ThemeManager::getCardback(double width) 0254 { 0255 QSize s(int(width), int(width / mCardAspectRatio)); 0256 if (s != mCardCache->size()) 0257 { 0258 mCardCache->setSize(s); 0259 QMetaObject::invokeMethod(this, "loadCardsInBackground", Qt::QueuedConnection); 0260 } 0261 0262 QPixmap pix = mCardCache->backside(); 0263 return pix; 0264 } 0265 0266 // Get a pixmap when its size is given (this can distort the image) 0267 const QPixmap ThemeManager::getPixmap(QSvgRenderer *renderer, const QString &svgid, const QSize &size) 0268 { 0269 QPixmap pixmap; 0270 if (size.width() < 1 || size.height() < 1) 0271 { 0272 if (global_debug > 1) 0273 qCDebug(LSKAT_LOG) << "ThemeManager::getPixmap Cannot create svgid ID " << svgid << " with zero size" << size; 0274 return pixmap; 0275 } 0276 0277 // Cached pixmap? 0278 if (mPixmapCache.contains(svgid)) 0279 { 0280 pixmap = mPixmapCache[svgid]; 0281 if (pixmap.size() == size) 0282 { 0283 return pixmap; 0284 } 0285 } 0286 0287 // Create new image 0288 QImage image(size, QImage::Format_ARGB32_Premultiplied); 0289 image.fill(0); 0290 QPainter p(&image); 0291 renderer->render(&p, svgid); 0292 p.end(); 0293 pixmap = QPixmap::fromImage(image); 0294 if (pixmap.isNull()) 0295 qCCritical(LSKAT_LOG) << "ThemeManager::getPixmap Cannot load svgid ID " << svgid; 0296 0297 // Cache image 0298 mPixmapCache[svgid] = pixmap; 0299 0300 return pixmap; 0301 } 0302 0303 // Get a pixmap when its size is given (this can distort the image) 0304 const QPixmap ThemeManager::getPixmap(const QString &svgid, const QSize &size) 0305 { 0306 return getPixmap(mRenderer, svgid, size); 0307 } 0308 0309 // Get a pixmap when only width is given (this keeps the aspect ratio) 0310 const QPixmap ThemeManager::getPixmap(const QString &svgid, double width) 0311 { 0312 QRectF rect = mRenderer->boundsOnElement(svgid); 0313 double factor = width / rect.width(); 0314 QSize size = QSize(int(width), int(rect.height() * factor)); 0315 return getPixmap(svgid, size); 0316 } 0317 0318 // Get a pixmap with original properties and a scale factor given with respect to 0319 // another SVG item. 0320 const QPixmap ThemeManager::getPixmap(const QString &svgid, const QString &svgref, double refwidth) 0321 { 0322 QRectF refrect = mRenderer->boundsOnElement(svgref); 0323 QRectF rect = mRenderer->boundsOnElement(svgid); 0324 double factor = refwidth / refrect.width(); 0325 QSize size = QSize(int(rect.width() * factor), int(rect.height() * factor)); 0326 return getPixmap(svgid, size); 0327 } 0328 0329 void ThemeManager::loadCardsInBackground() 0330 { 0331 mCardCache->loadTheme(KCardCache::LoadFrontSide|KCardCache::Load32Cards); 0332 } 0333 0334 // ========================== Themable interface =============================== 0335 0336 // Constructs a themable interface 0337 Themable::Themable() 0338 { 0339 mScale = 1.0; 0340 mThemeManager = nullptr; 0341 } 0342 0343 // Constructs a themable interface given its id and the master theme manager. 0344 // This automatically registers the object with the manager. 0345 Themable::Themable(const QString &id, ThemeManager *thememanager) 0346 { 0347 mScale = 1.0; 0348 mId = id; 0349 mThemeManager = thememanager; 0350 if (!thememanager) return; 0351 thememanager->registerTheme(this); 0352 } 0353 0354 // Destructs the themable object 0355 Themable::~Themable() 0356 { 0357 if (mThemeManager) mThemeManager->unregisterTheme(this); 0358 } 0359 0360 #include "moc_thememanager.cpp"