diff --git a/src/gui/gui2_canvas.cpp b/src/gui/gui2_canvas.cpp index 5bcc0c483..be6cb1a16 100644 --- a/src/gui/gui2_canvas.cpp +++ b/src/gui/gui2_canvas.cpp @@ -2,12 +2,11 @@ #include "gui2_element.h" #include "theme.h" - GuiCanvas::GuiCanvas(RenderLayer* renderLayer) : Renderable(renderLayer), click_element(nullptr), focus_element(nullptr) { enable_debug_rendering = false; - theme = GuiTheme::getTheme("default"); + theme = GuiTheme::getCurrentTheme(); } //due to a suspected compiler bug this deconstructor needs to be explicitly defined diff --git a/src/gui/theme.cpp b/src/gui/theme.cpp index 3b0d0fa88..837f3da19 100644 --- a/src/gui/theme.cpp +++ b/src/gui/theme.cpp @@ -1,4 +1,5 @@ #include "gui/theme.h" +#include "resources.h" #include #include #include @@ -6,6 +7,7 @@ static std::unordered_map fonts; std::unordered_map GuiTheme::themes; +string GuiTheme::current_theme = "default"; static glm::u8vec4 toColor(const string& s) { @@ -44,7 +46,7 @@ const GuiThemeStyle* GuiTheme::getStyle(const string& element) int n = element.rfind("."); if (n == -1) { - LOG(Warning, "Cannot find", element, "in theme", name); + LOG(Warning, "Cannot find ", element, " in theme ", name); return getStyle("fallback"); } return getStyle(element.substr(0, n)); @@ -60,10 +62,24 @@ GuiTheme* GuiTheme::getTheme(const string& name) LOG(Error, "Default theme not found. Most likely crashing now."); return nullptr; } - LOG(Warning, "Theme", name, "not found. Falling back to [default] theme."); + LOG(Warning, "Theme ", name, " not found. Falling back to [default] theme."); return getTheme("default"); } +void GuiTheme::setCurrentTheme(const string &theme_name) +{ + if(themes.find(theme_name) != themes.end()) + { + LOG(INFO, "Set theme to : ", theme_name); + GuiTheme::current_theme = theme_name; + } +} + +GuiTheme* GuiTheme::getCurrentTheme() +{ + return GuiTheme::getTheme(GuiTheme::current_theme); +} + bool GuiTheme::loadTheme(const string& name, const string& resource_name) { GuiTheme* theme = new GuiTheme(name); @@ -133,6 +149,11 @@ GuiTheme::GuiTheme(const string& name) fallback_state.color = {255, 255, 255, 255}; fallback_state.size = 12; fallback_state.font = nullptr; + std::vector fonts = findResources("gui/fonts/*.ttf"); + if(fonts.size() > 0) + { + fallback_state.font = getFont(fonts[0]); + } fallback_state.texture = ""; GuiThemeStyle fallback; for(unsigned int n=0; n styles; static std::unordered_map themes; + static string current_theme; }; #endif//GUI_THEME_H diff --git a/src/main.cpp b/src/main.cpp index c2db45fa8..0fdbfabde 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -238,11 +238,22 @@ int main(int argc, char** argv) #endif } - if (!GuiTheme::loadTheme("default", PreferencesManager::get("guitheme", "gui/default.theme.txt"))) + //For now there is only one named theme : default. + string theme_name = PreferencesManager::get("guitheme", "default"); + if (!GuiTheme::loadTheme(theme_name, "gui/" + theme_name +".theme.txt")) { - LOG(ERROR, "Failed to load default theme, exiting."); - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Failed to load gui theme, resources missing?", nullptr); - return 1; + LOG(ERROR, "Failed to load "+ theme_name + " theme, trying default. Resources missing or contains errors ? Check gui/" + theme_name + ".theme.txt"); + if (!GuiTheme::loadTheme("default", "gui/default.theme.txt")) + { + LOG(ERROR, "Failed to load default theme, exiting. Check gui/default.theme.txt"); //Yes, we may try to load twice default theme but this should be a rare error case which always finish in exit + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Failed to load gui theme, resources missing or contains errors ? Check gui/default.theme.txt", nullptr); + return 1; + } + GuiTheme::setCurrentTheme("default"); + } + else + { + GuiTheme::setCurrentTheme(theme_name); } if (PreferencesManager::get("headless") == "") @@ -337,8 +348,8 @@ int main(int argc, char** argv) soundManager->setMusicVolume(PreferencesManager::get("music_volume", "50").toFloat()); soundManager->setMasterSoundVolume(PreferencesManager::get("sound_volume", "50").toFloat()); - main_font = GuiTheme::getTheme("default")->getStyle("base")->states[0].font; - bold_font = GuiTheme::getTheme("default")->getStyle("bold")->states[0].font; + main_font = GuiTheme::getCurrentTheme()->getStyle("base")->states[0].font; + bold_font = GuiTheme::getCurrentTheme()->getStyle("bold")->states[0].font; if (!main_font || !bold_font) { LOG(ERROR, "Missing font or bold font."); diff --git a/src/menus/optionsMenu.cpp b/src/menus/optionsMenu.cpp index 8b3422a65..28f751c35 100644 --- a/src/menus/optionsMenu.cpp +++ b/src/menus/optionsMenu.cpp @@ -7,6 +7,7 @@ #include "soundManager.h" #include "windowManager.h" +#include "gui/theme.h" #include "gui/gui2_overlay.h" #include "gui/gui2_button.h" #include "gui/gui2_togglebutton.h" @@ -104,36 +105,93 @@ OptionsMenu::OptionsMenu() }))->setSize(GuiElement::GuiSizeMax, 50); //Select the language - (new GuiLabel(interface_page, "LANGUAGE_OPTIONS_LABEL", tr("Language (applies on back)"), 30))->addBackground()->setSize(GuiElement::GuiSizeMax, 50)->layout.margin.top = 20; - - std::vector languages = findResources("locale/main.*.po"); - - for(string &language : languages) { - //strip extension - language = language.substr(language.find(".") + 1, language.rfind(".")); - } - std::sort(languages.begin(), languages.end()); + (new GuiLabel(interface_page, "LANGUAGE_OPTIONS_LABEL", tr("Language (applies on back)"), 30))->addBackground()->setSize(GuiElement::GuiSizeMax, 50)->layout.margin.top = 20; + + std::vector languages = findResources("locale/main.*.po"); + + for(string &language : languages) + { + //strip extension + language = language.substr(language.find(".") + 1, language.rfind(".")); + } + std::sort(languages.begin(), languages.end()); - int default_index = 0; - auto default_elem = std::find(languages.begin(), languages.end(), PreferencesManager::get("language", "en")); - if(default_elem != languages.end()) - { - default_index = static_cast(default_elem - languages.begin()); + int default_index = 0; + auto default_elem = std::find(languages.begin(), languages.end(), PreferencesManager::get("language", "en")); + if(default_elem != languages.end()) + { + default_index = static_cast(default_elem - languages.begin()); + } + + (new GuiSelector(interface_page, "LANGUAGE_SELECTOR", [](int index, string value) + { + i18n::reset(); + i18n::load("locale/main." + value + ".po"); + PreferencesManager::set("language", value); + keys.init(); // Reinit keyboard shortcut labels + }))->setOptions(languages)->setSelectionIndex(default_index)->setSize(GuiElement::GuiSizeMax, 50); } - (new GuiSelector(interface_page, "LANGUAGE_SELECTOR", [](int index, string value) + //Gui theme selection { - i18n::reset(); - i18n::load("locale/main." + value + ".po"); - PreferencesManager::set("language", value); - keys.init(); // Reinit keyboard shortcut labels - }))->setOptions(languages)->setSelectionIndex(default_index)->setSize(GuiElement::GuiSizeMax, 50); + (new GuiLabel(interface_page, "GUI_THEME_OPTIONS_LABEL", tr("Interface Theme"), 30))->addBackground()->setSize(GuiElement::GuiSizeMax, 50)->layout.margin.top = 20; + + std::vector themes = findResources("gui/*.theme.txt"); + + auto iter = themes.begin(); + while(iter != themes.end()) + { + //strip extension + *iter = iter->substr(iter->find("/")+1, iter->find(".")); + if (!GuiTheme::loadTheme(*iter, "gui/" + *iter +".theme.txt")) + { + LOG(ERROR, "Failed to load theme : ", *iter); + iter = themes.erase(iter); + } + else if (!GuiTheme::getTheme(*iter)->getStyle("base")->states[0].font + || !GuiTheme::getTheme(*iter)->getStyle("bold")->states[0].font) + { + LOG(ERROR, "Missing base font or bold font for theme : ", *iter); + iter = themes.erase(iter); + } + else + { + ++iter; + } + } + + std::sort(themes.begin(), themes.end()); + if(0 == themes.size()) + { + LOG(ERROR, "Failed to load any theme, exiting"); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Failed to load any theme, resources missing ? Should be gui/*.theme.txt. and not contain errors.", nullptr); + exit(1); + } + + int default_index = 0; + auto default_elem = std::find(themes.begin(), themes.end(), PreferencesManager::get("guitheme", "default")); + if(default_elem != themes.end()) + { + default_index = static_cast(default_elem - themes.begin()); + } + + (new GuiSelector(interface_page, "GUI_THEME_SELECTOR", [](int index, string theme_name) + { + GuiTheme::setCurrentTheme(theme_name); + main_font = GuiTheme::getCurrentTheme()->getStyle("base")->states[0].font; + bold_font = GuiTheme::getCurrentTheme()->getStyle("bold")->states[0].font; + //Render default font is applied on back only + PreferencesManager::set("guitheme", theme_name); + }))->setOptions(themes)->setSelectionIndex(default_index)->setSize(GuiElement::GuiSizeMax, 50); + } // Bottom GUI. // Back button. (new GuiButton(this, "BACK", tr("button", "Back"), [this]() { + //Apply potentially modified font now, in order not to have some half rendered panel with one font and another + sp::RenderTarget::setDefaultFont(main_font); // Close this menu, stop the music, and return to the main menu. destroy(); soundManager->stopMusic();