00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "skin.h"
00024 #include "singleton.h"
00025
00026
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
00034 #include <qcache.h>
00035 #include <qtimer.h>
00036
00037
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
00175 m_cache.setMaxCost( 2 );
00176
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 ) != 0 ||
00210 !m_cache.insert( key, data ) )
00211 delete data;
00212
00213 if ( m_backgroundPixmapCache.find( skinPath, false ) != 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 );
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
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
00329