diff --git a/stepmania/Themes/default/BGAnimations/ScreenEvaluationStage decorations/default.lua b/stepmania/Themes/default/BGAnimations/ScreenEvaluationStage decorations/default.lua index c2e3b80daf..ca9ecea4ed 100644 --- a/stepmania/Themes/default/BGAnimations/ScreenEvaluationStage decorations/default.lua +++ b/stepmania/Themes/default/BGAnimations/ScreenEvaluationStage decorations/default.lua @@ -27,7 +27,7 @@ function ComboGraph( pn ) end -local t = THEME:GetPathB("ScreenWithMenuElements2", "decorations" ); +local t = LoadFallbackB(); t[#t+1] = GraphDisplay(PLAYER_1) .. { InitCommand = cmd(x,SCREEN_CENTER_X-222;y,SCREEN_CENTER_Y-16;draworder,1;); diff --git a/stepmania/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua b/stepmania/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua index cca2260933..7aa5882085 100644 --- a/stepmania/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua +++ b/stepmania/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua @@ -1,4 +1,4 @@ -local t = LoadFallbackB( "decorations" ); +local t = LoadFallbackB(); t[#t+1] = LoadActor( THEME:GetPathB('','_standard decoration required'), "StageFrame", "StageFrame" ); diff --git a/stepmania/Themes/default/BGAnimations/ScreenSelectMusic decorations/default.lua b/stepmania/Themes/default/BGAnimations/ScreenSelectMusic decorations/default.lua index d88b97c2d8..bae070dacf 100644 --- a/stepmania/Themes/default/BGAnimations/ScreenSelectMusic decorations/default.lua +++ b/stepmania/Themes/default/BGAnimations/ScreenSelectMusic decorations/default.lua @@ -62,7 +62,7 @@ local function OptionsArea(pn) end -local t = LoadFallbackB( "decorations" ); +local t = LoadFallbackB(); t[#t+1] = Def.ActorFrame { InitCommand=cmd(x,SCREEN_CENTER_X+140;y,SCREEN_CENTER_Y-10); OnCommand=cmd(addx,-SCREEN_WIDTH*0.6;bounceend,0.5;addx,SCREEN_WIDTH*0.6); diff --git a/stepmania/Themes/default/Scripts/Other.lua b/stepmania/Themes/default/Scripts/Other.lua index 1150e62aba..0fbebcdcae 100644 --- a/stepmania/Themes/default/Scripts/Other.lua +++ b/stepmania/Themes/default/Scripts/Other.lua @@ -1,10 +1,32 @@ -function LoadFallbackB( element ) - -- TODO: This should fall back to the current lookup's fallback, and not LoadingScreen's fallback - -- TODO: Remove element parameter and make it a LuaThreadVar - local fallback_screen = THEME:GetMetric(Var 'LoadingScreen','Fallback'); - local fallback_path = THEME:GetPathB(fallback_screen,element); - --Trace('fallback_path ' .. fallback_path ); - return LoadActor( fallback_path ); +local g_metrics_group = nil; +local g_element = nil; + +function LoadFallbackB() + -- Load the fallback BGA for the element that is currently being loaded. + -- The fallback metrics group and element name will come either from LuaThreadVars + -- (loading from C++) or from the Lua globals above (loading from Lua). + + --Warn( "g_element " .. (g_element or "") ); + --Warn( "MatchingElement " .. (Var 'MatchingElement' or "") ); + --Warn( "g_metrics_group " .. (g_metrics_group or "") ); + --Warn( "MatchingMetricsGroup " .. (Var 'MatchingMetricsGroup' or "") ); + + local metrics_group = g_metrics_group or Var 'MatchingMetricsGroup'; + local element = g_element or Var 'MatchingElement'; + local fallback = THEME:GetMetric(metrics_group,'Fallback'); + + local old_metrics_group = g_metrics_group; + local old_element = g_element; + + local path; + path, g_metrics_group, g_element = THEME:GetPathInfoB(fallback,element); + --Trace('path ' .. path ); + local t = LoadActor( path ); + + g_metrics_group = old_metrics_group; + g_element = old_element; + + return t; end function FormatNumSongsPlayed( num ) diff --git a/stepmania/src/AutoActor.cpp b/stepmania/src/AutoActor.cpp index 0e2defd99d..e28f444144 100644 --- a/stepmania/src/AutoActor.cpp +++ b/stepmania/src/AutoActor.cpp @@ -45,6 +45,16 @@ void AutoActor::Load( const RString &sPath ) m_pActor = new Actor; } +void AutoActor::LoadB( const RString &sMetricsGroup, const RString &sElement ) +{ + ThemeManager::PathInfo pi; + bool b = THEME->GetPathInfo( pi, EC_BGANIMATIONS, sMetricsGroup, sElement ); + ASSERT( b ); + LuaThreadVariable var1( "MatchingMetricsGroup", pi.sMatchingMetricsGroup ); + LuaThreadVariable var2( "MatchingElement", pi.sMatchingElement ); + Load( pi.sResolvedPath ); +} + void AutoActor::LoadActorFromNode( const XNode* pNode, Actor *pParent ) { Unload(); diff --git a/stepmania/src/AutoActor.h b/stepmania/src/AutoActor.h index 4a5d0eb854..4d8c2c1ebc 100644 --- a/stepmania/src/AutoActor.h +++ b/stepmania/src/AutoActor.h @@ -21,8 +21,9 @@ public: Actor *operator->() { return m_pActor; } void Unload(); bool IsLoaded() const { return m_pActor != NULL; } - void Load( Actor *pActor ); + void Load( Actor *pActor ); // transfer pointer void Load( const RString &sPath ); + void LoadB( const RString &sMetricsGroup, const RString &sElement ); // load a background and set up LuaThreadVariables for recursive loading void LoadActorFromNode( const XNode *pNode, Actor *pParent ); void LoadAndSetName( const RString &sScreenName, const RString &sActorName ); diff --git a/stepmania/src/ScreenWithMenuElements.cpp b/stepmania/src/ScreenWithMenuElements.cpp index b6c9c07cf0..dd40887531 100644 --- a/stepmania/src/ScreenWithMenuElements.cpp +++ b/stepmania/src/ScreenWithMenuElements.cpp @@ -78,7 +78,7 @@ void ScreenWithMenuElements::Init() /* Experimental: Load "decorations" and make them children of the screen. */ { AutoActor decorations; - decorations.Load( THEME->GetPathB(m_sName,"decorations") ); + decorations.LoadB( m_sName, "decorations" ); ActorFrame *pFrame = dynamic_cast((Actor*)decorations); if( pFrame ) pFrame->TransferChildren( this ); diff --git a/stepmania/src/ThemeManager.cpp b/stepmania/src/ThemeManager.cpp index 228a0da400..849e07d9f0 100644 --- a/stepmania/src/ThemeManager.cpp +++ b/stepmania/src/ThemeManager.cpp @@ -114,7 +114,7 @@ void ThemeManager::Unsubscribe( IThemeMetric *p ) /* We spend a lot of time doing redundant theme path lookups. Cache results. */ -static map g_ThemePathCache[NUM_ElementCategory]; +static map g_ThemePathCache[NUM_ElementCategory]; void ThemeManager::ClearThemePathCache() { for( int i = 0; i < NUM_ElementCategory; ++i ) @@ -503,10 +503,10 @@ void ThemeManager::FilterFileLanguages( vector &asPaths ) asPaths.erase( it, asPaths.end() ); } -RString ThemeManager::GetPathToRaw( const RString &sThemeName_, ElementCategory category, const RString &sMetricsGroup_, const RString &sElement_ ) +bool ThemeManager::GetPathInfoToRaw( PathInfo &out, const RString &sThemeName_, ElementCategory category, const RString &sMetricsGroup_, const RString &sElement_ ) { /* 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. */ + * else that might suddenly go away when we call ReloadMetrics, so make a copy. */ const RString sThemeName = sThemeName_; const RString sMetricsGroup = sMetricsGroup_; const RString sElement = sElement_; @@ -578,7 +578,7 @@ try_element_again: if( asElementPaths.size() == 0 ) - return RString(); // This isn't fatal. + return false; // This isn't fatal. FilterFileLanguages( asElementPaths ); @@ -613,7 +613,12 @@ try_element_again: bool bIsARedirect = GetExtension(sPath).CompareNoCase("redir")==0; if( !bIsARedirect ) - return sPath; + { + out.sResolvedPath = sPath; + out.sMatchingMetricsGroup = sMetricsGroup; + out.sMatchingElement = sElement; + return true; + } RString sNewFileName; GetFileContents( sPath, sNewFileName, true ); @@ -629,10 +634,8 @@ try_element_again: * 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. */ - RString sNewPath = GetPath(category, sNewClassName, sNewFile, true); - - if( !sNewPath.empty() ) - return sNewPath; + if( GetPathInfo(out,category,sNewClassName,sNewFile,true) ) + return true; RString sMessage = ssprintf( "ThemeManager: The redirect '%s' points to the file '%s', which does not exist. " @@ -645,13 +648,14 @@ try_element_again: ReloadMetrics(); goto try_element_again; case Dialog::ignore: - return GetPath( category, "", "_missing" ); + GetPathInfo( out, category, "", "_missing" ); + return true; } RageException::Throw( "%s", sMessage.c_str() ); } -RString ThemeManager::GetPathToAndFallback( ElementCategory category, const RString &sMetricsGroup_, const RString &sElement ) +bool ThemeManager::GetPathInfoToAndFallback( PathInfo &out, ElementCategory category, const RString &sMetricsGroup_, const RString &sElement ) { RString sMetricsGroup( sMetricsGroup_ ); @@ -661,18 +665,17 @@ RString ThemeManager::GetPathToAndFallback( ElementCategory category, const RStr FOREACHD_CONST( Theme, g_vThemes, iter ) { // search with requested name - RString sRet = GetPathToRaw( iter->sThemeName, category, sMetricsGroup, sElement ); - if( !sRet.empty() ) - return sRet; + if( GetPathInfoToRaw( out, iter->sThemeName, category, sMetricsGroup, sElement ) ) + return true; } if( sMetricsGroup.empty() ) - return RString(); + return false; // search fallback name (if any) sMetricsGroup = GetMetricsGroupFallback( sMetricsGroup ); if( sMetricsGroup.empty() ) - return RString(); + return false; } RageException::Throw( "Infinite recursion looking up theme element \"%s\"", @@ -682,7 +685,7 @@ RString ThemeManager::GetPathToAndFallback( ElementCategory category, const RStr while( true ) {} } -RString ThemeManager::GetPath( ElementCategory category, const RString &sMetricsGroup_, const RString &sElement_, bool bOptional ) +bool ThemeManager::GetPathInfo( PathInfo &out, ElementCategory category, const RString &sMetricsGroup_, const RString &sElement_, bool bOptional ) { /* 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. */ @@ -691,29 +694,31 @@ RString ThemeManager::GetPath( ElementCategory category, const RString &sMetrics RString sFileName = MetricsGroupAndElementToFileName( sMetricsGroup, sElement ); - map &Cache = g_ThemePathCache[category]; + map &Cache = g_ThemePathCache[category]; { - map::const_iterator i; + map::const_iterator i; i = Cache.find( sFileName ); if( i != Cache.end() ) - return i->second; + { + out = i->second; + return true; + } } try_element_again: // search the current theme - RString ret = GetPathToAndFallback( category, sMetricsGroup, sElement ); - if( !ret.empty() ) // we found something + if( GetPathInfoToAndFallback( out, category, sMetricsGroup, sElement ) ) // we found something { - Cache[sFileName] = ret; - return ret; + Cache[sFileName] = out; + return true; } if( bOptional ) { - Cache[sFileName] = ""; - return RString(); + Cache[sFileName] = PathInfo(); // clear cache entry + return false; } const RString &sCategory = ElementCategoryToString(category); @@ -740,8 +745,9 @@ try_element_again: if( sFileName == "_missing" ) RageException::Throw( "\"_missing\" isn't present in \"%s%s\".", GetThemeDirFromName(SpecialFiles::BASE_THEME_NAME).c_str(), sCategory.c_str() ); - Cache[sFileName] = GetPath( category, "", "_missing" ); - return Cache[sFileName]; + GetPathInfo( out, category, "", "_missing" ); + Cache[sFileName] = out; + return true; case Dialog::abort: LOG->UserLog( "Theme element", sCategory + '/' + sFileName, "could not be found in \"%s\" or \"%s\".", @@ -757,6 +763,13 @@ try_element_again: FAIL_M( "" ); // Silence gcc 4. } +RString ThemeManager::GetPath( ElementCategory category, const RString &sMetricsGroup, const RString &sElement, bool bOptional ) +{ + PathInfo pi; + GetPathInfo( pi, category, sMetricsGroup, sElement, bOptional ); + ASSERT( pi.sResolvedPath ); + return pi.sResolvedPath; +} RString ThemeManager::GetMetricsIniPath( const RString &sThemeName ) { @@ -1123,6 +1136,15 @@ class LunaThemeManager: public Luna public: static int GetMetric( T* p, lua_State *L ) { p->PushMetric( L, SArg(1),SArg(2) ); return 1; } static int GetString( T* p, lua_State *L ) { lua_pushstring(L, p->GetString(SArg(1),SArg(2)) ); return 1; } + static int GetPathInfoB( T* p, lua_State *L ) + { + ThemeManager::PathInfo pi; + p->GetPathInfo( pi, EC_BGANIMATIONS, SArg(1), SArg(2) ); + lua_pushstring(L, pi.sResolvedPath); + lua_pushstring(L, pi.sMatchingMetricsGroup); + lua_pushstring(L, pi.sMatchingElement); + return 3; + } static int GetPathF( T* p, lua_State *L ) { lua_pushstring(L, p->GetPathF(SArg(1),SArg(2)) ); return 1; } static int GetPathG( T* p, lua_State *L ) { lua_pushstring(L, p->GetPathG(SArg(1),SArg(2)) ); return 1; } static int GetPathB( T* p, lua_State *L ) { lua_pushstring(L, p->GetPathB(SArg(1),SArg(2)) ); return 1; } @@ -1133,6 +1155,7 @@ public: { ADD_METHOD( GetMetric ); ADD_METHOD( GetString ); + ADD_METHOD( GetPathInfoB ); ADD_METHOD( GetPathF ); ADD_METHOD( GetPathG ); ADD_METHOD( GetPathB ); diff --git a/stepmania/src/ThemeManager.h b/stepmania/src/ThemeManager.h index 0a931bbe6b..e8b405468b 100644 --- a/stepmania/src/ThemeManager.h +++ b/stepmania/src/ThemeManager.h @@ -55,9 +55,14 @@ public: static void EvaluateString( RString &sText ); - /* I renamed these for two reasons. The overload conflicts with the ones below: - * GetPathToB( str, str ) was matching the ones below instead of these. It's also - * easier to search for uses of obsolete functions if they have a different name. */ + struct PathInfo + { + RString sResolvedPath; + RString sMatchingMetricsGroup; + RString sMatchingElement; + }; + + bool GetPathInfo( PathInfo &out, ElementCategory category, const RString &sMetricsGroup, const RString &sElement, bool bOptional=false ); RString GetPath( ElementCategory category, const RString &sMetricsGroup, const RString &sElement, bool bOptional=false ); RString GetPathB( const RString &sMetricsGroup, const RString &sElement, bool bOptional=false ) { return GetPath(EC_BGANIMATIONS,sMetricsGroup,sElement,bOptional); }; RString GetPathF( const RString &sMetricsGroup, const RString &sElement, bool bOptional=false ) { return GetPath(EC_FONTS,sMetricsGroup,sElement,bOptional); }; @@ -106,8 +111,9 @@ protected: void LoadThemeMetrics( const RString &sThemeName, const RString &sLanguage_ ); RString GetMetricRaw( const IniFile &ini, const RString &sMetricsGroup, const RString &sValueName ); bool GetMetricRawRecursive( const IniFile &ini, const RString &sMetricsGroup, const RString &sValueName, RString &sRet ); - RString GetPathToAndFallback( ElementCategory category, const RString &sMetricsGroup, const RString &sFile ); - RString GetPathToRaw( const RString &sThemeName, ElementCategory category, const RString &sMetricsGroup, const RString &sFile ); + + bool GetPathInfoToAndFallback( PathInfo &out, ElementCategory category, const RString &sMetricsGroup, const RString &sFile ); + bool GetPathInfoToRaw( PathInfo &out, const RString &sThemeName, ElementCategory category, const RString &sMetricsGroup, const RString &sFile ); static RString GetThemeDirFromName( const RString &sThemeName ); RString GetElementDir( const RString &sThemeName ); static RString GetMetricsIniPath( const RString &sThemeName );