2 Copyright (C) 1997 Mathias Mueller <in5y158@public.uni-hamburg.de>
3 Copyright (C) 2006 Mauricio Piacentini <mauricio@tabuleiro.com>
5 Libkmahjongg is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "kmahjonggtileset.h"
24 #include <kconfiggroup.h>
26 #include <kstandarddirs.h>
27 #include <ksvgrenderer.h>
29 #include <QPixmapCache>
36 class KMahjonggTilesetMetricsData
39 short lvloffx
; // used for 3D indentation, x value
40 short lvloffy
; // used for 3D indentation, y value
41 short w
; // tile width ( +border +shadow)
42 short h
; // tile height ( +border +shadow)
43 short fw
; // face width
44 short fh
; // face height
46 KMahjonggTilesetMetricsData()
47 : lvloffx(0), lvloffy(0), w(0), h(0), fw(0), fh(0)
51 class KMahjonggTilesetPrivate
54 KMahjonggTilesetPrivate() : isSVG(false), graphicsLoaded(false) {}
55 QList
<QString
> elementIdTable
;
56 QMap
<QString
, QString
> authorproperties
;
58 KMahjonggTilesetMetricsData originaldata
;
59 KMahjonggTilesetMetricsData scaleddata
;
60 QString filename
; // cache the last file loaded to save reloading it
68 // ---------------------------------------------------------
70 KMahjonggTileset::KMahjonggTileset()
71 : d(new KMahjonggTilesetPrivate
)
73 buildElementIdTable();
75 static bool _inited
= false;
78 KGlobal::dirs()->addResourceType("kmahjonggtileset", "data", QString::fromLatin1("kmahjongglib/tilesets/"));
80 KGlobal::locale()->insertCatalog("libkmahjongglib");
84 // ---------------------------------------------------------
86 KMahjonggTileset::~KMahjonggTileset() {
90 void KMahjonggTileset::updateScaleInfo(short tilew
, short tileh
)
92 d
->scaleddata
.w
= tilew
;
93 d
->scaleddata
.h
= tileh
;
94 double ratio
= ((qreal
) d
->scaleddata
.w
) / ((qreal
) d
->originaldata
.w
);
95 d
->scaleddata
.lvloffx
= (short) (d
->originaldata
.lvloffx
* ratio
);
96 d
->scaleddata
.lvloffy
= (short) (d
->originaldata
.lvloffy
* ratio
);
97 d
->scaleddata
.fw
= (short) (d
->originaldata
.fw
* ratio
);
98 d
->scaleddata
.fh
= (short) (d
->originaldata
.fh
* ratio
);
101 QSize
KMahjonggTileset::preferredTileSize(const QSize
& boardsize
, int horizontalCells
, int verticalCells
)
103 //calculate our best tile size to fit the boardsize passed to us
104 qreal newtilew
, newtileh
, aspectratio
;
105 qreal bw
= boardsize
.width();
106 qreal bh
= boardsize
.height();
108 //use tileface for calculation, with one complete tile in the sum for extra margin
109 qreal fullh
= (d
->originaldata
.fh
* verticalCells
) + d
->originaldata
.h
;
110 qreal fullw
= (d
->originaldata
.fw
* horizontalCells
) + d
->originaldata
.w
;
111 qreal floatw
= d
->originaldata
.w
;
112 qreal floath
= d
->originaldata
.h
;
114 if ((fullw
/fullh
)>(bw
/bh
)) {
115 //space will be left on height, use width as limit
116 aspectratio
= bw
/fullw
;
118 aspectratio
= bh
/fullh
;
120 newtilew
= aspectratio
* floatw
;
121 newtileh
= aspectratio
* floath
;
122 return QSize((short)newtilew
, (short)newtileh
);
125 bool KMahjonggTileset::loadDefault()
127 QString idx
= "default.desktop";
129 QString tilesetPath
= KStandardDirs::locate("kmahjonggtileset", idx
);
130 kDebug() << "Inside LoadDefault(), located path at" << tilesetPath
;
131 if (tilesetPath
.isEmpty()) {
134 return loadTileset(tilesetPath
);
137 QString
KMahjonggTileset::authorProperty(const QString
&key
) const
139 return d
->authorproperties
[key
];
142 short KMahjonggTileset::width() const
144 return d
->scaleddata
.w
;
147 short KMahjonggTileset::height() const
149 return d
->scaleddata
.h
;
152 short KMahjonggTileset::levelOffsetX() const
154 return d
->scaleddata
.lvloffx
;
157 short KMahjonggTileset::levelOffsetY() const
159 return d
->scaleddata
.lvloffy
;
163 short KMahjonggTileset::qWidth() const
165 return (short) (d
->scaleddata
.fw
/ 2.0);
168 short KMahjonggTileset::qHeight() const
170 return (short) (d
->scaleddata
.fh
/ 2.0);
173 QString
KMahjonggTileset::path() const
178 #define kTilesetVersionFormat 1
180 // ---------------------------------------------------------
181 bool KMahjonggTileset::loadTileset( const QString
& tilesetPath
)
185 kDebug() << "Attempting to load .desktop at" << tilesetPath
;
187 //clear our properties map
188 d
->authorproperties
.clear();
190 // verify if it is a valid file first and if we can open it
191 QFile
tilesetfile(tilesetPath
);
192 if (!tilesetfile
.open(QIODevice::ReadOnly
)) {
197 KConfig
tileconfig(tilesetPath
, KConfig::SimpleConfig
);
198 KConfigGroup group
= tileconfig
.group("KMahjonggTileset");
200 d
->authorproperties
.insert("Name", group
.readEntry("Name"));// Returns translated data
201 d
->authorproperties
.insert("Author", group
.readEntry("Author"));
202 d
->authorproperties
.insert("Description", group
.readEntry("Description"));
203 d
->authorproperties
.insert("AuthorEmail", group
.readEntry("AuthorEmail"));
206 int tileversion
= group
.readEntry("VersionFormat",0);
207 //Format is increased when we have incompatible changes, meaning that older clients are not able to use the remaining information safely
208 if (tileversion
> kTilesetVersionFormat
) {
212 QString graphName
= group
.readEntry("FileName");
214 d
->graphicspath
= KStandardDirs::locate("kmahjonggtileset", graphName
);
215 kDebug() << "Using tileset at" << d
->graphicspath
;
216 //d->filename = graphicsPath;
220 if (d
->graphicspath
.isEmpty()) return (false);
222 d
->originaldata
.w
= group
.readEntry("TileWidth", 30);
223 d
->originaldata
.h
= group
.readEntry("TileHeight", 50);
224 d
->originaldata
.fw
= group
.readEntry("TileFaceWidth", 30);
225 d
->originaldata
.fh
= group
.readEntry("TileFaceHeight", 50);
226 d
->originaldata
.lvloffx
= group
.readEntry("LevelOffsetX", 10);
227 d
->originaldata
.lvloffy
= group
.readEntry("LevelOffsetY", 10);
229 //client application needs to call loadGraphics()
230 d
->graphicsLoaded
= false;
231 d
->filename
= tilesetPath
;
235 d->svg.load(graphicsPath);
236 if (d->svg.isValid()) {
237 d->filename = tilesetPath;
238 //invalidate our global cache
239 QPixmapCache::clear();
242 reloadTileset(QSize(d->originaldata.w, d->originaldata.h));
247 //TODO add support for png??
254 // ---------------------------------------------------------
255 bool KMahjonggTileset::loadGraphics()
257 if (d
->graphicsLoaded
== true) return (true) ;
260 d
->svg
.load(d
->graphicspath
);
261 if (d
->svg
.isValid()) {
262 //invalidate our global cache
263 QPixmapCache::clear();
264 d
->graphicsLoaded
= true;
265 reloadTileset(QSize(d
->originaldata
.w
, d
->originaldata
.h
));
270 //TODO add support for png??
277 // ---------------------------------------------------------
278 bool KMahjonggTileset::reloadTileset( const QSize
& newTilesize
)
280 QString tilesetPath
= d
->filename
;
282 if (QSize(d
->scaleddata
.w
, d
->scaleddata
.h
) == newTilesize
) return false;
285 if (d
->svg
.isValid()) {
286 updateScaleInfo(newTilesize
.width(), newTilesize
.height());
287 //rendering will be done when needed, automatically using the global cache
292 //TODO add support for png???
299 void KMahjonggTileset::buildElementIdTable() {
300 //Build a list for faster lookup of element ids, mapped to the enumeration used by GameData and BoardWidget
302 for (short idx
=1; idx
<=4; idx
++) {
303 d
->elementIdTable
.append(QString("TILE_%1").arg(idx
));
306 for (short idx
=1; idx
<=4; idx
++) {
307 d
->elementIdTable
.append(QString("TILE_%1_SEL").arg(idx
));
310 for (short idx
=1; idx
<=9; idx
++) {
311 d
->elementIdTable
.append(QString("CHARACTER_%1").arg(idx
));
313 for (short idx
=1; idx
<=9; idx
++) {
314 d
->elementIdTable
.append(QString("BAMBOO_%1").arg(idx
));
316 for (short idx
=1; idx
<=9; idx
++) {
317 d
->elementIdTable
.append(QString("ROD_%1").arg(idx
));
319 for (short idx
=1; idx
<=4; idx
++) {
320 d
->elementIdTable
.append(QString("SEASON_%1").arg(idx
));
322 for (short idx
=1; idx
<=4; idx
++) {
323 d
->elementIdTable
.append(QString("WIND_%1").arg(idx
));
325 for (short idx
=1; idx
<=3; idx
++) {
326 d
->elementIdTable
.append(QString("DRAGON_%1").arg(idx
));
328 for (short idx
=1; idx
<=4; idx
++) {
329 d
->elementIdTable
.append(QString("FLOWER_%1").arg(idx
));
333 QString
KMahjonggTileset::pixmapCacheNameFromElementId(const QString
& elementid
) {
334 return authorProperty("Name")+ elementid
+ QString("W%1H%2").arg(d
->scaleddata
.w
).arg(d
->scaleddata
.h
);
337 QPixmap
KMahjonggTileset::renderElement(short width
, short height
, const QString
& elementid
) {
338 //kDebug() << "render element" << elementid << width << height;
339 QImage
qiRend(QSize(width
, height
),QImage::Format_ARGB32_Premultiplied
);
342 if (d
->svg
.isValid()) {
344 d
->svg
.render(&p
, elementid
);
346 return QPixmap::fromImage(qiRend
);
349 QPixmap
KMahjonggTileset::selectedTile(int num
) {
351 QString elemId
= d
->elementIdTable
.at(num
+4);//selected offset in our idtable;
352 if (!QPixmapCache::find(pixmapCacheNameFromElementId(elemId
), pm
)) {
354 pm
= renderElement(d
->scaleddata
.w
, d
->scaleddata
.h
, elemId
);
355 QPixmapCache::insert(pixmapCacheNameFromElementId(elemId
), pm
);
360 QPixmap
KMahjonggTileset::unselectedTile(int num
) {
362 QString elemId
= d
->elementIdTable
.at(num
);
363 if (!QPixmapCache::find(pixmapCacheNameFromElementId(elemId
), pm
)) {
365 pm
= renderElement(d
->scaleddata
.w
, d
->scaleddata
.h
, elemId
);
366 QPixmapCache::insert(pixmapCacheNameFromElementId(elemId
), pm
);
371 QPixmap
KMahjonggTileset::tileface(int num
) {
373 if ((num
+ 8) >= d
->elementIdTable
.count()) {
374 kDebug() << "Client asked for invalid tileface id";
378 QString elemId
= d
->elementIdTable
.at(num
+ 8);//tileface offset in our idtable;
379 if (!QPixmapCache::find(pixmapCacheNameFromElementId(elemId
), pm
)) {
381 pm
= renderElement(d
->scaleddata
.fw
, d
->scaleddata
.fh
, elemId
);
382 QPixmapCache::insert(pixmapCacheNameFromElementId(elemId
), pm
);