File indexing completed on 2024-12-15 03:48:05

0001 /*
0002     SPDX-FileCopyrightText: 2008 Sascha Peilicke <sasch.pe@gmx.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "themerenderer.h"
0008 #include "preferences.h"
0009 
0010 #include <KGameThemeProvider>
0011 
0012 #include <QSvgRenderer>
0013 #include <QPixmapCache>
0014 #include <QPixmap>
0015 #include <QPainter>
0016 
0017 namespace Kigo {
0018 
0019 ThemeRenderer::ThemeRenderer()
0020     : m_themeProvider(new KGameThemeProvider(QByteArray(), this)) // empty config key to disable internal config storage
0021     , m_renderer(new QSvgRenderer)
0022 {
0023     QPixmapCache::setCacheLimit(3 * 1024);
0024     m_themeProvider->discoverThemes(
0025         QStringLiteral("themes"), // theme file location
0026         QStringLiteral("default") // default theme file name
0027     );
0028     const QByteArray themeIdentifier = Preferences::theme().toUtf8();
0029     KGameThemeProvider *provider = themeProvider();
0030     const QList<const KGameTheme *> themes = provider->themes();
0031     for (auto* theme : themes) {
0032         if (theme->identifier() == themeIdentifier) {
0033             provider->setCurrentTheme(theme);
0034             break;
0035         }
0036     }
0037     loadTheme(provider->currentTheme());
0038     connect(m_themeProvider, &KGameThemeProvider::currentThemeChanged,
0039             this, &ThemeRenderer::loadTheme);
0040 }
0041 
0042 ThemeRenderer::~ThemeRenderer()
0043 {
0044     delete m_renderer;
0045 }
0046 
0047 KGameThemeProvider *ThemeRenderer::themeProvider() const
0048 {
0049     return m_themeProvider;
0050 }
0051 
0052 void ThemeRenderer::loadTheme(const KGameTheme *theme)
0053 {
0054     //qCDebug(KIGO_LOG) << "Loading" << theme.graphics();
0055     if (!m_renderer->load(theme->graphicsPath())) {
0056         return;
0057     }
0058 
0059     Preferences::setTheme(QString::fromUtf8(theme->identifier()));
0060     Preferences::self()->save();
0061 
0062     QPixmapCache::clear();
0063 
0064     Q_EMIT themeChanged();
0065 }
0066 
0067 void ThemeRenderer::renderElement(Element element, QPainter *painter, const QRectF &rect) const
0068 {
0069     if (!m_renderer->isValid() || rect.isEmpty() || painter == nullptr) {
0070         return;
0071     }
0072 
0073     const QPixmap pixmap = renderElement(element, rect.size().toSize());
0074 
0075     // Draw pixmap with the parameter provided painter
0076     painter->drawPixmap(static_cast<int>(rect.x()), static_cast<int>(rect.y()), pixmap);
0077 }
0078 
0079 QPixmap ThemeRenderer::renderElement(Element element, const QSize &size) const
0080 {
0081     if (!m_renderer->isValid() || size.isEmpty()) {
0082         return QPixmap();
0083     }
0084 
0085     // Determine which board element we have to render and set the cache item name
0086     QString cacheName;
0087     switch (element) {
0088         case Element::Background:
0089             cacheName = QStringLiteral("background_%1x%2").arg(size.width()).arg(size.height());
0090             break;
0091         case Element::Board:
0092             cacheName = QStringLiteral("board_%1x%2").arg(size.width()).arg(size.height());
0093             break;
0094         case Element::HandicapMark:
0095             cacheName = QStringLiteral("handicap_mark_%1x%2").arg(size.width()).arg(size.height());
0096             break;
0097         case Element::WhiteStone:
0098             cacheName = QStringLiteral("white_stone_%1x%2").arg(size.width()).arg(size.height());
0099             break;
0100         case Element::WhiteStoneLast:
0101             cacheName = QStringLiteral("white_stone_last_%1x%2").arg(size.width()).arg(size.height());
0102             break;
0103         case Element::WhiteStoneTransparent:
0104             cacheName = QStringLiteral("white_stone_%1x%2_trans").arg(size.width()).arg(size.height());
0105             break;
0106         case Element::WhiteTerritory:
0107             cacheName = QStringLiteral("white_territory_%1x%2").arg(size.width()).arg(size.height());
0108             break;
0109         case Element::BlackStone:
0110             cacheName = QStringLiteral("black_stone_%1x%2").arg(size.width()).arg(size.height());
0111             break;
0112         case Element::BlackStoneLast:
0113             cacheName = QStringLiteral("black_stone_last_%1x%2").arg(size.width()).arg(size.height());
0114             break;
0115         case Element::BlackStoneTransparent:
0116             cacheName = QStringLiteral("black_stone_%1x%2_trans").arg(size.width()).arg(size.height());
0117             break;
0118         case Element::BlackTerritory:
0119             cacheName = QStringLiteral("black_territory_%1x%2").arg(size.width()).arg(size.height());
0120             break;
0121         case Element::PlacementMarker:
0122             cacheName = QStringLiteral("placement_marker_%1x%2").arg(size.width()).arg(size.height());
0123             break;
0124     }
0125 
0126     // Check if board element is already in cache, if not render it
0127     QPixmap pixmap;
0128     if (!QPixmapCache::find(cacheName, &pixmap)) {
0129         pixmap = QPixmap(size);
0130         pixmap.fill(Qt::transparent);
0131         QPainter p(&pixmap);
0132         switch (element) {
0133             case Element::Background:
0134                 m_renderer->render(&p, QStringLiteral("background"));
0135                 break;
0136             case Element::Board:
0137                 m_renderer->render(&p, QStringLiteral("board"));
0138                 break;
0139             case Element::HandicapMark:
0140                 m_renderer->render(&p, QStringLiteral("handicap_mark"));
0141                 break;
0142             case Element::WhiteStone:
0143                 m_renderer->render(&p, QStringLiteral("white_stone"));
0144                 break;
0145             case Element::WhiteStoneLast:
0146                 m_renderer->render(&p, QStringLiteral("white_stone_last"));
0147                 break;
0148             case Element::WhiteStoneTransparent:
0149                 p.setOpacity(0.5);
0150                 m_renderer->render(&p, QStringLiteral("white_stone"));
0151                 break;
0152             case Element::WhiteTerritory:
0153                 m_renderer->render(&p, QStringLiteral("white_territory"));
0154                 break;
0155             case Element::BlackStone:
0156                 m_renderer->render(&p, QStringLiteral("black_stone"));
0157                 break;
0158             case Element::BlackStoneLast:
0159                 m_renderer->render(&p, QStringLiteral("black_stone_last"));
0160                 break;
0161             case Element::BlackStoneTransparent:
0162                 p.setOpacity(0.5);
0163                 m_renderer->render(&p, QStringLiteral("black_stone"));
0164                 break;
0165             case Element::BlackTerritory:
0166                 m_renderer->render(&p, QStringLiteral("black_territory"));
0167                 break;
0168             case Element::PlacementMarker:
0169                 m_renderer->render(&p, QStringLiteral("placement_marker"));
0170                 break;
0171         }
0172         QPixmapCache::insert(cacheName, pixmap);
0173     }
0174     return pixmap;
0175 }
0176 
0177 QSize ThemeRenderer::elementSize(Element element) const
0178 {
0179     QRectF sizeRect;
0180     switch(element) {
0181         case Element::Background:
0182             sizeRect = m_renderer->boundsOnElement(QStringLiteral("background"));
0183             break;
0184         case Element::Board:
0185             sizeRect = m_renderer->boundsOnElement(QStringLiteral("board"));
0186             break;
0187         case Element::HandicapMark:
0188             sizeRect = m_renderer->boundsOnElement(QStringLiteral("handicap_mark"));
0189             break;
0190         case Element::WhiteStone:
0191             sizeRect = m_renderer->boundsOnElement(QStringLiteral("white_stone"));
0192             break;
0193         case Element::WhiteStoneLast:
0194             sizeRect = m_renderer->boundsOnElement(QStringLiteral("white_stone"));
0195             break;
0196         case Element::WhiteStoneTransparent:
0197             sizeRect = m_renderer->boundsOnElement(QStringLiteral("white_stone"));
0198             break;
0199         case Element::WhiteTerritory:
0200             sizeRect = m_renderer->boundsOnElement(QStringLiteral("white_territory"));
0201             break;
0202         case Element::BlackStone:
0203             sizeRect = m_renderer->boundsOnElement(QStringLiteral("black_stone"));
0204             break;
0205         case Element::BlackStoneLast:
0206             sizeRect = m_renderer->boundsOnElement(QStringLiteral("black_stone"));
0207             break;
0208         case Element::BlackStoneTransparent:
0209             sizeRect = m_renderer->boundsOnElement(QStringLiteral("black_stone"));
0210             break;
0211         case Element::BlackTerritory:
0212             sizeRect = m_renderer->boundsOnElement(QStringLiteral("black_territory"));
0213             break;
0214         case Element::PlacementMarker:
0215             sizeRect = m_renderer->boundsOnElement(QStringLiteral("placement_marker"));
0216             break;
0217     }
0218     return QSize(static_cast<int>(sizeRect.width()), static_cast<int>(sizeRect.height()));
0219 }
0220 
0221 } // End of namespace Kigo
0222 
0223 #include "moc_themerenderer.cpp"