Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

skin.cpp

Go to the documentation of this file.
00001 /*
00002    Copyright (C) 2002 Simon Hausmann <simon@lst.de>
00003              (C) 2002 Max Reiss <harlekin@handhelds.org>
00004              (C) 2002 L. Potter <ljp@llornkcor.com>
00005              (C) 2002 Holger Freyther <zecke@handhelds.org>
00006 
00007    This program is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU General Public
00009    License as published by the Free Software Foundation; either
00010    version 2 of the License, or (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; see the file COPYING.  If not, write to
00019    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020    Boston, MA 02111-1307, USA.
00021 */
00022 
00023 #include "skin.h"
00024 #include "singleton.h"
00025 
00026 /* OPIE */
00027 #include <opie2/odebug.h>
00028 #include <opie2/oresource.h>
00029 using namespace Opie::Core;
00030 #include <qpe/config.h>
00031 #include <qpe/global.h>
00032 
00033 /* QT */
00034 #include <qcache.h>
00035 #include <qtimer.h>
00036 
00037 /* STD */
00038 #include <assert.h>
00039 
00040 struct SkinData
00041 {
00042     typedef QMap<QString, QImage> ButtonMaskImageMap;
00043 
00044     QPixmap backgroundPixmap;
00045     QImage buttonUpImage;
00046     QImage buttonDownImage;
00047     QImage buttonMask;
00048     ButtonMaskImageMap buttonMasks;
00049 };
00050 
00051 class SkinCache : public Singleton<SkinCache>
00052 {
00053 public:
00054     SkinCache();
00055 
00056     SkinData *lookupAndTake( const QString &skinPath, const QString &fileNameInfix );
00057 
00058     void store( const QString &skinPath, const QString &fileNameInfix, SkinData *data );
00059 
00060 private:
00061     typedef QCache<SkinData> DataCache;
00062     typedef QCache<QPixmap> BackgroundPixmapCache;
00063 
00064     template <class CacheType>
00065     void store( const QCache<CacheType> &cache, const QString &key, CacheType *data );
00066 
00067     DataCache m_cache;
00068     BackgroundPixmapCache m_backgroundPixmapCache;
00069 };
00070 
00071 Skin::Skin( const QString &name, const QString &fileNameInfix )
00072     : m_fileNameInfix( fileNameInfix )
00073 {
00074     init( name );
00075 }
00076 
00077 Skin::Skin( const QString &fileNameInfix )
00078     : m_fileNameInfix( fileNameInfix )
00079 {
00080     init( defaultSkinName() );
00081 }
00082 
00083 Skin::~Skin()
00084 {
00085     if ( m_isCachable )
00086         SkinCache::self().store( m_skinPath, m_fileNameInfix, d );
00087     else
00088         delete d;
00089 }
00090 
00091 void Skin::init( const QString &name )
00092 {
00093     m_isCachable = true;
00094     m_skinPath = "opieplayer2/skins/" + name;
00095     d = SkinCache::self().lookupAndTake( m_skinPath, m_fileNameInfix );
00096 }
00097 
00098 QPixmap Skin::backgroundPixmap() const
00099 {
00100     if ( d->backgroundPixmap.isNull() )
00101         d->backgroundPixmap = loadImage( QString( "%1/background" ).arg( m_skinPath ) );
00102     return d->backgroundPixmap;
00103 }
00104 
00105 QImage Skin::buttonUpImage() const
00106 {
00107     if ( d->buttonUpImage.isNull() )
00108         d->buttonUpImage = loadImage( QString( "%1/skin%2_up" ).arg( m_skinPath ).arg( m_fileNameInfix ) );
00109     return d->buttonUpImage;
00110 }
00111 
00112 QImage Skin::buttonDownImage() const
00113 {
00114     if ( d->buttonDownImage.isNull() )
00115         d->buttonDownImage = loadImage( QString( "%1/skin%2_down" ).arg( m_skinPath ).arg( m_fileNameInfix ) );
00116     return d->buttonDownImage;
00117 }
00118 
00119 QImage Skin::buttonMask( const MediaWidget::SkinButtonInfo *skinButtonInfo, uint buttonCount ) const
00120 {
00121     if ( !d->buttonMask.isNull() )
00122         return d->buttonMask;
00123 
00124     QSize buttonAreaSize = buttonUpImage().size();
00125 
00126     d->buttonMask = QImage( buttonAreaSize, 8, 255 );
00127     d->buttonMask.fill( 0 );
00128 
00129     for ( uint i = 0; i < buttonCount; ++i )
00130         addButtonToMask( skinButtonInfo[ i ].command + 1, buttonMaskImage( skinButtonInfo[ i ].fileName ) );
00131 
00132     return d->buttonMask;
00133 }
00134 
00135 void Skin::addButtonToMask( int tag, const QImage &maskImage ) const
00136 {
00137     if ( maskImage.isNull() )
00138         return;
00139 
00140     uchar **dest = d->buttonMask.jumpTable();
00141     for ( int y = 0; y < d->buttonMask.height(); y++ ) {
00142         uchar *line = dest[y];
00143         for ( int x = 0; x < d->buttonMask.width(); x++ )
00144             if ( !qRed( maskImage.pixel( x, y ) ) )
00145                 line[x] = tag;
00146     }
00147 }
00148 
00149 QImage Skin::buttonMaskImage( const QString &fileName ) const
00150 {
00151     SkinData::ButtonMaskImageMap::Iterator it = d->buttonMasks.find( fileName );
00152     if ( it == d->buttonMasks.end() ) {
00153         QString prefix = m_skinPath + QString::fromLatin1( "/skin%1_mask_" ).arg( m_fileNameInfix );
00154         QString path = prefix + fileName;
00155         it = d->buttonMasks.insert( fileName, loadImage( path ) );
00156     }
00157     return *it;
00158 }
00159 
00160 QString Skin::defaultSkinName()
00161 {
00162     Config cfg( "OpiePlayer" );
00163     cfg.setGroup( "Options" );
00164     return cfg.readEntry( "Skin", "default" );
00165 }
00166 
00167 QImage Skin::loadImage( const QString &fileName )
00168 {
00169     return QImage( Opie::Core::OResource::findPixmap( fileName ) );
00170 }
00171 
00172 SkinCache::SkinCache()
00173 {
00174     // let's say we cache two skins (audio+video) at maximum
00175     m_cache.setMaxCost( 2 );
00176     // ... and one background pixmap
00177     m_backgroundPixmapCache.setMaxCost( 1 );
00178 }
00179 
00180 SkinData *SkinCache::lookupAndTake( const QString &skinPath, const QString &fileNameInfix )
00181 {
00182     QString key = skinPath + fileNameInfix;
00183 
00184     SkinData *data = m_cache.take( key );
00185     if ( !data )
00186         data = new SkinData;
00187     else
00188         odebug << "SkinCache: hit" << oendl;
00189 
00190     QPixmap *bgPixmap = m_backgroundPixmapCache.find( skinPath );
00191     if ( bgPixmap ) {
00192         odebug << "SkinCache: hit on bgpixmap" << oendl;
00193         data->backgroundPixmap = *bgPixmap;
00194     }
00195     else
00196         data->backgroundPixmap = QPixmap();
00197 
00198     return data;
00199 }
00200 
00201 void SkinCache::store( const QString &skinPath, const QString &fileNameInfix, SkinData *data )
00202 {
00203     QPixmap *backgroundPixmap = new QPixmap( data->backgroundPixmap );
00204 
00205     data->backgroundPixmap = QPixmap();
00206 
00207     QString key = skinPath + fileNameInfix;
00208 
00209     if ( m_cache.find( key, false /*ref*/ ) != 0 ||
00210          !m_cache.insert( key, data ) )
00211         delete data;
00212 
00213     if ( m_backgroundPixmapCache.find( skinPath, false /*ref*/ ) != 0 ||
00214          !m_backgroundPixmapCache.insert( skinPath, backgroundPixmap ) )
00215         delete backgroundPixmap;
00216 }
00217 
00218 SkinLoader::IncrementalLoader::IncrementalLoader( const Info &info )
00219     : m_skin( info.skinName, info.fileNameInfix ), m_info( info )
00220 {
00221     m_currentState = LoadBackgroundPixmap;
00222 }
00223 
00224 SkinLoader::IncrementalLoader::LoaderResult SkinLoader::IncrementalLoader::loadStep()
00225 {
00226     switch ( m_currentState ) {
00227         case LoadBackgroundPixmap:
00228             odebug << "load bgpixmap" << oendl;
00229             m_skin.backgroundPixmap();
00230             m_currentState = LoadButtonUpImage;
00231             break;
00232         case LoadButtonUpImage:
00233             odebug << "load upimage" << oendl;
00234             m_skin.buttonUpImage();
00235             m_currentState = LoadButtonDownImage;
00236             break;
00237         case LoadButtonDownImage:
00238             odebug << "load downimage" << oendl;
00239             m_skin.buttonDownImage();
00240             m_currentState = LoadButtonMasks;
00241             m_currentButton = 0;
00242             break;
00243         case LoadButtonMasks:
00244             odebug << "load button masks " << m_currentButton << "" << oendl;
00245             m_skin.buttonMaskImage( m_info.buttonInfo[ m_currentButton ].fileName );
00246 
00247             m_currentButton++;
00248             if ( m_currentButton >= m_info.buttonCount )
00249                 m_currentState = LoadButtonMask;
00250 
00251             break;
00252         case LoadButtonMask:
00253             odebug << "load whole mask" << oendl;
00254             m_skin.buttonMask( m_info.buttonInfo, m_info.buttonCount );
00255             return LoadingCompleted;
00256     }
00257 
00258     return MoreToCome;
00259 }
00260 
00261 SkinLoader::SkinLoader()
00262     : m_currentLoader( 0 ), m_timerId( -1 )
00263 {
00264 }
00265 
00266 SkinLoader::~SkinLoader()
00267 {
00268     Global::statusMessage( tr( "Loading of Skin finished" ) );
00269     killTimers();
00270     delete m_currentLoader;
00271 }
00272 
00273 void SkinLoader::schedule( const MediaWidget::GUIInfo &guiInfo )
00274 {
00275     schedule( Skin::defaultSkinName(), guiInfo );
00276 }
00277 
00278 void SkinLoader::schedule( const QString &skinName, const MediaWidget::GUIInfo &guiInfo )
00279 {
00280     pendingSkins << Info( skinName, guiInfo );
00281 }
00282 
00283 void SkinLoader::start()
00284 {
00285     assert( m_timerId == -1 );
00286     m_timerId = startTimer( 100 /* ms */ );
00287     odebug << "SkinLoader::start() " << pendingSkins.count() << " jobs" << oendl;
00288 }
00289 
00290 void SkinLoader::timerEvent( QTimerEvent *ev )
00291 {
00292     if ( ev->timerId() != m_timerId ) {
00293         QObject::timerEvent( ev );
00294         return;
00295     }
00296 
00297     if ( !m_currentLoader ) {
00298 
00299         if ( pendingSkins.isEmpty() ) {
00300             odebug << "all jobs done" << oendl;
00301             killTimer( m_timerId );
00302             m_timerId = -1;
00303             // ### qt3: use deleteLater();
00304             QTimer::singleShot( 0, this, SLOT( deleteMe() ) );
00305             return;
00306         }
00307 
00308         Info nfo = *pendingSkins.begin();
00309         pendingSkins.remove( pendingSkins.begin() );
00310 
00311         m_currentLoader = new IncrementalLoader( nfo );
00312         odebug << "new loader " << pendingSkins.count() << " jobs left" << oendl;
00313     }
00314 
00315     if ( m_currentLoader->loadStep() == IncrementalLoader::LoadingCompleted ) {
00316         delete m_currentLoader;
00317         m_currentLoader = 0;
00318     }
00319 
00320     odebug << "finished step" << oendl;
00321 }
00322 
00323 void SkinLoader::deleteMe()
00324 {
00325     delete this;
00326 }
00327 
00328 /* vim: et sw=4 ts=4
00329  */

Generated on Sat Nov 5 16:17:33 2005 for OPIE by  doxygen 1.4.2