2003-02-16 03:59:37 +00:00
# include "global.h"
2002-01-16 10:01:32 +00:00
/*
-----------------------------------------------------------------------------
2002-05-19 01:59:48 +00:00
Class: ThemeManager
2002-01-16 10:01:32 +00:00
2002-02-28 19:40:40 +00:00
Desc: See header.
2002-01-16 10:01:32 +00:00
2002-05-19 01:59:48 +00:00
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
2002-02-28 19:40:40 +00:00
Chris Danford
2002-01-16 10:01:32 +00:00
-----------------------------------------------------------------------------
*/
# include "ThemeManager.h"
2002-05-01 19:14:55 +00:00
# include "RageLog.h"
2002-07-23 01:41:40 +00:00
# include "PrefsManager.h"
2002-07-27 19:29:51 +00:00
# include "RageException.h"
2002-08-31 10:33:13 +00:00
# include "RageTimer.h"
2004-04-30 07:26:06 +00:00
# include "RageUtil.h"
2002-07-31 19:40:40 +00:00
# include "GameState.h"
# include "GameDef.h"
2002-08-13 23:26:46 +00:00
# include "IniFile.h"
2002-10-28 19:05:05 +00:00
# include "RageTimer.h"
2003-01-10 02:02:51 +00:00
# include "Font.h"
2003-01-18 09:18:30 +00:00
# include "FontCharAliases.h"
2003-03-02 01:43:33 +00:00
# include "RageDisplay.h"
2003-07-11 03:15:28 +00:00
# include "arch/ArchHooks/ArchHooks.h"
2003-07-22 07:47:27 +00:00
# include "arch/arch.h"
# include "RageFile.h"
2003-11-05 04:56:41 +00:00
# include "ScreenManager.h"
2004-04-30 07:26:06 +00:00
# include "StepMania.h"
2002-01-16 10:01:32 +00:00
ThemeManager * THEME = NULL ; // global object accessable from anywhere in the program
2002-07-23 01:41:40 +00:00
const CString BASE_THEME_NAME = " default " ;
2003-11-25 19:03:40 +00:00
const CString FALLBACK_THEME_NAME = " fallback " ;
2003-12-10 09:44:16 +00:00
const CString LANGUAGES_SUBDIR = " Languages/ " ;
2003-08-19 08:01:15 +00:00
const CString BASE_LANGUAGE = " english " ;
2003-12-10 09:26:05 +00:00
const CString THEMES_DIR = " Themes/ " ;
2003-08-19 08:01:15 +00:00
const CString METRICS_FILE = " metrics.ini " ;
2003-04-12 17:39:27 +00:00
const CString ELEMENT_CATEGORY_STRING [ NUM_ELEMENT_CATEGORIES ] =
{
" BGAnimations " ,
" Fonts " ,
" Graphics " ,
" Numbers " ,
2003-09-11 23:21:33 +00:00
" Sounds " ,
" Other "
2003-04-12 17:39:27 +00:00
} ;
2002-05-19 01:59:48 +00:00
2003-10-22 07:56:08 +00:00
/* We spend a lot of time doing redundant theme path lookups. Cache results. */
static map < CString , CString > g_ThemePathCache [ NUM_ELEMENT_CATEGORIES ] ;
2004-01-24 21:16:07 +00:00
void FileNameToClassAndElement ( const CString & sFileName , CString & sClassNameOut , CString & sElementOut )
{
// split into class name and file name
int iIndexOfFirstSpace = sFileName . Find ( " " ) ;
if ( iIndexOfFirstSpace = = - 1 ) // no space
{
sClassNameOut = " " ;
sElementOut = sFileName ;
}
else
{
sClassNameOut = sFileName . Left ( iIndexOfFirstSpace ) ;
sElementOut = sFileName . Right ( sFileName . length ( ) - iIndexOfFirstSpace - 1 ) ;
}
}
CString ClassAndElementToFileName ( const CString & sClassName , const CString & sElement )
{
if ( sClassName . empty ( ) )
return sElement ;
else
return sClassName + " " + sElement ;
}
2002-03-19 07:09:49 +00:00
ThemeManager : : ThemeManager ( )
{
2004-03-20 03:02:12 +00:00
m_pIniCurMetrics = new IniFile ;
m_pIniBaseMetrics = new IniFile ;
2002-08-13 23:26:46 +00:00
2002-10-28 19:05:05 +00:00
m_sCurThemeName = BASE_THEME_NAME ; // Use the base theme for now. It's up to PrefsManager to change this.
2003-08-19 08:01:15 +00:00
m_uHashForCurThemeMetrics = 0 ;
m_uHashForBaseThemeMetrics = 0 ;
m_uHashForCurThemeCurLanguage = 0 ;
m_uHashForBaseThemeCurLanguage = 0 ;
m_uHashForCurThemeBaseLanguage = 0 ;
m_uHashForBaseThemeBaseLanguage = 0 ;
2003-03-11 19:02:09 +00:00
2002-03-19 07:09:49 +00:00
CStringArray arrayThemeNames ;
2003-04-13 04:50:08 +00:00
GetThemeNames ( arrayThemeNames ) ;
2002-03-19 07:09:49 +00:00
}
2002-08-13 23:26:46 +00:00
ThemeManager : : ~ ThemeManager ( )
{
2004-03-20 03:02:12 +00:00
delete m_pIniCurMetrics ;
delete m_pIniBaseMetrics ;
2002-08-13 23:26:46 +00:00
}
2003-04-13 04:50:08 +00:00
void ThemeManager : : GetThemeNames ( CStringArray & AddTo )
2002-03-19 07:09:49 +00:00
{
2003-07-22 07:47:27 +00:00
GetDirListing ( THEMES_DIR + " * " , AddTo , true ) ;
2002-03-19 07:09:49 +00:00
// strip out the folder called "CVS"
2002-10-31 04:11:08 +00:00
for ( CStringArray : : iterator i = AddTo . begin ( ) ; i ! = AddTo . end ( ) ; + + i )
{
2003-02-06 07:32:57 +00:00
if ( * i = = " CVS " ) {
2002-10-31 04:11:08 +00:00
AddTo . erase ( i , i + 1 ) ;
break ;
}
}
2002-03-19 07:09:49 +00:00
}
2002-07-23 01:41:40 +00:00
bool ThemeManager : : DoesThemeExist ( CString sThemeName )
2002-03-19 07:09:49 +00:00
{
2002-07-23 01:41:40 +00:00
CStringArray asThemeNames ;
2003-04-13 04:50:08 +00:00
GetThemeNames ( asThemeNames ) ;
2002-10-31 02:12:14 +00:00
for ( unsigned i = 0 ; i < asThemeNames . size ( ) ; i + + )
2002-07-27 19:29:51 +00:00
{
2003-01-03 05:29:45 +00:00
if ( ! sThemeName . CompareNoCase ( asThemeNames [ i ] ) )
2002-07-23 01:41:40 +00:00
return true ;
2002-07-27 19:29:51 +00:00
}
2002-07-23 01:41:40 +00:00
return false ;
2002-03-19 07:09:49 +00:00
}
2003-08-19 08:01:15 +00:00
void ThemeManager : : GetLanguages ( CStringArray & AddTo )
{
AddTo . clear ( ) ;
CStringArray asTemp ;
GetLanguagesForTheme ( m_sCurThemeName , AddTo ) ;
GetLanguagesForTheme ( BASE_THEME_NAME , asTemp ) ;
AddTo . insert ( AddTo . begin ( ) , asTemp . begin ( ) , asTemp . end ( ) ) ;
// remove dupes
sort ( AddTo . begin ( ) , AddTo . end ( ) ) ;
CStringArray : : iterator it = unique ( AddTo . begin ( ) , AddTo . end ( ) ) ;
AddTo . erase ( it , AddTo . end ( ) ) ;
}
bool ThemeManager : : DoesLanguageExist ( CString sLanguage )
{
CStringArray asLanguages ;
GetLanguages ( asLanguages ) ;
for ( unsigned i = 0 ; i < asLanguages . size ( ) ; i + + )
if ( sLanguage . CompareNoCase ( asLanguages [ i ] ) = = 0 )
return true ;
return false ;
}
void ThemeManager : : SwitchThemeAndLanguage ( CString sThemeName , CString sLanguage )
2002-07-23 01:41:40 +00:00
{
2002-09-29 17:38:07 +00:00
if ( ! DoesThemeExist ( sThemeName ) )
2002-07-23 01:41:40 +00:00
m_sCurThemeName = BASE_THEME_NAME ;
else
m_sCurThemeName = sThemeName ;
2002-08-13 23:26:46 +00:00
2003-08-19 08:01:15 +00:00
if ( ! DoesLanguageExist ( sLanguage ) )
m_sCurLanguage = BASE_LANGUAGE ;
else
m_sCurLanguage = sLanguage ;
2003-12-01 00:27:55 +00:00
// clear theme path cache
2004-04-30 07:26:06 +00:00
int i ;
for ( i = 0 ; i < NUM_ELEMENT_CATEGORIES ; + + i )
2003-12-01 00:27:55 +00:00
g_ThemePathCache [ i ] . clear ( ) ;
2002-08-13 23:26:46 +00:00
// update hashes for metrics files
2003-08-19 08:01:15 +00:00
m_uHashForCurThemeMetrics = GetHashForFile ( GetMetricsIniPath ( m_sCurThemeName ) ) ;
m_uHashForBaseThemeMetrics = GetHashForFile ( GetMetricsIniPath ( BASE_THEME_NAME ) ) ;
m_uHashForBaseThemeBaseLanguage = GetHashForFile ( GetLanguageIniPath ( BASE_THEME_NAME , BASE_LANGUAGE ) ) ;
m_uHashForCurThemeBaseLanguage = GetHashForFile ( GetLanguageIniPath ( m_sCurThemeName , BASE_LANGUAGE ) ) ;
m_uHashForBaseThemeCurLanguage = GetHashForFile ( GetLanguageIniPath ( BASE_THEME_NAME , m_sCurLanguage ) ) ;
m_uHashForCurThemeCurLanguage = GetHashForFile ( GetLanguageIniPath ( m_sCurThemeName , m_sCurLanguage ) ) ;
2002-08-13 23:26:46 +00:00
// read new metrics. First read base metrics, then read cur theme's metrics, overriding base theme
2004-03-20 03:02:12 +00:00
m_pIniCurMetrics - > Reset ( ) ;
m_pIniBaseMetrics - > Reset ( ) ;
2004-05-23 02:27:51 +00:00
m_pIniBaseMetrics - > ReadFile ( GetMetricsIniPath ( FALLBACK_THEME_NAME ) ) ;
m_pIniBaseMetrics - > ReadFile ( GetMetricsIniPath ( BASE_THEME_NAME ) ) ;
m_pIniCurMetrics - > ReadFile ( GetMetricsIniPath ( m_sCurThemeName ) ) ;
m_pIniBaseMetrics - > ReadFile ( GetLanguageIniPath ( FALLBACK_THEME_NAME , BASE_LANGUAGE ) ) ;
m_pIniBaseMetrics - > ReadFile ( GetLanguageIniPath ( BASE_THEME_NAME , BASE_LANGUAGE ) ) ;
m_pIniCurMetrics - > ReadFile ( GetLanguageIniPath ( m_sCurThemeName , BASE_LANGUAGE ) ) ;
m_pIniBaseMetrics - > ReadFile ( GetLanguageIniPath ( FALLBACK_THEME_NAME , m_sCurLanguage ) ) ;
m_pIniBaseMetrics - > ReadFile ( GetLanguageIniPath ( BASE_THEME_NAME , m_sCurLanguage ) ) ;
m_pIniCurMetrics - > ReadFile ( GetLanguageIniPath ( m_sCurThemeName , m_sCurLanguage ) ) ;
2003-04-22 04:11:04 +00:00
2004-04-30 07:26:06 +00:00
CString sMetric ;
for ( i = 0 ; GetCommandlineArgument ( " metric " , & sMetric , i ) ; + + i )
{
/* sMetric must be "foo::bar=baz". "foo" and "bar" never contain "=", so in
* "foo::bar=1+1=2", "baz" is always "1+1=2". Neither foo nor bar may be
* empty, but baz may be. */
Regex re ( " ^([^=]+) : : ( [ ^ = ] + ) = ( . * ) $ " ) ;
vector < CString > sBits ;
if ( ! re . Compare ( sMetric , sBits ) )
RageException : : Throw ( " Invalid argument \" --metric=%s \" " , sMetric . c_str ( ) ) ;
m_pIniCurMetrics - > SetValue ( sBits [ 0 ] , sBits [ 1 ] , sBits [ 2 ] ) ;
}
2003-04-22 05:21:45 +00:00
LOG - > MapLog ( " theme " , " Theme: %s " , sThemeName . c_str ( ) ) ;
2003-08-19 08:01:15 +00:00
LOG - > MapLog ( " language " , " Language: %s " , sLanguage . c_str ( ) ) ;
2002-03-19 07:09:49 +00:00
}
2003-01-23 04:41:57 +00:00
CString ThemeManager : : GetThemeDirFromName ( const CString & sThemeName )
2002-03-19 07:09:49 +00:00
{
2003-12-10 09:44:16 +00:00
return THEMES_DIR + sThemeName + " / " ;
2002-03-19 07:09:49 +00:00
}
2004-02-03 04:41:43 +00:00
CString ThemeManager : : GetPathToAndFallback ( CString sThemeName , ElementCategory category , CString sClassName , CString sElement )
{
2004-02-15 21:39:15 +00:00
int n = 100 ;
while ( n - - )
2004-02-03 04:41:43 +00:00
{
2004-02-15 21:39:15 +00:00
// search with requested name
CString sRet = GetPathToRaw ( sThemeName , category , sClassName , sElement ) ;
2004-02-03 04:41:43 +00:00
if ( ! sRet . empty ( ) )
return sRet ;
2004-02-15 21:39:15 +00:00
// search fallback name (if any)
CString sFallback ;
2004-03-20 03:02:12 +00:00
GetMetricRaw ( sClassName , " Fallback " , sFallback ) ;
if ( sFallback . empty ( ) )
2004-02-15 21:39:15 +00:00
return " " ;
sClassName = sFallback ;
2004-02-03 04:41:43 +00:00
}
2004-02-15 21:39:15 +00:00
RageException : : Throw ( " Infinite recursion looking up theme element from theme \" %s \" , class \" %s \" " ,
sThemeName . c_str ( ) , sClassName . c_str ( ) ) ;
2004-02-03 04:41:43 +00:00
}
2004-01-24 21:16:07 +00:00
CString ThemeManager : : GetPathToRaw ( CString sThemeName , ElementCategory category , CString sClassName , CString sElement )
2003-01-05 07:55:31 +00:00
{
2003-02-22 21:47:42 +00:00
try_element_again :
2003-01-05 07:55:31 +00:00
2003-01-26 21:45:13 +00:00
const CString sThemeDir = GetThemeDirFromName ( sThemeName ) ;
2003-04-12 17:39:27 +00:00
const CString sCategory = ELEMENT_CATEGORY_STRING [ category ] ;
2003-01-05 07:55:31 +00:00
2003-03-15 00:16:45 +00:00
CStringArray asElementPaths ;
2003-01-05 07:55:31 +00:00
2003-04-12 17:39:27 +00:00
// If sFileName already has an extension, we're looking for a specific file
2004-01-24 21:16:07 +00:00
bool bLookingForSpecificFile = sElement . find_last_of ( ' . ' ) ! = sElement . npos ;
2003-04-12 17:39:27 +00:00
bool bDirsOnly = category = = BGAnimations ;
if ( bLookingForSpecificFile )
{
2004-01-24 21:16:07 +00:00
GetDirListing ( sThemeDir + sCategory + " / " + ClassAndElementToFileName ( sClassName , sElement ) , asElementPaths , bDirsOnly , true ) ;
2003-04-12 17:39:27 +00:00
}
else // look for all files starting with sFileName that have types we can use
{
2004-04-06 00:46:05 +00:00
const CString wildcard = ( category = = BGAnimations ? " " : " * " ) ;
2003-04-12 17:39:27 +00:00
/* First, look for redirs. */
2004-04-06 00:46:05 +00:00
GetDirListing ( sThemeDir + sCategory + " / " + ClassAndElementToFileName ( sClassName , sElement ) + wildcard + " .redir " ,
2003-04-12 17:39:27 +00:00
asElementPaths , false , true ) ;
2003-10-19 23:00:11 +00:00
CStringArray asPaths ;
2004-01-24 21:16:07 +00:00
GetDirListing ( sThemeDir + sCategory + " / " + ClassAndElementToFileName ( sClassName , sElement ) + wildcard ,
2003-10-19 23:00:11 +00:00
asPaths , bDirsOnly , true ) ;
for ( unsigned p = 0 ; p < asPaths . size ( ) ; + + p )
{
static const char * masks [ NUM_ELEMENT_CATEGORIES ] [ 12 ] = {
{ " " , NULL } ,
{ " ini " , NULL } ,
2003-10-31 02:06:48 +00:00
{ " actor " , " sprite " , " png " , " jpg " , " bmp " , " gif " , " avi " , " mpg " , " mpeg " , " txt " , " " , NULL } ,
2003-10-19 23:00:11 +00:00
{ " png " , NULL } ,
{ " mp3 " , " ogg " , " wav " , NULL } ,
{ " sm " , NULL } ,
} ;
const char * * asset_masks = masks [ category ] ;
const CString ext = GetExtension ( asPaths [ p ] ) ;
if ( ext = = " redir " )
continue ; // got it already
for ( int i = 0 ; asset_masks [ i ] ; + + i )
{
2003-10-31 02:06:48 +00:00
/* No extension means directories. */
if ( asset_masks [ i ] [ 0 ] = = 0 & & ! IsADirectory ( asPaths [ p ] ) )
continue ;
2003-10-19 23:00:11 +00:00
if ( ext = = asset_masks [ i ] )
{
asElementPaths . push_back ( asPaths [ p ] ) ;
break ;
}
}
}
2003-04-12 17:39:27 +00:00
if ( category = = Fonts )
2004-01-24 21:16:07 +00:00
Font : : WeedFontNames ( asElementPaths , ClassAndElementToFileName ( sClassName , sElement ) ) ;
2003-04-12 17:39:27 +00:00
}
2003-03-15 00:16:45 +00:00
2003-11-17 03:37:51 +00:00
if ( asElementPaths . size ( ) = = 0 )
{
2004-05-30 23:23:39 +00:00
// HACK: have Numbers fall back to fonts. Eventually Numbers will be removed.
if ( category = = Numbers )
return GetPathToRaw ( sThemeName , Fonts , sClassName , sElement ) ;
2003-11-17 03:37:51 +00:00
return " " ; // This isn't fatal.
}
2003-03-15 00:16:45 +00:00
if ( asElementPaths . size ( ) > 1 )
{
2003-07-03 02:41:27 +00:00
FlushDirCache ( ) ;
2003-10-22 07:56:08 +00:00
g_ThemePathCache [ category ] . clear ( ) ;
2003-03-15 03:09:06 +00:00
2003-03-15 00:16:45 +00:00
CString message = ssprintf (
2003-07-11 03:15:28 +00:00
" ThemeManager: There is more than one theme element element that matches "
2004-01-24 21:16:07 +00:00
" '%s/%s/%s %s'. Please remove all but one of these matches. " ,
sThemeName . c_str ( ) , sCategory . c_str ( ) , sClassName . c_str ( ) , sElement . c_str ( ) ) ;
2003-07-11 03:39:02 +00:00
2003-11-17 03:37:51 +00:00
switch ( HOOKS - > MessageBoxAbortRetryIgnore ( message ) )
{
case ArchHooks : : abort :
RageException : : Throw ( message ) ;
break ;
case ArchHooks : : retry :
2004-02-01 03:14:37 +00:00
FlushDirCache ( ) ;
ReloadMetrics ( ) ;
2003-11-15 06:08:13 +00:00
goto try_element_again ;
2003-11-17 03:37:51 +00:00
case ArchHooks : : ignore :
break ;
}
2003-03-15 00:16:45 +00:00
}
2003-11-17 03:37:51 +00:00
CString sPath = asElementPaths [ 0 ] ;
bool bIsARedirect = GetExtension ( sPath ) . CompareNoCase ( " redir " ) = = 0 ;
if ( ! bIsARedirect )
2003-03-15 00:16:45 +00:00
{
2003-11-17 03:37:51 +00:00
return sPath ;
2003-03-15 00:16:45 +00:00
}
2003-11-17 03:37:51 +00:00
else // bIsARedirect
2003-03-15 00:16:45 +00:00
{
2003-11-17 03:37:51 +00:00
CString sNewFileName = GetRedirContents ( sPath ) ;
2004-01-24 21:16:07 +00:00
CString sNewClassName , sNewFile ;
FileNameToClassAndElement ( sNewFileName , sNewClassName , sNewFile ) ;
2003-11-17 03:37:51 +00:00
/* backwards-compatibility hack */
if ( category = = Fonts )
sNewFileName . Replace ( " 16x16.png " , " " ) ;
/* Search again. For example, themes/default/Fonts/foo might redir
* to "Hello"; but "Hello" might be overridden in themes/hot pink/Fonts/Hello. */
/* Important: We need to do a full search. For example, BG redirs in
* the default theme point to "_shared background", and themes override
* just "_shared background"; the redirs in the default theme should end
* up resolving to the overridden background. */
/* Use GetPathToOptional because we don't want report that there's an element
* missing. Instead we want to report that the redirect is invalid. */
2004-02-14 01:16:04 +00:00
CString sNewPath = GetPath ( category , sNewClassName , sNewFile , true ) ;
2003-11-17 03:37:51 +00:00
if ( ! sNewPath . empty ( ) )
return sNewPath ;
else
2003-03-15 00:16:45 +00:00
{
2003-11-17 03:37:51 +00:00
CString message = ssprintf (
" ThemeManager: The redirect '%s' points to the file '%s', which does not exist. "
" Verify that this redirect is correct. " ,
sPath . c_str ( ) , sNewFileName . c_str ( ) ) ;
2003-03-15 00:16:45 +00:00
2003-11-17 03:37:51 +00:00
if ( ArchHooks : : retry = = HOOKS - > MessageBoxAbortRetryIgnore ( message ) )
2004-02-01 03:14:37 +00:00
{
FlushDirCache ( ) ;
ReloadMetrics ( ) ;
2003-11-17 03:37:51 +00:00
goto try_element_again ;
2004-02-01 03:14:37 +00:00
}
2003-07-11 03:15:28 +00:00
2003-11-17 03:37:51 +00:00
RageException : : Throw ( " %s " , message . c_str ( ) ) ;
2003-03-15 00:16:45 +00:00
}
}
2003-01-26 21:45:13 +00:00
}
2003-01-23 04:41:57 +00:00
2004-02-14 01:16:04 +00:00
CString ThemeManager : : GetPath ( ElementCategory category , CString sClassName , CString sElement , bool bOptional )
2003-01-19 03:26:05 +00:00
{
2004-01-24 21:16:07 +00:00
CString sFileName = ClassAndElementToFileName ( sClassName , sElement ) ;
2003-10-22 07:56:08 +00:00
map < CString , CString > & Cache = g_ThemePathCache [ category ] ;
{
map < CString , CString > : : const_iterator i ;
i = Cache . find ( sFileName ) ;
if ( i ! = Cache . end ( ) )
return i - > second ;
}
2003-01-19 03:26:05 +00:00
try_element_again :
2004-01-24 21:16:07 +00:00
2004-02-03 04:41:43 +00:00
// search the current theme
CString ret = GetPathToAndFallback ( m_sCurThemeName , category , sClassName , sElement ) ;
2003-04-12 17:39:27 +00:00
if ( ! ret . empty ( ) ) // we found something
2003-10-22 07:56:08 +00:00
{
Cache [ sFileName ] = ret ;
2003-04-12 17:39:27 +00:00
return ret ;
2003-10-22 07:56:08 +00:00
}
2003-07-22 07:47:27 +00:00
2004-02-03 04:41:43 +00:00
// search the base theme
ret = GetPathToAndFallback ( BASE_THEME_NAME , category , sClassName , sElement ) ;
2003-01-26 21:45:13 +00:00
if ( ! ret . empty ( ) ) // we found something
2003-10-22 07:56:08 +00:00
{
Cache [ sFileName ] = ret ;
2003-01-19 03:26:05 +00:00
return ret ;
2003-10-22 07:56:08 +00:00
}
2004-01-24 21:16:07 +00:00
if ( bOptional )
2003-10-22 07:56:08 +00:00
{
Cache [ sFileName ] = " " ;
2003-04-12 17:39:27 +00:00
return " " ;
2003-10-22 07:56:08 +00:00
}
2003-01-19 03:26:05 +00:00
2003-04-12 17:39:27 +00:00
CString sCategory = ELEMENT_CATEGORY_STRING [ category ] ;
2003-04-12 20:22:42 +00:00
2003-12-28 22:27:27 +00:00
/* We can't fall back on _missing in Other: the file types are unknown. */
2004-02-03 04:41:43 +00:00
CString sMessage = " The theme element \" " + sCategory + " / " + sFileName + " \" is missing. " ;
2003-12-28 22:27:27 +00:00
ArchHooks : : MessageBoxResult res ;
if ( category ! = Other )
res = HOOKS - > MessageBoxAbortRetryIgnore ( sMessage , " MissingThemeElement " ) ;
else
res = HOOKS - > MessageBoxRetryCancel ( sMessage , " MissingThemeElement " ) ;
switch ( res )
2003-01-19 03:26:05 +00:00
{
2003-11-15 06:08:13 +00:00
case ArchHooks : : retry :
2003-07-03 08:12:06 +00:00
FlushDirCache ( ) ;
2004-02-01 03:14:37 +00:00
ReloadMetrics ( ) ;
2003-01-19 03:26:05 +00:00
goto try_element_again ;
2003-11-17 03:37:51 +00:00
case ArchHooks : : ignore :
LOG - > Warn (
2003-12-10 09:44:16 +00:00
" Theme element '%s/%s' could not be found in '%s' or '%s'. " ,
2003-11-17 03:37:51 +00:00
sCategory . c_str ( ) ,
sFileName . c_str ( ) ,
GetThemeDirFromName ( m_sCurThemeName ) . c_str ( ) ,
GetThemeDirFromName ( BASE_THEME_NAME ) . c_str ( ) ) ;
/* Err? */
if ( sFileName = = " _missing " )
RageException : : Throw ( " '_missing' isn't present in '%s%s' " , GetThemeDirFromName ( BASE_THEME_NAME ) . c_str ( ) , sCategory . c_str ( ) ) ;
2004-02-14 01:16:04 +00:00
Cache [ sFileName ] = GetPath ( category , " " , " _missing " ) ;
2003-11-17 03:37:51 +00:00
return Cache [ sFileName ] ;
2003-12-28 22:27:27 +00:00
/* XXX: "abort" and "cancel" are synonyms; merge */
2003-11-17 03:37:51 +00:00
case ArchHooks : : abort :
2003-12-28 22:27:27 +00:00
case ArchHooks : : cancel :
2003-12-10 09:44:16 +00:00
RageException : : Throw ( " Theme element '%s/%s' could not be found in '%s' or '%s'. " ,
2003-04-25 00:01:35 +00:00
sCategory . c_str ( ) ,
sFileName . c_str ( ) ,
GetThemeDirFromName ( m_sCurThemeName ) . c_str ( ) ,
GetThemeDirFromName ( BASE_THEME_NAME ) . c_str ( ) ) ;
2003-11-15 06:08:13 +00:00
default :
ASSERT ( 0 ) ;
2003-11-17 03:37:51 +00:00
return " " ;
2003-01-19 03:26:05 +00:00
}
}
2002-08-13 23:26:46 +00:00
2003-08-19 08:01:15 +00:00
CString ThemeManager : : GetMetricsIniPath ( CString sThemeName )
2002-08-13 23:26:46 +00:00
{
2003-08-19 08:01:15 +00:00
return GetThemeDirFromName ( sThemeName ) + METRICS_FILE ;
2002-08-13 23:26:46 +00:00
}
2003-03-24 21:37:13 +00:00
bool ThemeManager : : HasMetric ( CString sClassName , CString sValueName )
{
CString sThrowAway ;
2004-02-15 01:32:12 +00:00
return GetMetricRaw ( sClassName , sValueName , sThrowAway ) ;
2003-03-24 21:37:13 +00:00
}
2003-11-05 04:56:41 +00:00
void ThemeManager : : ReloadMetricsIfNecessary ( )
{
//
// reload metrics if file has changed
//
CString sCurMetricPath = GetMetricsIniPath ( m_sCurThemeName ) ;
CString sDefaultMetricPath = GetMetricsIniPath ( BASE_THEME_NAME ) ;
if ( m_uHashForCurThemeMetrics ! = GetHashForFile ( sCurMetricPath ) | |
m_uHashForBaseThemeMetrics ! = GetHashForFile ( sDefaultMetricPath ) )
{
2003-11-07 20:43:17 +00:00
ReloadMetrics ( ) ;
2003-11-05 04:56:41 +00:00
}
2003-11-07 20:43:17 +00:00
}
void ThemeManager : : ReloadMetrics ( )
{
SwitchThemeAndLanguage ( m_sCurThemeName , m_sCurLanguage ) ; // force a reload of the metrics cache
2003-12-10 06:07:15 +00:00
if ( SCREENMAN )
SCREENMAN - > SystemMessage ( " Reloaded metrics " ) ;
2003-11-05 04:56:41 +00:00
//
// clear theme path cache
//
for ( int i = 0 ; i < NUM_ELEMENT_CATEGORIES ; + + i )
g_ThemePathCache [ i ] . clear ( ) ;
}
2004-03-20 10:24:42 +00:00
bool ThemeManager : : GetMetricRaw ( CString sClassName , CString sValueName , CString & ret , int level )
2004-02-15 01:32:12 +00:00
{
2004-03-20 10:24:42 +00:00
if ( level > 100 )
RageException : : Throw ( " Infinite recursion looking up theme metric \" %s::%s \" " , sClassName . c_str ( ) , sValueName . c_str ( ) ) ;
2004-03-20 03:02:12 +00:00
2004-03-20 10:24:42 +00:00
CString sFallback ;
2004-03-20 03:02:12 +00:00
if ( m_pIniCurMetrics - > GetValue ( sClassName , sValueName , ret ) )
return true ;
if ( m_pIniCurMetrics - > GetValue ( sClassName , " Fallback " , sFallback ) )
2004-02-15 21:39:15 +00:00
{
2004-03-20 10:24:42 +00:00
if ( GetMetricRaw ( sFallback , sValueName , ret , level + 1 ) )
2004-02-15 21:39:15 +00:00
return true ;
2004-03-20 03:02:12 +00:00
}
2004-02-15 01:32:12 +00:00
2004-03-20 03:02:12 +00:00
if ( m_pIniBaseMetrics - > GetValue ( sClassName , sValueName , ret ) )
return true ;
if ( m_pIniBaseMetrics - > GetValue ( sClassName , " Fallback " , sFallback ) )
{
2004-03-20 10:24:42 +00:00
if ( GetMetricRaw ( sFallback , sValueName , ret , level + 1 ) )
2004-03-20 03:02:12 +00:00
return true ;
2004-02-15 21:39:15 +00:00
}
2004-03-20 03:02:12 +00:00
return false ;
2004-02-15 01:32:12 +00:00
}
2003-03-18 21:41:17 +00:00
CString ThemeManager : : GetMetricRaw ( CString sClassName , CString sValueName )
2002-08-13 23:26:46 +00:00
{
2002-08-22 09:31:32 +00:00
try_metric_again :
2003-11-05 05:17:56 +00:00
2004-02-15 01:32:12 +00:00
CString ret ;
if ( ThemeManager : : GetMetricRaw ( sClassName , sValueName , ret ) )
return ret ;
2002-08-13 23:26:46 +00:00
2004-01-24 21:16:07 +00:00
2003-11-15 06:08:13 +00:00
CString sMessage = ssprintf ( " The theme metric '%s-%s' is missing. Correct this and click Retry, or Cancel to break. " , sClassName . c_str ( ) , sValueName . c_str ( ) ) ;
switch ( HOOKS - > MessageBoxAbortRetryIgnore ( sMessage ) )
2003-11-05 05:17:56 +00:00
{
2003-11-15 06:08:13 +00:00
case ArchHooks : : abort :
break ; // fall through
case ArchHooks : : retry :
FlushDirCache ( ) ;
ReloadMetrics ( ) ;
goto try_metric_again ;
case ArchHooks : : ignore :
return " " ;
default :
ASSERT ( 0 ) ;
2003-11-05 05:17:56 +00:00
}
2002-08-22 09:31:32 +00:00
2004-02-15 01:32:12 +00:00
CString sCurMetricPath = GetMetricsIniPath ( m_sCurThemeName ) ;
CString sDefaultMetricPath = GetMetricsIniPath ( BASE_THEME_NAME ) ;
2002-12-21 19:34:02 +00:00
RageException : : Throw ( " Theme metric '%s : %s' could not be found in '%s' or '%s'. " ,
2003-04-25 00:01:35 +00:00
sClassName . c_str ( ) ,
sValueName . c_str ( ) ,
sCurMetricPath . c_str ( ) ,
sDefaultMetricPath . c_str ( )
2002-08-13 23:26:46 +00:00
) ;
}
2003-03-18 21:41:17 +00:00
/* Get a string metric. */
CString ThemeManager : : GetMetric ( CString sClassName , CString sValueName )
{
CString sValue = GetMetricRaw ( sClassName , sValueName ) ;
// "::" means newline since you can't use line breaks in an ini file.
sValue . Replace ( " :: " , " \n " ) ;
/* XXX: add a parameter to turn this off if there are some metrics where
* we don't want markers */
FontCharAliases : : ReplaceMarkers ( sValue ) ;
return sValue ;
}
2002-09-17 23:02:37 +00:00
int ThemeManager : : GetMetricI ( CString sClassName , CString sValueName )
2002-08-13 23:26:46 +00:00
{
2003-03-18 21:41:17 +00:00
return atoi ( GetMetricRaw ( sClassName , sValueName ) ) ;
2002-08-13 23:26:46 +00:00
}
2002-09-17 23:02:37 +00:00
float ThemeManager : : GetMetricF ( CString sClassName , CString sValueName )
2002-08-13 23:26:46 +00:00
{
2003-03-18 21:41:17 +00:00
return ( float ) atof ( GetMetricRaw ( sClassName , sValueName ) ) ;
2002-08-13 23:26:46 +00:00
}
2004-05-23 02:27:51 +00:00
// #include "LuaHelpers.h"
2002-09-17 23:02:37 +00:00
bool ThemeManager : : GetMetricB ( CString sClassName , CString sValueName )
2002-08-13 23:26:46 +00:00
{
2004-05-23 02:27:51 +00:00
// const CString str = GetMetricRaw( sClassName,sValueName );
// if( str == "0" )
// return false; /* optimization */
// if( str == "1" )
// return true; /* optimization */
// return Lua::RunExpression( str );
2003-03-18 21:41:17 +00:00
return atoi ( GetMetricRaw ( sClassName , sValueName ) ) ! = 0 ;
2002-08-13 23:26:46 +00:00
}
2002-10-28 05:30:45 +00:00
RageColor ThemeManager : : GetMetricC ( CString sClassName , CString sValueName )
2002-08-13 23:26:46 +00:00
{
2003-11-18 04:06:39 +00:00
RageColor ret ( 1 , 1 , 1 , 1 ) ;
if ( ! ret . FromString ( GetMetricRaw ( sClassName , sValueName ) ) )
LOG - > Warn ( " The color value '%s' for NoteSkin metric '%s : %s' is invalid. " , GetMetricRaw ( sClassName , sValueName ) . c_str ( ) , sClassName . c_str ( ) , sValueName . c_str ( ) ) ;
return ret ;
2002-08-13 23:26:46 +00:00
}
2003-04-13 04:50:08 +00:00
void ThemeManager : : NextTheme ( )
{
CStringArray as ;
GetThemeNames ( as ) ;
2003-04-14 04:35:19 +00:00
unsigned i ;
for ( i = 0 ; i < as . size ( ) ; i + + )
2003-04-13 04:50:08 +00:00
if ( as [ i ] . CompareNoCase ( m_sCurThemeName ) = = 0 )
break ;
int iNewIndex = ( i + 1 ) % as . size ( ) ;
2003-08-19 08:01:15 +00:00
SwitchThemeAndLanguage ( as [ iNewIndex ] , m_sCurLanguage ) ;
}
void ThemeManager : : GetLanguagesForTheme ( CString sThemeName , CStringArray & asLanguagesOut )
{
CString sLanguageDir = GetThemeDirFromName ( sThemeName ) + LANGUAGES_SUBDIR ;
CStringArray as ;
GetDirListing ( sLanguageDir + " *.ini " , as ) ;
// stip out metrics.ini
for ( int i = as . size ( ) - 1 ; i > = 0 ; i - - )
{
if ( as [ i ] . CompareNoCase ( METRICS_FILE ) = = 0 )
as . erase ( as . begin ( ) + i ) ;
// strip ".ini"
as [ i ] = as [ i ] . Left ( as [ i ] . size ( ) - 4 ) ;
}
asLanguagesOut = as ;
}
CString ThemeManager : : GetLanguageIniPath ( CString sThemeName , CString sLanguage )
{
return GetThemeDirFromName ( sThemeName ) + LANGUAGES_SUBDIR + sLanguage + " .ini " ;
2003-04-14 04:35:19 +00:00
}
2004-01-24 21:16:07 +00:00
// TODO: remove these and update the places that use them
2004-02-14 01:16:04 +00:00
CString ThemeManager : : GetPathToB ( CString sFileName , bool bOptional ) { CString sClassName , sElement ; FileNameToClassAndElement ( sFileName , sClassName , sElement ) ; return GetPathB ( sClassName , sElement , bOptional ) ; }
CString ThemeManager : : GetPathToF ( CString sFileName , bool bOptional ) { CString sClassName , sElement ; FileNameToClassAndElement ( sFileName , sClassName , sElement ) ; return GetPathF ( sClassName , sElement , bOptional ) ; }
CString ThemeManager : : GetPathToG ( CString sFileName , bool bOptional ) { CString sClassName , sElement ; FileNameToClassAndElement ( sFileName , sClassName , sElement ) ; return GetPathG ( sClassName , sElement , bOptional ) ; }
CString ThemeManager : : GetPathToN ( CString sFileName , bool bOptional ) { CString sClassName , sElement ; FileNameToClassAndElement ( sFileName , sClassName , sElement ) ; return GetPathN ( sClassName , sElement , bOptional ) ; }
CString ThemeManager : : GetPathToS ( CString sFileName , bool bOptional ) { CString sClassName , sElement ; FileNameToClassAndElement ( sFileName , sClassName , sElement ) ; return GetPathS ( sClassName , sElement , bOptional ) ; }
CString ThemeManager : : GetPathToO ( CString sFileName , bool bOptional ) { CString sClassName , sElement ; FileNameToClassAndElement ( sFileName , sClassName , sElement ) ; return GetPathO ( sClassName , sElement , bOptional ) ; }