Windows: Make UI update significantly cheaper.

Setting menu strings, reloading shaders, and redrawing the menu were all
a bit slow.  This skips those things unless they've changed.
This commit is contained in:
Unknown W. Brackets 2017-04-04 20:33:22 -07:00
parent e99f1c00ff
commit 6642bf3170
6 changed files with 63 additions and 21 deletions

View file

@ -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<ShaderInfo> &GetAllPostShaderInfo();
const std::vector<ShaderInfo> &GetAllPostShaderInfo();

View file

@ -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;

View file

@ -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();

View file

@ -45,8 +45,10 @@ namespace MainWindow {
static bool browsePauseAfter;
static std::map<int, std::string> initialMenuKeys;
static std::vector<std::string> countryCodes;
static std::vector<std::string> availableShaders;
static std::string menuLanguageID = "";
static bool menuShaderInfoLoaded = false;
std::vector<ShaderInfo> 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<ShaderInfo> 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<ShaderInfo> 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.

View file

@ -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;
}

View file

@ -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<std::string, I18NCategory *> cats_;
std::string languageID_;
DISALLOW_COPY_AND_ASSIGN(I18NRepo);
};