thememanager.cpp

Go to the documentation of this file.
00001 /*
00002    This file is part of the KDE games lskat program
00003    Copyright (c) 2006 Martin Heni <kde@heni-online.de>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 // General includes
00022 // #include <typeinfo>
00023 
00024 // Qt includes
00025 #include <QImage>
00026 #include <QPixmap>
00027 #include <QPainter>
00028 #include <QColor>
00029 #include <QRectF>
00030 #include <QDir>
00031 
00032 // KDE includes
00033 #include <kdebug.h>
00034 #include <kstandarddirs.h>
00035 
00036 // Local includes
00037 #include "thememanager.h"
00038 #include "lskatglobal.h"
00039 #include "deck.h"
00040 
00041 
00042 // SVG id for accessing the backside of a card
00043 #define CARDBACK_SVGID "back"
00044 
00045 // Constructor for the theme manager
00046 ThemeManager::ThemeManager(QString cards, QString deck, QString themefile, QObject* parent, int initialSize)
00047     : QObject(parent)
00048 {
00049   mScale           = initialSize;
00050   mAspectRatio     = 1.0;
00051   mCardAspectRatio = 1.0;
00052   mCardFile        = cards;
00053   mDeckFile        = deck;
00054   mRenderer        = 0;
00055   mCardRenderer    = 0;
00056   mDeckRenderer    = 0;
00057 
00058   // updateTheme(themefile);
00059   updateCardTheme(themefile, cards, deck);
00060 }
00061 
00062 
00063 // Register an object with the manager
00064 void ThemeManager::registerTheme(Themable* ob)
00065 {
00066   mObjects[ob] = 1;
00067 }
00068 
00069 
00070 // Unregister an object from the manager
00071 void ThemeManager::unregisterTheme(Themable* ob)
00072 {
00073   mObjects.remove(ob);
00074 }
00075 
00076 
00077 // Force an refresh of the theme object given
00078 void ThemeManager::updateTheme(Themable* ob)
00079 {
00080   ob->changeTheme();
00081 }
00082 
00083 
00084 // Update a pixmap card deck 
00085 void ThemeManager::updateCardTheme(QString cards, QString deck)
00086 {
00087   updateCardTheme(mThemeFile, cards, deck);
00088 }
00089 void ThemeManager::updateCardTheme(QString themefile, QString cards, QString deck)
00090 {
00091   kDebug() << "ThemeManager Pixmap cards: "<< endl;
00092   kDebug() << "  Cards = " << cards << endl;
00093   kDebug() << "  Deck  = " << deck << endl;
00094 
00095   // Cards
00096   mCardFile = cards;
00097 
00098   KConfig cardInfo( cards+"/index.desktop", KConfig::OnlyLocal);
00099   KConfigGroup cardGroup(&cardInfo, "KDE Backdeck");
00100   QPointF cardSize   = cardGroup.readEntry("BackSize", QPointF(1.0,1.0));
00101   QString cardSVG    = cardGroup.readEntry("SVG", QString());
00102   kDebug() << "cardSize = " << cardSize << endl;
00103 
00104   kDebug() << "SVG card = " << cardSVG << " is " << (!cardSVG.isNull()) << endl;
00105 
00106   QString svgfile = cards+"/"+cardSVG;
00107 
00108   mCardRenderer = 0;
00109   if (!cardSVG.isNull())
00110   {
00111     mCardRenderer = new KSvgRenderer(this);
00112     bool result   = mCardRenderer->load(svgfile);
00113     if (!result) 
00114     {
00115       kFatal() << "Cannot open file " << svgfile << endl;
00116     }
00117     kDebug() << "Rendering " << svgfile << endl;
00118   }
00119 
00120 
00121   // Deck
00122   mDeckFile = deck;
00123   QString deckIndex = deck;
00124   deckIndex.replace(".png",".desktop");
00125 
00126   // Cards
00127   KConfig deckInfo( deckIndex, KConfig::OnlyLocal);
00128   KConfigGroup deckGroup(&deckInfo, "KDE Cards");
00129   QString deckSVG  = deckGroup.readEntry("SVG", QString());
00130 
00131   QString deckDir = deck;
00132   int pos = deck.lastIndexOf(QDir::separator());
00133   if (pos > 0) deckDir = deck.left(pos);
00134 
00135 
00136   svgfile = deckDir+"/"+deckSVG;
00137   kDebug() << "SVG deck = " << deckSVG << " is " << (!deckSVG.isNull()) << endl;
00138 
00139   mDeckRenderer = 0;
00140   if (!deckSVG.isNull())
00141   {
00142     mDeckRenderer = new KSvgRenderer(this);
00143     bool result   = mDeckRenderer->load(svgfile);
00144     if (!result) 
00145     {
00146       kFatal() << "Cannot open file " << svgfile << endl;
00147     }
00148     kDebug() << "Rendering " << svgfile << endl;
00149   }
00150 
00151 
00152   updateTheme(themefile);
00153 }
00154 
00155 
00156 // Update the theme file and refresh all registered objects. Used 
00157 // to really change the theme.
00158 void ThemeManager::updateTheme(QString themefile)
00159 {
00160   // Empty cache
00161   mPixmapCache.clear();
00162   mThemeFile = themefile;
00163 
00164   // Process dirs
00165   QString rcfile = KStandardDirs::locate("data", themefile);
00166   kDebug() << "ThemeManager LOAD with theme "<<rcfile << endl;
00167 
00168   // Read config and SVG file for theme
00169   mConfig = new KConfig(rcfile, KConfig::NoGlobals);
00170   QString svgfile = config("general").readEntry("svgfile");
00171   svgfile = KStandardDirs::locate("data", svgfile);
00172   kDebug() << "Reading SVG master file  = " << svgfile << endl;
00173 
00174   mAspectRatio     =  config("general").readEntry("aspect-ratio", 1.0);
00175   mCardAspectRatio =  config("general").readEntry("card-aspect-ratio", 1.0);
00176   kDebug() << "Aspect ration = " << mAspectRatio << " Cards aspect=" << mCardAspectRatio<< endl;
00177 
00178 
00179 
00180   mRenderer = new KSvgRenderer(this);
00181   bool result = mRenderer->load(svgfile);
00182   if (!result) 
00183   {
00184     kFatal() << "Cannot open file " << svgfile << endl;
00185   }
00186 
00187   // Notify all theme objects of a change
00188   QHashIterator<Themable*, int> it(mObjects);
00189   while (it.hasNext())
00190   {
00191       it.next();
00192       Themable* ob = it.key();
00193       ob->changeTheme();
00194   }
00195 }
00196 
00197 
00198 // Rescale the theme. Call all registed objects so that they can refresh.
00199 void ThemeManager::rescale(int scale)
00200 {
00201   if (global_debug > 1)
00202   {
00203     if (scale==mScale)
00204       kDebug() <<" No scale change to " << scale << " If this happends to often its BAD " << endl;
00205   }
00206   //if (scale==mScale) return;
00207   mScale = scale;
00208   if (global_debug > 1) kDebug() << "Rescale to " << scale<<endl;
00209 
00210   QHashIterator<Themable*, int> it(mObjects);
00211   while (it.hasNext())
00212   {
00213       it.next();
00214       Themable* ob = it.key();
00215       ob->changeTheme();
00216   }
00217 }
00218 
00219 
00220 // Retreive the theme's scale
00221 double ThemeManager::getScale()
00222 {
00223   return (double)mScale;
00224 }  
00225 
00226 
00227 // Retreive the current theme configuration file.
00228 KConfigGroup ThemeManager::config(QString id)
00229 {
00230    KConfigGroup grp = mConfig->group(id); 
00231    return grp;
00232 }
00233 
00234 
00235 // Convert 'old' cardnumber [1-31] to SVG id of SVG card files
00236 QString ThemeManager::calcCardSVGId(int no)
00237 {
00238     const static char *ids[] = { "back",
00239                                "1_club", "1_spade", "1_heart", "1_diamond",
00240                                "king_club", "king_spade", "king_heart", "king_diamond",
00241                                "queen_club", "queen_spade", "queen_heart", "queen_diamond",
00242                                "jack_club", "jack_spade", "jack_heart", "jack_diamond",
00243                                "10_club", "10_spade", "10_heart", "10_diamond",
00244                                "9_club", "9_spade", "9_heart", "9_diamond",
00245                                "8_club", "8_spade", "8_heart", "8_diamond",
00246                                "7_club", "7_spade", "7_heart", "7_diamond",
00247                                "6_club", "6_spade", "6_heart", "6_diamond",
00248                                "5_club", "5_spade", "5_heart", "5_diamond",
00249                                "4_club", "4_spade", "4_heart", "4_diamond",
00250                                "3_club", "3_spade", "3_heart", "3_diamond",
00251                                "2_club", "2_spade", "2_heart", "2_diamond",
00252                                0 };
00253   return QString(ids[no]);
00254 }
00255 
00256 
00257 // Get the pixmap for a card , given suite, type and the desired card width in pixel
00258 const QPixmap ThemeManager::getCard(int suite, int cardtype, double width)
00259 {
00260   // Card no
00261   int no = 4*cardtype+suite+1;
00262 
00263   QPixmap pm;
00264   // SVG cards
00265   if (mCardRenderer)
00266   {
00267     QString svgid = calcCardSVGId(no);
00268     QSize size = QSize(int(width), int(width/mCardAspectRatio) );
00269     // kDebug() << "Card " << Deck::name((Suite)suite, (CardType)cardtype) << " => "<< svgid << "S="<<size<< endl;
00270     pm = getPixmap(mCardRenderer, svgid, size);
00271   }
00272   // Pixmap cards
00273   else
00274   {
00275     QString dir = mCardFile;
00276     QString file = QString("%1.png").arg(no);
00277     if (mPixmapCache.contains(file))
00278     {
00279       pm = mPixmapCache[file]; 
00280     }
00281     else if (!pm.load(dir+"/"+file))
00282     {
00283       kError() << "Cannot load card file " << dir+file << endl;
00284     }
00285     else
00286     {
00287       // Cache image
00288       mPixmapCache[file] = pm;
00289     }
00290   }
00291 
00292   // Scale to card aspect ratio if severly wrong
00293   double aspect = double(pm.width())/double(pm.height());
00294   if (aspect/mCardAspectRatio >1.05 || aspect/mCardAspectRatio < 0.95)
00295   {
00296     //kWarning() << "Wrong card aspect ratio " << aspect << " vs " << mCardAspectRatio << endl;
00297     return pm.scaled(int(width), int(width/mCardAspectRatio),
00298                      Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
00299   }
00300   else
00301   {
00302     return pm.scaledToWidth(int(width), Qt::SmoothTransformation);
00303   }
00304 }
00305 
00306 
00307 // Get the pixmap for a card back, given the desired card width in pixel
00308 const QPixmap ThemeManager::getCardback(double width)
00309 {
00310   QPixmap pm;
00311   // SVG deck
00312   if (mDeckRenderer)
00313   {
00314     QString svgid = QString(CARDBACK_SVGID);
00315     QSize size = QSize(int(width), int(width/mCardAspectRatio) );
00316     pm = getPixmap(mDeckRenderer, svgid, size);
00317   }
00318   // Pixmap deck
00319   else
00320   {
00321     QString file = mDeckFile;
00322     if (mPixmapCache.contains(file))
00323     {
00324       pm = mPixmapCache[file]; 
00325     }
00326     else if (!pm.load(file))
00327     {
00328       kError() << "Cannot load deck file " << file << endl;
00329     }
00330     else
00331     {
00332       // Cache image
00333       mPixmapCache[file] = pm;
00334     }
00335   }
00336 
00337   // Scale to card aspect ratio if severly wrong
00338   double aspect = double(pm.width())/double(pm.height());
00339   if (aspect/mCardAspectRatio >1.05 || aspect/mCardAspectRatio < 0.95)
00340   {
00341     //kWarning() << "Wrong deck aspect ratio " << aspect << " vs " << mCardAspectRatio << endl;
00342     return pm.scaled(int(width), int(width/mCardAspectRatio), 
00343                      Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
00344   }
00345   else
00346   {
00347     return pm.scaledToWidth(int(width), Qt::SmoothTransformation);
00348   }
00349 }
00350 
00351 
00352 // Get a pixmap when its size is given (this can distort the image)
00353 const QPixmap ThemeManager::getPixmap(KSvgRenderer* renderer, QString svgid, QSize size)
00354 {
00355   if (size.width() < 1 || size.height() < 1) 
00356     kFatal() << "ThemeManager::getPixmap Cannot create svgid ID " << svgid << " with zero size " << size << endl;
00357   
00358   QPixmap pixmap;
00359 
00360   //  Cached pixmap?
00361   if (mPixmapCache.contains(svgid))
00362   {
00363     pixmap = mPixmapCache[svgid]; 
00364     if (pixmap.size() == size) 
00365     {
00366       return pixmap;
00367     }
00368   }
00369 
00370   // Create new image
00371   QImage image(size, QImage::Format_ARGB32_Premultiplied);
00372   image.fill(0);
00373   QPainter p(&image);
00374   renderer->render(&p, svgid);
00375   pixmap = QPixmap::fromImage(image);
00376   if (pixmap.isNull())
00377     kFatal() << "ThemeManager::getPixmap Cannot load svgid ID " << svgid << endl;
00378 
00379   // Cache image
00380   mPixmapCache[svgid] = pixmap;
00381 
00382   return pixmap;
00383 }
00384 
00385 
00386 // Get a pixmap when its size is given (this can distort the image)
00387 const QPixmap ThemeManager::getPixmap(QString svgid, QSize size)
00388 {
00389   return getPixmap(mRenderer, svgid, size);
00390 }
00391 
00392 
00393 // Get a pixmap when only width is given (this keeps the aspect ratio)
00394 const QPixmap ThemeManager::getPixmap(QString svgid, double width)
00395 {
00396   QRectF rect   = mRenderer->boundsOnElement(svgid);
00397   double factor = width/rect.width();
00398   QSize size    = QSize(int(width),  int(rect.height()*factor));
00399   return getPixmap(svgid, size);
00400 }
00401 
00402 
00403 // Get a pixmap with original properties and a scale factor given with respect to
00404 // another SVG item.
00405 const QPixmap ThemeManager::getPixmap(QString svgid, QString svgref, double refwidth)
00406 {
00407   QRectF refrect    = mRenderer->boundsOnElement(svgref);
00408   QRectF rect       = mRenderer->boundsOnElement(svgid);
00409   double factor     = refwidth/refrect.width();
00410   QSize size        = QSize(int(rect.width()*factor),  int(rect.height()*factor));
00411   return getPixmap(svgid, size);
00412 }
00413 
00414 
00415 // ========================== Themable interface ===============================
00416 
00417 // Constructs a themable interface
00418 Themable::Themable()
00419 {
00420   mScale        = 1.0;
00421   mThemeManager = 0;
00422 }
00423 
00424 
00425 // Constructs a themeable interface given its id and the master theme manager. 
00426 // This automatically registeres the object with the manager.
00427 Themable::Themable(QString id, ThemeManager* thememanager)
00428 {
00429   mScale        = 1.0;
00430   mId           = id;
00431   mThemeManager = thememanager;
00432   if (!thememanager) return;
00433   thememanager->registerTheme(this);
00434 }
00435 
00436 
00437 // Destructs the themeable object
00438 Themable::~Themable()
00439 {
00440   if (mThemeManager) mThemeManager->unregisterTheme(this);
00441 }
00442 
00443 
00444 

Generated on Tue May 1 09:34:40 2007 for LSkat by  doxygen 1.4.6