diff --git a/stepmania/Themes/default/metrics.ini b/stepmania/Themes/default/metrics.ini index f17434feec..ee6215bfe5 100644 --- a/stepmania/Themes/default/metrics.ini +++ b/stepmania/Themes/default/metrics.ini @@ -1923,6 +1923,7 @@ RandomBackgrounds=Choose the maximum number of random backgrounds to be loaded s [ScreenAppearanceOptions] HelpText=&UP; &DOWN; to change line &LEFT; &RIGHT; to select between options::START to accept changes BACK to discard changes +Language=Choose your language. Announcer=Choose from this list of installed annoucner packs.::For more information about creating announcer packs, see the README. Theme=Choose from this list of installed theme packs.::For more information about creating theme packs, see the README. DefaultNoteSkin=Choose from this list of installed note skins.::For more information about creating a note skin, see the README. diff --git a/stepmania/src/PrefsManager.cpp b/stepmania/src/PrefsManager.cpp index 924c4cb59c..d745d5764f 100644 --- a/stepmania/src/PrefsManager.cpp +++ b/stepmania/src/PrefsManager.cpp @@ -131,6 +131,7 @@ PrefsManager::PrefsManager() * already here than lots of people asking why songs aren't being displayed. */ m_bHiddenSongs = false; m_bVsync = true; + m_sLanguage = ""; // ThemeManager will deal with this invalid language /* XXX: Set these defaults for individual consoles using VideoCardDefaults.ini. */ #ifdef _XBOX @@ -265,6 +266,7 @@ void PrefsManager::ReadGlobalPrefsFromDisk( bool bSwitchToLastPlayedGame ) ini.GetValueB( "Options", "ForceLogFlush", m_bForceLogFlush ); ini.GetValueB( "Options", "Logging", m_bLogging ); ini.GetValueB( "Options", "ShowLogWindow", m_bShowLogWindow ); + ini.GetValue ( "Options", "Language", m_sLanguage ); m_asAdditionalSongFolders.clear(); @@ -377,6 +379,7 @@ void PrefsManager::SaveGlobalPrefsToDisk() ini.SetValueI( "Options", "ProgressiveLifebar", m_iProgressiveLifebar ); ini.SetValueI( "Options", "ProgressiveStageLifebar", m_iProgressiveStageLifebar ); ini.SetValueI( "Options", "ProgressiveNonstopLifebar", m_iProgressiveNonstopLifebar ); + ini.SetValue ( "Options", "Language", m_sLanguage ); /* Only write these if they aren't the default. This ensures that we can change * the default and have it take effect for everyone (except people who @@ -413,7 +416,7 @@ void PrefsManager::ReadGamePrefsFromDisk() // it's OK to call these functions with names that don't exist. ANNOUNCER->SwitchAnnouncer( sAnnouncer ); - THEME->SwitchTheme( sTheme ); + THEME->SwitchThemeAndLanguage( sTheme, m_sLanguage ); // XXX: ? // if(NOTESKIN->DoesNoteSkinExist(sNoteSkin)) diff --git a/stepmania/src/PrefsManager.h b/stepmania/src/PrefsManager.h index 8734aac0b1..92231cdcec 100644 --- a/stepmania/src/PrefsManager.h +++ b/stepmania/src/PrefsManager.h @@ -92,6 +92,7 @@ public: int m_iProgressiveLifebar; int m_iProgressiveStageLifebar; int m_iProgressiveNonstopLifebar; + CString m_sLanguage; // course ranking enum { COURSE_SORT_SONGS, COURSE_SORT_METER, COURSE_SORT_METER_SUM, COURSE_SORT_RANK } m_iCourseSortOrder; diff --git a/stepmania/src/ScreenAppearanceOptions.cpp b/stepmania/src/ScreenAppearanceOptions.cpp index 5fa7a8585b..83fdd703e8 100644 --- a/stepmania/src/ScreenAppearanceOptions.cpp +++ b/stepmania/src/ScreenAppearanceOptions.cpp @@ -28,7 +28,8 @@ enum { - AO_ANNOUNCER = 0, + AO_LANGUAGE = 0, + AO_ANNOUNCER, AO_THEME, AO_SKIN, AO_INSTRUCTIONS, @@ -46,6 +47,7 @@ enum { OptionRow g_AppearanceOptionsLines[NUM_APPEARANCE_OPTIONS_LINES] = { + OptionRow( "Language" ), OptionRow( "Announcer" ), OptionRow( "Theme" ), OptionRow( "Default\nNoteSkin" ), @@ -80,6 +82,25 @@ void ScreenAppearanceOptions::ImportOptions() { unsigned i; + // + // fill in language names + // + CStringArray arrayLanguages; + THEME->GetLanguages( arrayLanguages ); + + m_OptionRow[AO_LANGUAGE].choices.clear(); + for( i=0; iGetCurLanguage()) ) + m_iSelectedOption[0][AO_LANGUAGE] = i; + + // // fill in announcer names // @@ -170,7 +191,7 @@ void ScreenAppearanceOptions::ExportOptions() CString sNewTheme = m_OptionRow[AO_THEME].choices[iSelectedTheme]; if( THEME->GetCurThemeName() != sNewTheme ) { - THEME->SwitchTheme( sNewTheme ); + THEME->SwitchThemeAndLanguage( sNewTheme, THEME->GetCurLanguage() ); ApplyGraphicOptions(); // reset graphics to apply new window title and icon SONGMAN->UpdateRankingCourses(); // update ranking courses diff --git a/stepmania/src/StepMania.cpp b/stepmania/src/StepMania.cpp index c7ae05357b..0035e738f9 100644 --- a/stepmania/src/StepMania.cpp +++ b/stepmania/src/StepMania.cpp @@ -183,9 +183,9 @@ void ResetGame() { CString sGameName = GAMESTATE->GetCurrentGameDef()->m_szName; if( THEME->DoesThemeExist( sGameName ) ) - THEME->SwitchTheme( sGameName ); + THEME->SwitchThemeAndLanguage( sGameName, THEME->GetCurLanguage() ); else - THEME->SwitchTheme( "default" ); + THEME->SwitchThemeAndLanguage( "default", THEME->GetCurLanguage() ); TEXTUREMAN->DoDelayedDelete(); } PREFSMAN->SaveGamePrefsToDisk(); diff --git a/stepmania/src/ThemeManager.cpp b/stepmania/src/ThemeManager.cpp index 4f3b346543..22593bc5a3 100644 --- a/stepmania/src/ThemeManager.cpp +++ b/stepmania/src/ThemeManager.cpp @@ -31,7 +31,10 @@ ThemeManager* THEME = NULL; // global object accessable from anywhere in the pro const CString BASE_THEME_NAME = "default"; +const CString LANGUAGES_SUBDIR = "Languages" SLASH; +const CString BASE_LANGUAGE = "english"; const CString THEMES_DIR = BASE_PATH "Themes" SLASH; +const CString METRICS_FILE = "metrics.ini"; const CString ELEMENT_CATEGORY_STRING[NUM_ELEMENT_CATEGORIES] = { "BGAnimations", @@ -46,7 +49,12 @@ ThemeManager::ThemeManager() m_pIniMetrics = new IniFile; m_sCurThemeName = BASE_THEME_NAME; // Use the base theme for now. It's up to PrefsManager to change this. - m_uHashForCurThemeMetrics = m_uHashForBaseThemeMetrics = 0; + m_uHashForCurThemeMetrics = 0; + m_uHashForBaseThemeMetrics = 0; + m_uHashForCurThemeCurLanguage = 0; + m_uHashForBaseThemeCurLanguage = 0; + m_uHashForCurThemeBaseLanguage = 0; + m_uHashForBaseThemeBaseLanguage = 0; CStringArray arrayThemeNames; GetThemeNames( arrayThemeNames ); @@ -83,25 +91,69 @@ bool ThemeManager::DoesThemeExist( CString sThemeName ) return false; } -void ThemeManager::SwitchTheme( CString sThemeName ) +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; iReset(); - m_pIniMetrics->SetPath( GetMetricsPathFromName(BASE_THEME_NAME) ); + m_pIniMetrics->SetPath( GetMetricsIniPath(BASE_THEME_NAME) ); m_pIniMetrics->ReadFile(); - m_pIniMetrics->SetPath( GetMetricsPathFromName(m_sCurThemeName) ); + m_pIniMetrics->SetPath( GetMetricsIniPath(m_sCurThemeName) ); + m_pIniMetrics->ReadFile(); + m_pIniMetrics->SetPath( GetLanguageIniPath(BASE_THEME_NAME,BASE_LANGUAGE) ); + m_pIniMetrics->ReadFile(); + m_pIniMetrics->SetPath( GetLanguageIniPath(m_sCurThemeName,BASE_LANGUAGE) ); + m_pIniMetrics->ReadFile(); + m_pIniMetrics->SetPath( GetLanguageIniPath(BASE_THEME_NAME,m_sCurLanguage) ); + m_pIniMetrics->ReadFile(); + m_pIniMetrics->SetPath( GetLanguageIniPath(m_sCurThemeName,m_sCurLanguage) ); m_pIniMetrics->ReadFile(); LOG->MapLog("theme", "Theme: %s", sThemeName.c_str()); + LOG->MapLog("language", "Language: %s", sLanguage.c_str()); } CString ThemeManager::GetThemeDirFromName( const CString &sThemeName ) @@ -273,9 +325,9 @@ try_element_again: } -CString ThemeManager::GetMetricsPathFromName( CString sThemeName ) +CString ThemeManager::GetMetricsIniPath( CString sThemeName ) { - return GetThemeDirFromName( sThemeName ) + "metrics.ini"; + return GetThemeDirFromName( sThemeName ) + METRICS_FILE; } bool ThemeManager::HasMetric( CString sClassName, CString sValueName ) @@ -289,8 +341,8 @@ CString ThemeManager::GetMetricRaw( CString sClassName, CString sValueName ) #if defined(DEBUG) && defined(WIN32) try_metric_again: #endif - CString sCurMetricPath = GetMetricsPathFromName(m_sCurThemeName); - CString sDefaultMetricPath = GetMetricsPathFromName(BASE_THEME_NAME); + CString sCurMetricPath = GetMetricsIniPath(m_sCurThemeName); + CString sDefaultMetricPath = GetMetricsIniPath(BASE_THEME_NAME); // Is our metric cache out of date? if ( !m_uHashForBaseThemeMetrics || m_ReloadTimer.PeekDeltaTime() >= 1 ) @@ -305,7 +357,7 @@ try_metric_again: LOG->Warn( "Metrics file is out of date. Reloading..." ); // MessageBeep( MB_OK ); } - SwitchTheme(m_sCurThemeName); // force a reload of the metrics cache + SwitchThemeAndLanguage(m_sCurThemeName, m_sCurLanguage); // force a reload of the metrics cache } } @@ -378,5 +430,28 @@ void ThemeManager::NextTheme() if( as[i].CompareNoCase(m_sCurThemeName)==0 ) break; int iNewIndex = (i+1)%as.size(); - SwitchTheme( as[iNewIndex] ); + 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"; } diff --git a/stepmania/src/ThemeManager.h b/stepmania/src/ThemeManager.h index 4925275a65..e53ea9ea3a 100644 --- a/stepmania/src/ThemeManager.h +++ b/stepmania/src/ThemeManager.h @@ -27,8 +27,11 @@ public: void GetThemeNames( CStringArray& AddTo ); bool DoesThemeExist( CString sThemeName ); - void SwitchTheme( CString sThemeName ); + void GetLanguages( CStringArray& AddTo ); + bool DoesLanguageExist( CString sLanguage ); + void SwitchThemeAndLanguage( CString sThemeName, CString sLanguage ); CString GetCurThemeName() { return m_sCurThemeName; }; + CString GetCurLanguage() { return m_sCurLanguage; }; CString GetCurThemeDir() { return GetThemeDirFromName(m_sCurThemeName); }; void NextTheme(); @@ -51,13 +54,20 @@ protected: CString GetPathTo( CString sThemeName, ElementCategory category, CString sFileName ); static CString GetThemeDirFromName( const CString &sThemeName ); CString GetElementDir( CString sThemeName ); - static CString GetMetricsPathFromName( CString sThemeName ); + static CString GetMetricsIniPath( CString sThemeName ); + static void GetLanguagesForTheme( CString sThemeName, CStringArray& asLanguagesOut ); + static CString GetLanguageIniPath( CString sThemeName, CString sLanguage ); CString m_sCurThemeName; + CString m_sCurLanguage; - IniFile* m_pIniMetrics; // make this a pointer so we don't have to include IniFile in this header! + IniFile* m_pIniMetrics; // make this a pointer so we don't have to include IniFile here unsigned m_uHashForCurThemeMetrics; unsigned m_uHashForBaseThemeMetrics; + unsigned m_uHashForCurThemeCurLanguage; + unsigned m_uHashForBaseThemeCurLanguage; + unsigned m_uHashForCurThemeBaseLanguage; + unsigned m_uHashForBaseThemeBaseLanguage; RageTimer m_ReloadTimer; };