2003-02-16 03:59:37 +00:00
# include "global.h"
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"
2004-07-25 17:07:32 +00:00
# include "Game.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"
2004-06-10 22:47:51 +00:00
# include "arch/Dialog/Dialog.h"
2003-07-22 07:47:27 +00:00
# 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"
2004-09-21 06:07:12 +00:00
# include "Foreach.h"
# include "ThemeMetric.h"
2005-01-24 02:26:55 +00:00
# include "LuaManager.h"
2005-01-09 01:31:06 +00:00
# include "ScreenDimensions.h"
2005-01-26 11:21:43 +00:00
# include "Command.h"
2002-01-16 10:01:32 +00:00
ThemeManager * THEME = NULL ; // global object accessable from anywhere in the program
2005-02-28 04:10:01 +00:00
static const CString ElementCategoryNames [ NUM_ELEMENT_CATEGORIES ] = {
2003-04-12 17:39:27 +00:00
" BGAnimations " ,
" Fonts " ,
" Graphics " ,
" Numbers " ,
2003-09-11 23:21:33 +00:00
" Sounds " ,
" Other "
2003-04-12 17:39:27 +00:00
} ;
2005-03-05 21:50:33 +00:00
XToString ( ElementCategory , NUM_ELEMENT_CATEGORIES ) ;
2005-02-28 04:10:01 +00:00
StringToX ( ElementCategory ) ;
static void LuaElementCategory ( lua_State * L )
{
FOREACH_ElementCategory ( ec )
{
CString s = ElementCategoryNames [ ec ] ;
s . MakeUpper ( ) ;
LUA - > SetGlobal ( " ELEMENT_CATEGORY_ " + s , ec ) ;
}
}
REGISTER_WITH_LUA_FUNCTION ( LuaElementCategory ) ;
const CString BASE_THEME_NAME = " default " ;
const CString LANGUAGES_SUBDIR = " Languages/ " ;
const CString BASE_LANGUAGE = " english " ;
const CString THEMES_DIR = " Themes/ " ;
const CString METRICS_FILE = " metrics.ini " ;
2002-05-19 01:59:48 +00:00
2004-08-10 04:33:36 +00:00
struct Theme
{
CString sThemeName ;
2005-01-07 14:28:00 +00:00
IniFile * iniMetrics ; // pointer because the copy constructor isn't a deep copy
2004-08-10 04:33:36 +00:00
} ;
// When looking for a metric or an element, search these from head to tail.
deque < Theme > g_vThemes ;
2004-09-21 06:07:12 +00:00
//
// For self-registering metrics
//
2005-02-05 11:21:13 +00:00
# include "SubscriptionManager.h"
2005-02-05 21:40:36 +00:00
template < >
2005-02-05 11:21:13 +00:00
set < IThemeMetric * > * SubscriptionManager < IThemeMetric > : : s_pSubscribers = NULL ;
2004-09-21 06:07:12 +00:00
void ThemeManager : : Subscribe ( IThemeMetric * p )
{
2005-02-05 11:21:13 +00:00
SubscriptionManager < IThemeMetric > : : Subscribe ( p ) ;
2005-01-05 04:31:36 +00:00
// It's ThemeManager's responsibility to make sure all of it's subscribers
// are updated with current data. If a metric is created after
// a theme is loaded, ThemeManager should update it right away (not just
// when the theme changes).
if ( THEME & & THEME - > GetCurThemeName ( ) . size ( ) )
p - > Read ( ) ;
2004-09-21 06:07:12 +00:00
}
2004-11-06 20:36:04 +00:00
void ThemeManager : : Unsubscribe ( IThemeMetric * p )
{
2005-02-05 11:21:13 +00:00
SubscriptionManager < IThemeMetric > : : Unsubscribe ( p ) ;
2004-11-06 20:36:04 +00:00
}
2004-09-21 06:07:12 +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 ] ;
2005-03-20 05:39:32 +00:00
void ThemeManager : : ClearThemePathCache ( )
{
for ( int i = 0 ; i < NUM_ELEMENT_CATEGORIES ; + + i )
g_ThemePathCache [ i ] . clear ( ) ;
}
2003-10-22 07:56:08 +00:00
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 ( )
{
2005-02-12 22:52:24 +00:00
THEME = this ; // so that we can Register THEME on construction
2004-09-16 22:53:40 +00:00
/* We don't have any theme loaded until SwitchThemeAndLanguage is called. */
m_sCurThemeName = " " ;
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 ( )
{
}
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
}
2004-11-06 06:34:21 +00:00
bool ThemeManager : : DoesThemeExist ( const 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 ;
2004-08-13 02:13:39 +00:00
/* XXX: this should use FallbackTheme */
2003-08-19 08:01:15 +00:00
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 ( ) ) ;
}
2004-11-06 06:34:21 +00:00
bool ThemeManager : : DoesLanguageExist ( const CString & sLanguage )
2003-08-19 08:01:15 +00:00
{
CStringArray asLanguages ;
GetLanguages ( asLanguages ) ;
for ( unsigned i = 0 ; i < asLanguages . size ( ) ; i + + )
if ( sLanguage . CompareNoCase ( asLanguages [ i ] ) = = 0 )
return true ;
return false ;
}
2004-11-06 06:34:21 +00:00
void ThemeManager : : LoadThemeRecursive ( deque < Theme > & theme , const CString & sThemeName )
2004-08-10 04:33:36 +00:00
{
static int depth = 0 ;
2004-08-13 02:13:39 +00:00
static bool loaded_base = false ;
2004-08-10 04:33:36 +00:00
depth + + ;
ASSERT_M ( depth < 20 , " Circular NoteSkin fallback references detected. " ) ;
2004-08-13 02:13:39 +00:00
if ( ! sThemeName . CompareNoCase ( BASE_THEME_NAME ) )
loaded_base = true ;
2004-08-10 04:33:36 +00:00
Theme t ;
2005-01-07 14:28:00 +00:00
t . iniMetrics = new IniFile ;
2004-08-10 04:33:36 +00:00
t . sThemeName = sThemeName ;
2005-01-07 14:28:00 +00:00
t . iniMetrics - > ReadFile ( GetMetricsIniPath ( sThemeName ) ) ;
t . iniMetrics - > ReadFile ( GetLanguageIniPath ( sThemeName , BASE_LANGUAGE ) ) ;
2004-08-10 04:33:36 +00:00
if ( m_sCurLanguage . CompareNoCase ( BASE_LANGUAGE ) )
2005-01-07 14:28:00 +00:00
t . iniMetrics - > ReadFile ( GetLanguageIniPath ( sThemeName , m_sCurLanguage ) ) ;
2004-08-10 04:33:36 +00:00
2004-08-13 02:13:39 +00:00
/* Read the fallback theme. If no fallback theme is specified, and we havn't
* already loaded it, fall back on BASE_THEME_NAME. That way, default theme
* fallbacks can be disabled with "FallbackTheme=". */
2004-08-10 04:33:36 +00:00
CString sFallback ;
2005-01-07 14:28:00 +00:00
if ( ! t . iniMetrics - > GetValue ( " Global " , " FallbackTheme " , sFallback ) )
2004-08-13 02:13:39 +00:00
{
if ( sThemeName . CompareNoCase ( BASE_THEME_NAME ) & & ! loaded_base )
sFallback = BASE_THEME_NAME ;
}
if ( ! sFallback . empty ( ) )
2004-08-10 04:33:36 +00:00
LoadThemeRecursive ( theme , sFallback ) ;
g_vThemes . push_front ( t ) ;
2004-08-13 02:13:39 +00:00
if ( ! sThemeName . CompareNoCase ( sThemeName ) )
loaded_base = false ;
2004-08-10 04:33:36 +00:00
depth - - ;
}
2004-11-06 06:34:21 +00:00
void ThemeManager : : SwitchThemeAndLanguage ( const CString & sThemeName , const CString & sLanguage )
2002-07-23 01:41:40 +00:00
{
2004-11-06 06:34:21 +00:00
CString sTheme = sThemeName ;
CString sLang = sLanguage ;
if ( ! DoesThemeExist ( sTheme ) )
sTheme = BASE_THEME_NAME ;
if ( ! DoesLanguageExist ( sLang ) )
sLang = BASE_LANGUAGE ;
2004-09-16 22:45:55 +00:00
LOG - > Trace ( " ThemeManager::SwitchThemeAndLanguage: \" %s \" , \" %s \" " ,
2004-11-06 06:34:21 +00:00
sTheme . c_str ( ) , sLang . c_str ( ) ) ;
2004-09-16 22:45:55 +00:00
2004-11-06 06:34:21 +00:00
if ( sTheme = = m_sCurThemeName & & sLang = = m_sCurLanguage )
2004-09-16 22:45:55 +00:00
return ;
2004-11-06 06:34:21 +00:00
m_sCurThemeName = sTheme ;
m_sCurLanguage = sLang ;
2003-08-19 08:01:15 +00:00
2003-12-01 00:27:55 +00:00
// clear theme path cache
2004-09-21 07:53:39 +00:00
for ( int i = 0 ; i < NUM_ELEMENT_CATEGORIES ; + + i )
2003-12-01 00:27:55 +00:00
g_ThemePathCache [ i ] . clear ( ) ;
2004-08-10 04:33:36 +00:00
g_vThemes . clear ( ) ;
2004-07-21 23:42:52 +00:00
2004-08-10 04:33:36 +00:00
// load current theme
2004-08-13 02:13:39 +00:00
LoadThemeRecursive ( g_vThemes , m_sCurThemeName ) ;
2004-08-10 04:33:36 +00:00
2004-04-30 07:26:06 +00:00
CString sMetric ;
2004-09-21 07:53:39 +00:00
for ( int i = 0 ; GetCommandlineArgument ( " metric " , & sMetric , i ) ; + + i )
2004-04-30 07:26:06 +00:00
{
/* 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 ( ) ) ;
2005-01-07 14:28:00 +00:00
g_vThemes . front ( ) . iniMetrics - > SetValue ( sBits [ 0 ] , sBits [ 1 ] , sBits [ 2 ] ) ;
2004-04-30 07:26:06 +00:00
}
2004-11-06 06:34:21 +00:00
LOG - > MapLog ( " theme " , " Theme: %s " , sTheme . c_str ( ) ) ;
LOG - > MapLog ( " language " , " Language: %s " , sLang . c_str ( ) ) ;
2004-09-16 22:45:55 +00:00
// reload common sounds
if ( SCREENMAN ! = NULL )
SCREENMAN - > ThemeChanged ( ) ;
2004-09-21 06:07:12 +00:00
2004-11-11 22:31:55 +00:00
/* Lua globals can use metrics which are cached, and vice versa. Update Lua
* globals first; it's Lua's job to explicitly update cached metrics that it
* uses. */
2005-01-09 01:31:06 +00:00
UpdateLuaGlobals ( ) ;
2004-11-11 22:31:55 +00:00
2004-09-21 06:07:12 +00:00
// reload subscribers
2005-02-05 11:21:13 +00:00
FOREACHS_CONST ( IThemeMetric * , * SubscriptionManager < IThemeMetric > : : s_pSubscribers , p )
( * p ) - > Read ( ) ;
2002-03-19 07:09:49 +00:00
}
2005-03-18 22:09:10 +00:00
void ThemeManager : : RunLuaScripts ( const CString & sMask )
{
/* Run all script files with the given mask in Lua for all themes. Start
* from the deepest fallback theme and work outwards. */
deque < Theme > : : const_iterator iter = g_vThemes . end ( ) ;
do
{
- - iter ;
const CString & sThemeDir = GetThemeDirFromName ( iter - > sThemeName ) ;
CStringArray asElementPaths ;
GetDirListing ( sThemeDir + " Scripts/ " + sMask , asElementPaths , false , true ) ;
for ( unsigned i = 0 ; i < asElementPaths . size ( ) ; + + i )
{
const CString & sPath = asElementPaths [ i ] ;
LOG - > Trace ( " Loading \" %s \" ... " , sPath . c_str ( ) ) ;
LUA - > RunScriptFile ( sPath ) ;
}
}
while ( iter ! = g_vThemes . begin ( ) ) ;
}
2005-01-09 01:31:06 +00:00
void ThemeManager : : UpdateLuaGlobals ( )
{
2005-03-18 22:09:10 +00:00
/* Ugly: we need Serialize.lua to be loaded in order to be able to ResetState,
* but everything else should be able to depend on globals being set. */
RunLuaScripts ( " Serialize.lua " ) ;
2005-01-24 03:05:37 +00:00
LUA - > ResetState ( ) ;
2005-01-09 01:31:06 +00:00
/* Important: explicitly refresh cached metrics that we use. */
THEME_SCREEN_WIDTH . Read ( ) ;
THEME_SCREEN_HEIGHT . Read ( ) ;
2005-01-19 23:01:53 +00:00
LUA - > SetGlobal ( " SCREEN_WIDTH " , ( int ) SCREEN_WIDTH ) ;
LUA - > SetGlobal ( " SCREEN_HEIGHT " , ( int ) SCREEN_HEIGHT ) ;
LUA - > SetGlobal ( " SCREEN_LEFT " , ( int ) SCREEN_LEFT ) ;
LUA - > SetGlobal ( " SCREEN_RIGHT " , ( int ) SCREEN_RIGHT ) ;
LUA - > SetGlobal ( " SCREEN_TOP " , ( int ) SCREEN_TOP ) ;
LUA - > SetGlobal ( " SCREEN_BOTTOM " , ( int ) SCREEN_BOTTOM ) ;
LUA - > SetGlobal ( " SCREEN_CENTER_X " , ( int ) SCREEN_CENTER_X ) ;
LUA - > SetGlobal ( " SCREEN_CENTER_Y " , ( int ) SCREEN_CENTER_Y ) ;
2005-01-19 23:36:15 +00:00
2005-03-18 22:09:10 +00:00
RunLuaScripts ( " *.lua " ) ;
2005-01-09 01:31:06 +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-11-06 06:34:21 +00:00
CString ThemeManager : : GetPathToAndFallback ( const CString & sThemeName , ElementCategory category , const CString & sClassName , const CString & sElement )
2004-02-03 04:41:43 +00:00
{
2004-11-06 06:34:21 +00:00
CString sClass = sClassName ;
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
2004-11-06 06:34:21 +00:00
CString sRet = GetPathToRaw ( sThemeName , category , sClass , 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-11-06 06:34:21 +00:00
GetMetricRaw ( sClass , " Fallback " , sFallback ) ;
2004-03-20 03:02:12 +00:00
if ( sFallback . empty ( ) )
2004-02-15 21:39:15 +00:00
return " " ;
2004-11-06 06:34:21 +00:00
sClass = 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 \" " ,
2004-11-06 06:34:21 +00:00
sThemeName . c_str ( ) , sClass . c_str ( ) ) ;
2004-02-03 04:41:43 +00:00
}
2005-01-20 19:16:47 +00:00
CString ThemeManager : : GetPathToRaw ( const CString & sThemeName_ , ElementCategory category , const CString & sClassName_ , const CString & sElement_ )
2003-01-05 07:55:31 +00:00
{
2005-01-20 19:16:47 +00:00
/* Ugly: the parameters to this function may be a reference into g_vThemes, or something
* else that might suddenly go away when we call ReloadMetrics. */
const CString sThemeName = sThemeName_ ;
const CString sClassName = sClassName_ ;
const CString sElement = sElement_ ;
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 ) ;
2005-02-28 04:10:01 +00:00
const CString & sCategory = ElementCategoryToString ( 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
if ( bLookingForSpecificFile )
{
2005-03-12 21:21:36 +00:00
GetDirListing ( sThemeDir + sCategory + " / " + ClassAndElementToFileName ( sClassName , sElement ) , asElementPaths , false , true ) ;
2003-04-12 17:39:27 +00:00
}
else // look for all files starting with sFileName that have types we can use
{
/* First, look for redirs. */
2005-03-12 21:21:36 +00:00
GetDirListing ( sThemeDir + sCategory + " / " + ClassAndElementToFileName ( sClassName , sElement ) + " *.redir " ,
2003-04-12 17:39:27 +00:00
asElementPaths , false , true ) ;
2003-10-19 23:00:11 +00:00
CStringArray asPaths ;
2005-03-12 21:21:36 +00:00
GetDirListing ( sThemeDir + sCategory + " / " + ClassAndElementToFileName ( sClassName , sElement ) + " * " ,
asPaths , false , true ) ;
2003-10-19 23:00:11 +00:00
for ( unsigned p = 0 ; p < asPaths . size ( ) ; + + p )
{
2005-01-07 22:01:57 +00:00
static const char * masks [ NUM_ELEMENT_CATEGORIES ] [ 13 ] = {
2005-03-20 07:09:22 +00:00
{ " " , " actor " , " xml " , NULL } ,
2003-10-19 23:00:11 +00:00
{ " ini " , NULL } ,
2005-01-07 22:01:57 +00:00
{ " xml " , " 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 } ,
2005-03-13 08:40:11 +00:00
{ " * " , NULL } ,
2003-10-19 23:00:11 +00:00
} ;
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 ;
2005-03-13 08:40:11 +00:00
if ( ext = = asset_masks [ i ] | | ! strcmp ( asset_masks [ i ] , " * " ) )
2003-10-19 23:00:11 +00:00
{
asElementPaths . push_back ( asPaths [ p ] ) ;
break ;
}
}
}
2005-02-28 04:10:01 +00:00
if ( category = = ELEMENT_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-07-24 23:26:34 +00:00
// HACK: have Fonts fall back to Numbers. Eventually Numbers will be removed.
2005-02-28 04:10:01 +00:00
if ( category = = ELEMENT_CATEGORY_FONTS )
return GetPathToRaw ( sThemeName , ELEMENT_CATEGORY_NUMBERS , 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
2004-06-10 22:47:51 +00:00
switch ( Dialog : : AbortRetryIgnore ( message ) )
2003-11-17 03:37:51 +00:00
{
2004-06-10 22:47:51 +00:00
case Dialog : : abort :
2003-11-17 03:37:51 +00:00
RageException : : Throw ( message ) ;
break ;
2004-06-10 22:47:51 +00:00
case Dialog : : retry :
2004-02-01 03:14:37 +00:00
FlushDirCache ( ) ;
ReloadMetrics ( ) ;
2003-11-15 06:08:13 +00:00
goto try_element_again ;
2004-06-10 22:47:51 +00:00
case Dialog : : ignore :
2003-11-17 03:37:51 +00:00
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 */
2005-02-28 04:10:01 +00:00
if ( category = = ELEMENT_CATEGORY_FONTS )
2003-11-17 03:37:51 +00:00
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 ( ) )
2005-01-13 09:53:36 +00:00
{
2003-11-17 03:37:51 +00:00
return sNewPath ;
2005-01-13 09:53:36 +00:00
}
2003-11-17 03:37:51 +00:00
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
2004-06-10 22:47:51 +00:00
if ( Dialog : : AbortRetryIgnore ( message ) = = Dialog : : retry )
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
2005-01-20 19:16:47 +00:00
CString ThemeManager : : GetPath ( ElementCategory category , const CString & sClassName_ , const CString & sElement_ , bool bOptional )
2003-01-19 03:26:05 +00:00
{
2005-01-20 19:16:47 +00:00
/* Ugly: the parameters to this function may be a reference into g_vThemes, or something
* else that might suddenly go away when we call ReloadMetrics. */
const CString sClassName = sClassName_ ;
const CString sElement = sElement_ ;
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-08-10 04:33:36 +00:00
for ( deque < Theme > : : const_iterator iter = g_vThemes . begin ( ) ;
iter ! = g_vThemes . end ( ) ;
iter + + )
2003-10-22 07:56:08 +00:00
{
2004-08-10 04:33:36 +00:00
// search the current theme
CString ret = GetPathToAndFallback ( iter - > sThemeName , category , sClassName , sElement ) ;
if ( ! ret . empty ( ) ) // we found something
{
Cache [ sFileName ] = ret ;
return ret ;
}
2003-10-22 07:56:08 +00:00
}
2003-07-22 07:47:27 +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
2005-02-28 04:10:01 +00:00
const CString & sCategory = ElementCategoryToString ( 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. " ;
2004-06-10 22:47:51 +00:00
Dialog : : Result res ;
2005-02-28 04:10:01 +00:00
if ( category ! = ELEMENT_CATEGORY_OTHER )
2004-06-10 22:47:51 +00:00
res = Dialog : : AbortRetryIgnore ( sMessage , " MissingThemeElement " ) ;
2003-12-28 22:27:27 +00:00
else
2005-01-20 19:40:24 +00:00
res = Dialog : : AbortRetry ( sMessage , " MissingThemeElement " ) ;
2003-12-28 22:27:27 +00:00
switch ( res )
2003-01-19 03:26:05 +00:00
{
2004-06-10 22:47:51 +00:00
case Dialog : : 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 ;
2004-06-10 22:47:51 +00:00
case Dialog : : ignore :
2003-11-17 03:37:51 +00:00
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 ] ;
2004-06-10 22:47:51 +00:00
case Dialog : : abort :
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
2004-11-06 06:34:21 +00:00
CString ThemeManager : : GetMetricsIniPath ( const 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
}
2004-11-06 06:34:21 +00:00
bool ThemeManager : : HasMetric ( const CString & sClassName , const CString & sValueName )
2003-03-24 21:37:13 +00:00
{
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-07 20:43:17 +00:00
void ThemeManager : : ReloadMetrics ( )
{
2004-09-16 22:45:55 +00:00
// force a reload of the metrics cache
2004-11-06 06:34:21 +00:00
const CString sThemeName = m_sCurThemeName ;
const CString sCurLanguage = m_sCurLanguage ;
2004-09-16 22:45:55 +00:00
m_sCurThemeName = " " ;
m_sCurLanguage = " " ;
SwitchThemeAndLanguage ( sThemeName , sCurLanguage ) ;
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-11-06 06:34:21 +00:00
bool ThemeManager : : GetMetricRaw ( const CString & sClassName , const 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
2004-08-10 04:33:36 +00:00
for ( deque < Theme > : : const_iterator iter = g_vThemes . begin ( ) ;
iter ! = g_vThemes . end ( ) ;
iter + + )
2004-02-15 21:39:15 +00:00
{
2005-01-07 14:28:00 +00:00
if ( iter - > iniMetrics - > GetValue ( sClassName , sValueName , ret ) )
2004-07-23 04:33:05 +00:00
return true ;
2005-01-07 14:28:00 +00:00
if ( iter - > iniMetrics - > GetValue ( sClassName , " Fallback " , sFallback ) )
2004-08-10 04:33:36 +00:00
{
if ( GetMetricRaw ( sFallback , sValueName , ret , level + 1 ) )
return true ;
}
2004-07-23 04:33:05 +00:00
}
2004-03-20 03:02:12 +00:00
return false ;
2004-02-15 01:32:12 +00:00
}
2005-01-20 19:16:47 +00:00
CString ThemeManager : : GetMetricRaw ( const CString & sClassName_ , const CString & sValueName_ )
2002-08-13 23:26:46 +00:00
{
2005-01-20 19:16:47 +00:00
/* Ugly: the parameters to this function may be a reference into g_vThemes, or something
* else that might suddenly go away when we call ReloadMetrics. */
const CString sClassName = sClassName_ ;
const CString sValueName = sValueName_ ;
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 ( ) ) ;
2004-06-10 22:47:51 +00:00
switch ( Dialog : : AbortRetryIgnore ( sMessage ) )
2003-11-05 05:17:56 +00:00
{
2004-06-10 22:47:51 +00:00
case Dialog : : abort :
2003-11-15 06:08:13 +00:00
break ; // fall through
2004-06-10 22:47:51 +00:00
case Dialog : : retry :
2003-11-15 06:08:13 +00:00
FlushDirCache ( ) ;
ReloadMetrics ( ) ;
goto try_metric_again ;
2004-06-10 22:47:51 +00:00
case Dialog : : ignore :
2003-11-15 06:08:13 +00:00
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 ) ;
2005-02-16 23:00:09 +00:00
CString sError = ssprintf ( " 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
) ;
2005-02-16 23:00:09 +00:00
RageException : : Throw ( sError ) ;
2002-08-13 23:26:46 +00:00
}
2003-03-18 21:41:17 +00:00
/* Get a string metric. */
2004-11-06 06:34:21 +00:00
CString ThemeManager : : GetMetric ( const CString & sClassName , const CString & sValueName )
2003-03-18 21:41:17 +00:00
{
CString sValue = GetMetricRaw ( sClassName , sValueName ) ;
2005-01-16 20:36:27 +00:00
EvaluateString ( sValue ) ;
2003-03-18 21:41:17 +00:00
return sValue ;
}
2005-01-16 20:36:27 +00:00
void ThemeManager : : EvaluateString ( CString & sText )
{
/* If the string begins with an @, treat it as a raw Lua expression, and don't do any
* other filtering. (XXX: maybe we should still do font aliases) */
2005-02-16 00:16:14 +00:00
if ( LUA - > RunAtExpressionS ( sText ) )
2005-01-16 20:36:27 +00:00
return ;
// "::" means newline since you can't use line breaks in an ini file.
// XXX: this makes it impossible to put a colon at the end of a line, eg: "Color:\nRed"
sText . Replace ( " :: " , " \n " ) ;
FontCharAliases : : ReplaceMarkers ( sText ) ;
}
2004-11-06 06:34:21 +00:00
int ThemeManager : : GetMetricI ( const CString & sClassName , const CString & sValueName )
2002-08-13 23:26:46 +00:00
{
2005-02-12 22:52:24 +00:00
CString sValue = GetMetric ( sClassName , sValueName ) ; // Use non-raw so that Lua expressions are allowed
return atoi ( sValue ) ;
2002-08-13 23:26:46 +00:00
}
2004-11-06 06:34:21 +00:00
float ThemeManager : : GetMetricF ( const CString & sClassName , const CString & sValueName )
2002-08-13 23:26:46 +00:00
{
2005-02-12 22:52:24 +00:00
CString sValue = GetMetric ( sClassName , sValueName ) ; // Use non-raw so that Lua expressions are allowed
2004-09-28 10:03:49 +00:00
2005-01-19 23:01:53 +00:00
LUA - > PrepareExpression ( sValue ) ;
2004-09-28 10:03:49 +00:00
2005-01-19 23:01:53 +00:00
return LUA - > RunExpressionF ( sValue ) ;
2002-08-13 23:26:46 +00:00
}
2005-01-24 02:26:55 +00:00
// #include "LuaManager.h"
2004-11-06 06:34:21 +00:00
bool ThemeManager : : GetMetricB ( const CString & sClassName , const CString & sValueName )
2002-08-13 23:26:46 +00:00
{
2005-02-12 22:52:24 +00:00
CString sValue = GetMetric ( sClassName , sValueName ) ; // Use non-raw so that Lua expressions are allowed
2004-12-06 06:41:31 +00:00
/* Watch out: "0" and "1" are not false and true in Lua (all string values are
* true). Make sure that we catch all values that are supposed to be simple
* booleans. */
TrimLeft ( sValue ) ;
TrimRight ( sValue ) ;
if ( sValue . Left ( 1 ) = = " 0 " )
2004-09-22 04:55:31 +00:00
return false ; /* optimization */
2004-12-06 06:41:31 +00:00
if ( sValue . Left ( 1 ) = = " 1 " )
2004-09-22 04:55:31 +00:00
return true ; /* optimization */
2004-11-06 06:00:58 +00:00
2005-01-19 23:01:53 +00:00
LUA - > PrepareExpression ( sValue ) ;
2004-11-06 06:00:58 +00:00
2005-01-19 23:01:53 +00:00
return LUA - > RunExpressionB ( sValue ) ;
2002-08-13 23:26:46 +00:00
}
2004-11-06 06:34:21 +00:00
RageColor ThemeManager : : GetMetricC ( const CString & sClassName , const CString & sValueName )
2002-08-13 23:26:46 +00:00
{
2005-02-12 22:52:24 +00:00
CString sValue = GetMetric ( sClassName , sValueName ) ; // Use non-raw so that Lua expressions are allowed
2003-11-18 04:06:39 +00:00
RageColor ret ( 1 , 1 , 1 , 1 ) ;
2005-02-12 22:52:24 +00:00
if ( ! ret . FromString ( sValue ) )
2005-02-15 01:53:30 +00:00
LOG - > Warn ( " The color value '%s' for metric '%s : %s' is invalid. " , sValue . c_str ( ) , sClassName . c_str ( ) , sValueName . c_str ( ) ) ;
2003-11-18 04:06:39 +00:00
return ret ;
2002-08-13 23:26:46 +00:00
}
2003-04-13 04:50:08 +00:00
2005-01-26 11:21:43 +00:00
Commands ThemeManager : : GetMetricM ( const CString & sClassName , const CString & sValueName )
2004-11-06 23:13:47 +00:00
{
2005-02-09 09:44:16 +00:00
CString sValue = GetMetric ( sClassName , sValueName ) ; // Use non-raw so that Lua expressions are allowed
return ParseCommands ( sValue ) ;
2004-11-06 23:13:47 +00:00
}
2005-01-26 11:21:43 +00:00
apActorCommands ThemeManager : : GetMetricA ( const CString & sClassName , const CString & sValueName )
{
2005-02-12 22:52:24 +00:00
CString sValue = GetMetric ( sClassName , sValueName ) ; // Use non-raw so that Lua expressions are allowed
2005-02-23 19:15:24 +00:00
return apActorCommands ( new ActorCommands ( sValue ) ) ;
2005-01-26 11:21:43 +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 ) ;
}
2004-11-06 06:34:21 +00:00
void ThemeManager : : GetLanguagesForTheme ( const CString & sThemeName , CStringArray & asLanguagesOut )
2003-08-19 08:01:15 +00:00
{
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 ;
}
2004-11-06 06:34:21 +00:00
CString ThemeManager : : GetLanguageIniPath ( const CString & sThemeName , const CString & sLanguage )
2003-08-19 08:01:15 +00:00
{
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-11-06 06:34:21 +00:00
CString ThemeManager : : GetPathToB ( const CString & sFileName , bool bOptional ) { CString sClassName , sElement ; FileNameToClassAndElement ( sFileName , sClassName , sElement ) ; return GetPathB ( sClassName , sElement , bOptional ) ; }
CString ThemeManager : : GetPathToF ( const CString & sFileName , bool bOptional ) { CString sClassName , sElement ; FileNameToClassAndElement ( sFileName , sClassName , sElement ) ; return GetPathF ( sClassName , sElement , bOptional ) ; }
CString ThemeManager : : GetPathToG ( const CString & sFileName , bool bOptional ) { CString sClassName , sElement ; FileNameToClassAndElement ( sFileName , sClassName , sElement ) ; return GetPathG ( sClassName , sElement , bOptional ) ; }
CString ThemeManager : : GetPathToS ( const CString & sFileName , bool bOptional ) { CString sClassName , sElement ; FileNameToClassAndElement ( sFileName , sClassName , sElement ) ; return GetPathS ( sClassName , sElement , bOptional ) ; }
CString ThemeManager : : GetPathToO ( const CString & sFileName , bool bOptional ) { CString sClassName , sElement ; FileNameToClassAndElement ( sFileName , sClassName , sElement ) ; return GetPathO ( sClassName , sElement , bOptional ) ; }
2004-06-08 01:24:17 +00:00
2004-07-19 08:05:14 +00:00
void ThemeManager : : GetModifierNames ( set < CString > & AddTo )
{
2004-08-10 04:33:36 +00:00
for ( deque < Theme > : : const_iterator iter = g_vThemes . begin ( ) ;
iter ! = g_vThemes . end ( ) ;
2004-08-13 02:13:39 +00:00
+ + iter )
2004-08-10 04:33:36 +00:00
{
2005-01-07 14:28:00 +00:00
const XNode * cur = iter - > iniMetrics - > GetChild ( " OptionNames " ) ;
2004-08-13 02:13:39 +00:00
if ( cur )
{
2005-01-07 14:28:00 +00:00
FOREACH_CONST_Attr ( cur , p )
AddTo . insert ( p - > m_sName ) ;
2004-08-13 02:13:39 +00:00
}
2004-08-10 04:33:36 +00:00
}
2004-07-19 08:05:14 +00:00
}
2005-01-26 11:21:43 +00:00
void ThemeManager : : GetMetric ( const CString & sClassName , const CString & sValueName , apActorCommands & valueOut )
2004-12-02 05:56:38 +00:00
{
valueOut = GetMetricA ( sClassName , sValueName ) ;
}
2005-02-17 06:09:08 +00:00
void ThemeManager : : GetMetric ( const CString & sClassName , const CString & sValueName , LuaExpression & valueOut )
{
CString sValue = GetMetricRaw ( sClassName , sValueName ) ;
2005-02-17 08:41:13 +00:00
valueOut . SetFromExpression ( " function(self) " + sValue + " end " ) ;
2005-02-17 06:09:08 +00:00
}
2005-02-12 22:52:24 +00:00
2005-03-13 20:44:26 +00:00
void ThemeManager : : GetMetricsThatBeginWith ( const CString & _sClassName , const CString & sValueName , set < CString > & vsValueNamesOut )
{
CString sClassName = _sClassName ;
while ( ! sClassName . empty ( ) )
{
// Iterate over themes in the chain.
for ( deque < Theme > : : const_iterator i = g_vThemes . begin ( ) ;
i ! = g_vThemes . end ( ) ;
+ + i )
{
const XNode * cur = i - > iniMetrics - > GetChild ( sClassName ) ;
if ( cur = = NULL )
continue ;
// Iterate over all metrics that match.
2005-03-14 00:38:51 +00:00
for ( XAttrs : : const_iterator j = cur - > m_attrs . lower_bound ( sValueName ) ; j ! = cur - > m_attrs . end ( ) ; j + + )
2005-03-13 20:44:26 +00:00
{
const CString & sv = j - > first ;
if ( sv . Left ( sValueName . size ( ) ) = = sValueName )
vsValueNamesOut . insert ( sv ) ;
2005-03-14 00:38:51 +00:00
else // we passed the last metric that matched sValueName
2005-03-13 20:44:26 +00:00
break ;
}
}
// put the fallback (if any) in sClassName
CString sFallback ;
if ( GetMetricRaw ( sClassName , " Fallback " , sFallback ) )
sClassName = sFallback ;
else
sClassName = " " ;
}
}
2005-02-12 22:52:24 +00:00
// lua start
# include "LuaBinding.h"
template < class T >
class LunaThemeManager : public Luna < T >
{
public :
LunaThemeManager ( ) { LUA - > Register ( Register ) ; }
static int GetMetric ( T * p , lua_State * L ) { lua_pushstring ( L , p - > GetMetric ( SArg ( 1 ) , SArg ( 2 ) ) ) ; return 1 ; }
2005-02-28 04:10:01 +00:00
static int GetPath ( T * p , lua_State * L ) { lua_pushstring ( L , p - > GetPath ( ( ElementCategory ) IArg ( 1 ) , SArg ( 2 ) , SArg ( 3 ) ) ) ; return 1 ; }
2005-02-12 22:52:24 +00:00
static void Register ( lua_State * L )
{
ADD_METHOD ( GetMetric )
2005-02-28 04:10:01 +00:00
ADD_METHOD ( GetPath )
2005-02-12 22:52:24 +00:00
Luna < T > : : Register ( L ) ;
2005-03-18 22:44:47 +00:00
// Add global singleton if constructed already. If it's not constructed yet,
// then we'll register it later when we reinit Lua just before
// initializing the display.
if ( THEME )
{
lua_pushstring ( L , " THEME " ) ;
THEME - > PushSelf ( LUA - > L ) ;
lua_settable ( L , LUA_GLOBALSINDEX ) ;
}
2005-02-12 22:52:24 +00:00
}
} ;
LUA_REGISTER_CLASS ( ThemeManager )
// lua end
2004-06-08 01:24:17 +00:00
/*
* (c) 2001-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/