2 * Copyright 2007-2009 Parker Coates <parker.coates@gmail.com>
4 * This file is part of Killbots.
6 * Killbots is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * Killbots is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Killbots. If not, see <http://www.gnu.org/licenses/>.
22 #include <kgamesvgdocument.h>
23 #include <kgametheme.h>
26 #include <KDE/KGlobal>
27 #include <KDE/KPixmapCache>
28 #include <KDE/KSvgRenderer>
30 #include <QtCore/QDateTime>
31 #include <QtCore/QFileInfo>
32 #include <QtCore/QHash>
33 #include <QtGui/QColor>
34 #include <QtGui/QCursor>
35 #include <QtGui/QPainter>
45 m_pixmapCache("killbots-cache"),
47 m_hasBeenLoaded( false )
50 KSvgRenderer m_svgRenderer
;
51 KPixmapCache m_pixmapCache
;
52 QHash
<int,QCursor
> m_cursors
;
60 K_GLOBAL_STATIC( Killbots::RenderPrivate
, rp
)
65 bool Killbots::Render::loadTheme( const QString
& fileName
)
70 if ( newTheme
.load( fileName
) )
72 const QDateTime cacheTimeStamp
= QDateTime::fromTime_t( rp
->m_pixmapCache
.timestamp() );
73 const QDateTime desktopFileTimeStamp
= QFileInfo( newTheme
.path() ).lastModified();
74 const QDateTime svgFileTimeStamp
= QFileInfo( newTheme
.graphics() ).lastModified();
76 // We check to see if the cache contains a key matching the path to the
79 const bool isNotInCache
= !rp
->m_pixmapCache
.find( newTheme
.path(), nullPixmap
);
81 kDebug() << "Theme is not already in cache.";
83 const bool desktopFileIsNewer
= desktopFileTimeStamp
> cacheTimeStamp
;
84 if ( desktopFileIsNewer
)
86 kDebug() << "Desktop file is newer than cache.";
87 kDebug() << "Cache timestamp is" << cacheTimeStamp
.toString( Qt::ISODate
);
88 kDebug() << "Desktop file timestamp is" << desktopFileTimeStamp
.toString( Qt::ISODate
);
91 const bool svgFileIsNewer
= svgFileTimeStamp
> cacheTimeStamp
;
94 kDebug() << "SVG file is newer than cache.";
95 kDebug() << "Cache timestamp is" << cacheTimeStamp
.toString( Qt::ISODate
);
96 kDebug() << "SVG file timestamp is" << svgFileTimeStamp
.toString( Qt::ISODate
);
99 // Discard the cache if the loaded theme doesn't match the one already
100 // in the cache, or if either of the theme files have been updated
101 // since the cache was created.
102 const bool discardCache
= isNotInCache
|| svgFileIsNewer
|| desktopFileIsNewer
;
104 // Only bother actually loading the SVG if no SVG has been loaded
105 // yet or if the cache must be discarded.
106 if ( !rp
->m_hasBeenLoaded
|| discardCache
)
110 kDebug() << "Discarding cache.";
111 rp
->m_pixmapCache
.discard();
112 rp
->m_pixmapCache
.setTimestamp( QDateTime::currentDateTime().toTime_t() );
114 // We store a null pixmap in the cache with the new theme's
115 // file path as the key. This allows us to keep track of the
116 // theme that is stored in the disk cache between runs.
117 rp
->m_pixmapCache
.insert( newTheme
.path(), nullPixmap
);
120 result
= rp
->m_hasBeenLoaded
= rp
->m_svgRenderer
.load( newTheme
.graphics() );
122 // Get the theme's aspect ratio from the .desktop file.
123 const QRectF tileRect
= rp
->m_svgRenderer
.boundsOnElement("cell");
124 rp
->m_aspectRatio
= tileRect
.width() / tileRect
.height();
125 rp
->m_aspectRatio
= qBound( 0.3333, rp
->m_aspectRatio
, 3.0 );
127 // Get the theme's text color. Use the fill color of the "text" SVG element.
128 // If it exists doesn't exist or the fill isn't a valid color, default to black.
129 KGameSvgDocument svg
;
130 svg
.load( newTheme
.graphics() );
131 if ( !svg
.elementById("text").isNull() )
132 rp
->m_textColor
= QColor( svg
.styleProperty("fill") );
133 if ( !rp
->m_textColor
.isValid() )
134 rp
->m_textColor
= Qt::black
;
137 for ( int i
= 0; i
<= 8; ++i
)
139 const QPixmap pixmap
= renderElement( QString("cursor%1").arg( i
), QSize( 42, 42 ) );
140 if ( !pixmap
.isNull() )
141 rp
->m_cursors
.insert( i
, QCursor( pixmap
) );
150 bool Killbots::Render::loadDefaultTheme()
152 return loadTheme("themes/default.desktop");
156 QPixmap
Killbots::Render::renderElement( const QString
& elementId
, QSize size
)
160 const QString key
= elementId
+ QString::number( size
.width() )
161 + 'x' + QString::number( size
.height() );
163 if ( !rp
->m_pixmapCache
.find( key
, result
) )
165 kDebug() << "Rendering \"" << elementId
<< "\" at " << size
<< " pixels.";
167 result
= QPixmap( size
);
168 result
.fill( Qt::transparent
);
170 QPainter
p( &result
);
171 rp
->m_svgRenderer
.render( &p
, elementId
);
174 rp
->m_pixmapCache
.insert( key
, result
);
181 QCursor
Killbots::Render::cursorFromAction( int direction
)
183 return rp
->m_cursors
.value( direction
, Qt::ArrowCursor
);
187 QColor
Killbots::Render::textColor()
189 return rp
->m_textColor
;
193 qreal
Killbots::Render::aspectRatio()
195 return rp
->m_aspectRatio
;