diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index b0e654e3a3..f069b40d04 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -45,9 +45,12 @@ struct ShaderInfo { bool operator == (const std::string &other) { return name == other; } + bool operator == (const ShaderInfo &other) { + return name == other.name; + } }; void ReloadAllPostShaderInfo(); const ShaderInfo *GetPostShaderInfo(std::string name); -const std::vector &GetAllPostShaderInfo(); \ No newline at end of file +const std::vector &GetAllPostShaderInfo(); diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index e5ab81cfcd..b8536f97ff 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -863,8 +863,9 @@ namespace MainWindow break; case WM_USER_UPDATE_UI: - // This also calls ChangeMenu TranslateMenus(hwndMain, menu); + // Update checked status immediately for accelerators. + UpdateMenus(); break; case WM_USER_WINDOW_TITLE_CHANGED: @@ -881,9 +882,7 @@ namespace MainWindow case WM_MENUSELECT: // Called when a menu is opened. Also when an item is selected, but meh. - // This is a good place to update the enabled/disabled state of menu items. - UpdateMenus(); - SetIngameMenuItemStates(menu, GetUIState()); + UpdateMenus(true); WindowsRawInput::NotifyMenu(); break; diff --git a/Windows/MainWindow.h b/Windows/MainWindow.h index 48eb344d38..09d217a40d 100644 --- a/Windows/MainWindow.h +++ b/Windows/MainWindow.h @@ -60,7 +60,7 @@ namespace MainWindow void CreateDebugWindows(); void DestroyDebugWindows(); void Close(); - void UpdateMenus(); + void UpdateMenus(bool isMenuSelect = false); void UpdateCommands(); void SetWindowTitle(const wchar_t *title); void Redraw(); diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 7d3c447681..4f5a844141 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -45,8 +45,10 @@ namespace MainWindow { static bool browsePauseAfter; static std::map initialMenuKeys; - static std::vector countryCodes; static std::vector availableShaders; + static std::string menuLanguageID = ""; + static bool menuShaderInfoLoaded = false; + std::vector menuShaderInfo; LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); @@ -164,7 +166,18 @@ namespace MainWindow { CheckMenuItem(menu, item++, ((g_Config.sPostShaderName == availableShaders[i]) ? MF_CHECKED : MF_UNCHECKED)); } - void CreateShadersSubmenu(HMENU menu) { + bool CreateShadersSubmenu(HMENU menu) { + // We only reload this initially and when a menu is actually opened. + if (!menuShaderInfoLoaded) { + ReloadAllPostShaderInfo(); + menuShaderInfoLoaded = true; + } + std::vector info = GetAllPostShaderInfo(); + + if (menuShaderInfo.size() != info.size() || !std::equal(info.begin(), info.end(), menuShaderInfo.begin())) { + return false; + } + I18NCategory *des = GetI18NCategory("DesktopUI"); I18NCategory *ps = GetI18NCategory("PostShaders"); const std::wstring key = ConvertUTF8ToWString(des->T("Postprocessing Shader")); @@ -176,15 +189,12 @@ namespace MainWindow { RemoveMenu(optionsMenu, SUBMENU_CUSTOM_SHADERS, MF_BYPOSITION); InsertMenu(optionsMenu, SUBMENU_CUSTOM_SHADERS, MF_POPUP | MF_STRING | MF_BYPOSITION, (UINT_PTR)shaderMenu, key.c_str()); - ReloadAllPostShaderInfo(); - std::vector info = GetAllPostShaderInfo(); - availableShaders.clear(); - int item = ID_SHADERS_BASE + 1; int checkedStatus = -1; const char *translatedShaderName = nullptr; + availableShaders.clear(); for (auto i = info.begin(); i != info.end(); ++i) { checkedStatus = MF_UNCHECKED; availableShaders.push_back(i->section); @@ -196,6 +206,9 @@ namespace MainWindow { AppendMenu(shaderMenu, MF_STRING | MF_BYPOSITION | checkedStatus, item++, ConvertUTF8ToWString(translatedShaderName).c_str()); } + + menuShaderInfo = info; + return true; } static void _TranslateMenuItem(const HMENU hMenu, const int menuIDOrPosition, const char *key, bool byCommand = false, const std::wstring& accelerator = L"") { @@ -224,7 +237,7 @@ namespace MainWindow { _TranslateMenuItem(GetSubMenu(menu, mainMenuItem), subMenuItem, key, false, accelerator); } - void TranslateMenus(HWND hWnd, HMENU menu) { + void DoTranslateMenus(HWND hWnd, HMENU menu) { // Menu headers and submenu headers don't have resource IDs, // So we have to hardcode strings here, unfortunately. TranslateMenu(menu, "File", MENU_FILE); @@ -233,8 +246,6 @@ namespace MainWindow { TranslateMenu(menu, "Game Settings", MENU_OPTIONS); TranslateMenu(menu, "Help", MENU_HELP); - CreateShadersSubmenu(menu); - // File menu TranslateMenuItem(menu, ID_FILE_LOAD); TranslateMenuItem(menu, ID_FILE_LOAD_DIR); @@ -336,9 +347,25 @@ namespace MainWindow { // Help menu: it's translated in CreateHelpMenu. CreateHelpMenu(menu); + } - DrawMenuBar(hWnd); - UpdateMenus(); + void TranslateMenus(HWND hWnd, HMENU menu) { + bool changed = false; + + const std::string curLanguageID = i18nrepo.LanguageID(); + if (curLanguageID != menuLanguageID) { + DoTranslateMenus(hWnd, menu); + menuLanguageID = curLanguageID; + changed = true; + } + + if (CreateShadersSubmenu(menu)) { + changed = true; + } + + if (changed) { + DrawMenuBar(hWnd); + } } void BrowseAndBoot(std::string defaultPath, bool browseDirectory) { @@ -1016,7 +1043,11 @@ namespace MainWindow { } } - void UpdateMenus() { + void UpdateMenus(bool isMenuSelect) { + if (isMenuSelect) { + menuShaderInfoLoaded = false; + } + HMENU menu = GetMenu(GetHWND()); #define CHECKITEM(item,value) CheckMenuItem(menu,item,MF_BYCOMMAND | ((value) ? MF_CHECKED : MF_UNCHECKED)); CHECKITEM(ID_DEBUG_IGNOREILLEGALREADS, g_Config.bIgnoreBadMemAccess); @@ -1279,19 +1310,19 @@ namespace MainWindow { static GlobalUIState lastGlobalUIState = UISTATE_PAUSEMENU; static CoreState lastCoreState = CORE_ERROR; + HMENU menu = GetMenu(GetHWND()); + EnableMenuItem(menu, ID_DEBUG_LOG, !g_Config.bEnableLogging); + if (lastGlobalUIState == GetUIState() && lastCoreState == coreState) return; lastCoreState = coreState; lastGlobalUIState = GetUIState(); - HMENU menu = GetMenu(GetHWND()); - bool isPaused = Core_IsStepping() && GetUIState() == UISTATE_INGAME; TranslateMenuItem(menu, ID_TOGGLE_PAUSE, L"\tF8", isPaused ? "Run" : "Pause"); SetIngameMenuItemStates(menu, GetUIState()); - EnableMenuItem(menu, ID_DEBUG_LOG, !g_Config.bEnableLogging); } // Message handler for about box. diff --git a/ext/native/i18n/i18n.cpp b/ext/native/i18n/i18n.cpp index 84e7e79822..974610efd4 100644 --- a/ext/native/i18n/i18n.cpp +++ b/ext/native/i18n/i18n.cpp @@ -9,6 +9,10 @@ I18NRepo::~I18NRepo() { Clear(); } +std::string I18NRepo::LanguageID() { + return languageID_; +} + void I18NRepo::Clear() { for (auto iter = cats_.begin(); iter != cats_.end(); ++iter) { delete iter->second; @@ -95,6 +99,8 @@ bool I18NRepo::LoadIni(const std::string &languageID, const std::string &overrid cats_[iter->name()] = LoadSection(&(*iter), iter->name().c_str()); } } + + languageID_ = languageID; return true; } diff --git a/ext/native/i18n/i18n.h b/ext/native/i18n/i18n.h index 479bcf4812..c57bc81f55 100644 --- a/ext/native/i18n/i18n.h +++ b/ext/native/i18n/i18n.h @@ -74,6 +74,8 @@ public: bool LoadIni(const std::string &languageID, const std::string &overridePath = ""); // NOT the filename! void SaveIni(const std::string &languageID); + std::string LanguageID(); + I18NCategory *GetCategory(const char *categoryName); const char *T(const char *category, const char *key, const char *def = 0); @@ -84,6 +86,7 @@ private: void SaveSection(IniFile &ini, IniFile::Section *section, I18NCategory *cat); std::map cats_; + std::string languageID_; DISALLOW_COPY_AND_ASSIGN(I18NRepo); };