From 4d00a81fe7bf2d992ebb0213ba30261ad7295ae9 Mon Sep 17 00:00:00 2001 From: Charles Dang Date: Mon, 29 May 2017 12:03:23 +1100 Subject: [PATCH] GUI2/Settings: bunch of cleanup and minor refactoring Notable changes: * get_window_builder now returns a const reference instead of an iterator. * gui_definition and builder_window (not the one in window.cpp) now take a config reference directly and call read() from their ctors instead of requiring that be called manually. * Added some more documentation. * Made variable names more accurate. * Removed some unused static variables * Removed the unused non-class load_widget_definitions function (the gui_definition member of the same name remains. --- src/gui/core/window_builder.cpp | 12 +- src/gui/core/window_builder.hpp | 10 +- src/gui/widgets/helper.cpp | 2 + src/gui/widgets/settings.cpp | 225 ++++++++++++++++---------------- src/gui/widgets/settings.hpp | 22 ++-- 5 files changed, 135 insertions(+), 136 deletions(-) diff --git a/src/gui/core/window_builder.cpp b/src/gui/core/window_builder.cpp index 88fee169c5dc..6f1849bd5100 100644 --- a/src/gui/core/window_builder.cpp +++ b/src/gui/core/window_builder.cpp @@ -125,9 +125,8 @@ window* build(CVideo& video, const builder_window::window_resolution* definition window* build(CVideo& video, const std::string& type) { - std::vector::const_iterator definition - = get_window_builder(type); - window* window = build(video, &*definition); + const builder_window::window_resolution& definition = get_window_builder(type); + window* window = build(video, &definition); window->set_id(type); return window; } @@ -251,11 +250,8 @@ builder_widget_ptr create_builder_widget(const config& cfg) * * */ -const std::string& builder_window::read(const config& cfg) +void builder_window::read(const config& cfg) { - id_ = cfg["id"].str(); - description_ = cfg["description"].str(); - VALIDATE(!id_.empty(), missing_mandatory_wml_key("window", "id")); VALIDATE(!description_.empty(), missing_mandatory_wml_key("window", "description")); @@ -268,8 +264,6 @@ const std::string& builder_window::read(const config& cfg) { resolutions.emplace_back(i); } - - return id_; } /*WIKI diff --git a/src/gui/core/window_builder.hpp b/src/gui/core/window_builder.hpp index 5461bde2116f..f7f2d5194a6d 100644 --- a/src/gui/core/window_builder.hpp +++ b/src/gui/core/window_builder.hpp @@ -150,12 +150,14 @@ typedef std::shared_ptr builder_grid_const_ptr; class builder_window { public: - builder_window() : resolutions(), id_(), description_() + explicit builder_window(const config& cfg) + : resolutions() + , id_(cfg["id"]) + , description_(cfg["description"]) { + read(cfg); } - const std::string& read(const config& cfg); - struct window_resolution { public: @@ -203,6 +205,8 @@ class builder_window std::vector resolutions; private: + void read(const config& cfg); + std::string id_; std::string description_; }; diff --git a/src/gui/widgets/helper.cpp b/src/gui/widgets/helper.cpp index 156eeab5fd3b..26b3ef819d9c 100644 --- a/src/gui/widgets/helper.cpp +++ b/src/gui/widgets/helper.cpp @@ -33,6 +33,7 @@ static bool initialized_ = false; bool init() { + const size_t start = SDL_GetTicks(); if(initialized_) { return true; } @@ -40,6 +41,7 @@ bool init() load_settings(); initialized_ = true; + std::cout << "GUI2 init took " << (SDL_GetTicks() - start) << " ms" << std::endl; return initialized_; } diff --git a/src/gui/widgets/settings.cpp b/src/gui/widgets/settings.cpp index d929067a4aa2..220ff0a2361b 100644 --- a/src/gui/widgets/settings.cpp +++ b/src/gui/widgets/settings.cpp @@ -67,37 +67,52 @@ std::vector get_tips() } // namespace settings /** - * Returns the list of registered windows. + * Notes on the registered widget and window lists. * - * The function can be used the look for registered windows or to add them. + * These lists are GUI-independent. They represent the widgets and windows + * registered from the C++ interface with @ref register_widget or @register_window. + * + * Also note these cannot be free-standing static data members within this file since + * that causes a crash for some reason. */ + +/** Returns the list of registered windows. */ static std::vector& registered_window_types() { static std::vector result; return result; } -struct registered_widget_type_mapped_type +struct registered_widget_parser { - std::function parser; + widget_parser_t parser; const char* key; }; -typedef std::map registered_widget_type; +using registered_widget_map = std::map; -static registered_widget_type& registered_widget_types() +/** Returns the list of registered widgets. */ +static registered_widget_map& registered_widget_types() { - static registered_widget_type result; + static registered_widget_map result; return result; } -struct gui_definition +/** + * A GUI definiton. + * + * Each GUI contains several widgets, their definitons, and windows and controls the appearance and + * layout of each. + + * Multiple GUI definitions may exist, though only a single default one is provided right now. + */ +class gui_definition { - gui_definition() - : id() - , description() - , control_definition() - , windows() +public: + explicit gui_definition(const config& cfg) + : id(cfg["id"]) + , description(cfg["description"].t_str()) + , widget_types() , window_types() , popup_show_delay_(0) , popup_show_time_(0) @@ -111,29 +126,30 @@ struct gui_definition , has_helptip_message_() , tips_() { + read(cfg); } std::string id; t_string description; - const std::string& read(const config& cfg); - - /** Activates a gui. */ + /** Activates this gui. */ void activate() const; - typedef std::map> - styled_widget_definition_map; - - styled_widget_definition_map control_definition; + using styled_widget_definition_map = + std::map>; - std::map windows; + /** Map of each widget type, by id, and a sub-map of each of the type's definitions, also by id. */ + styled_widget_definition_map widget_types; + /** Map of all known windows (the builder class builds a window). */ std::map window_types; - void load_widget_definitions( + void load_widget_types( const std::string& definition_type, const std::vector& definitions); private: + void read(const config& cfg); + unsigned popup_show_delay_; unsigned popup_show_time_; unsigned help_show_time_; @@ -183,7 +199,7 @@ struct gui_definition * id & string & & Unique id for this gui (theme). $ * description & t_string & & Unique translatable name for this gui. $ * - * widget_definitions & section & & The definitions of all + * widget_types & section & & The definitions of all * [[#widget_list|widgets]]. $ * window & section & & The definitions of all * [[#window_list|windows]]. $ @@ -327,17 +343,14 @@ struct gui_definition * @end{tag}{name="tip"} * @end{parent}{name="gui/"} */ -const std::string& gui_definition::read(const config& cfg) +void gui_definition::read(const config& cfg) { - id = cfg["id"].str(); - description = cfg["description"]; - VALIDATE(!id.empty(), missing_mandatory_wml_key("gui", "id")); VALIDATE(!description.empty(), missing_mandatory_wml_key("gui", "description")); - DBG_GUI_P << "Parsing gui " << id << '\n'; + DBG_GUI_P << "Parsing gui " << id << std::endl; - /***** Control definitions *****/ + /** Parse widget definitions of each registered type. */ for(auto& widget_type : registered_widget_types()) { std::vector definitions; @@ -349,14 +362,12 @@ const std::string& gui_definition::read(const config& cfg) definitions.push_back(widget_type.second.parser(definition)); } - load_widget_definitions(widget_type.first, definitions); + load_widget_types(widget_type.first, definitions); } - /***** Window types *****/ - for(const auto& w : cfg.child_range("window")) { - std::pair child; - child.first = child.second.read(w); - window_types.insert(child); + /** Parse each window. */ + for(auto& w : cfg.child_range("window")) { + window_types.emplace(w["id"], builder_window(w)); } if(id == "default") { @@ -402,8 +413,6 @@ const std::string& gui_definition::read(const config& cfg) VALIDATE(!has_helptip_message_.empty(), missing_mandatory_wml_key("[settings]", "has_helptip_message")); tips_ = tip_of_the_day::load(cfg); - - return id; } void gui_definition::activate() const @@ -421,50 +430,45 @@ void gui_definition::activate() const settings::tips = tips_; } -void gui_definition::load_widget_definitions( +void gui_definition::load_widget_types( const std::string& definition_type, const std::vector& definitions) { for(const auto& def : definitions) { - if(control_definition[definition_type].find(def->id) != control_definition[definition_type].end()) { + if(widget_types[definition_type].find(def->id) != widget_types[definition_type].end()) { ERR_GUI_P << "Skipping duplicate styled_widget definition '" << def->id << "' for '" << definition_type << "'\n"; continue; } - control_definition[definition_type].emplace(def->id, def); + widget_types[definition_type].emplace(def->id, def); } - // The default GUI needs to ensure each widget has a default definition, but non-default GUIs can just fall back to - // the default definition in the default GUI. + // The default GUI needs to ensure each widget has a default definition, but + // non-default GUIs can just fall back to the default definition in the default GUI. if(this->id != "default") { return; } - t_string msg(vgettext("Widget definition '$definition' doesn't contain the definition for '$id'.", { + const t_string msg(vgettext("Widget definition '$definition' doesn't contain the definition for '$id'.", { {"definition", definition_type}, {"id", "default"} })); - VALIDATE(control_definition[definition_type].find("default") != control_definition[definition_type].end(), msg); + VALIDATE(widget_types[definition_type].find("default") != widget_types[definition_type].end(), msg); } -/** Map with all known windows, (the builder class builds a window). */ -static std::map windows; - -/** Map with all known guis. */ +/** Map with all known GUIs. */ static std::map guis; -/** Points to the current gui. */ -static std::map::const_iterator current_gui = guis.end(); +/** Points to the current GUI. */ +static auto current_gui = guis.end(); -/** Points to the default gui. */ -static std::map::iterator default_gui = guis.end(); +/** Points to the default GUI. */ +static auto default_gui = guis.end(); void register_window(const std::string& id) { - const std::vector::iterator itor = std::find( - registered_window_types().begin(), - registered_window_types().end(), id); + const auto itor = std::find(registered_window_types().begin(), registered_window_types().end(), id); if(itor == registered_window_types().end()) { registered_window_types().push_back(id); @@ -478,7 +482,7 @@ std::vector unit_test_access_only::get_registered_window_list() void load_settings() { - LOG_GUI_G << "Setting: init gui.\n"; + LOG_GUI_G << "Setting: init gui." << std::endl; // Init. window::update_screen_size(); @@ -502,9 +506,7 @@ void load_settings() // Parse GUI definitions. for(const auto& g : cfg.child_range("gui")) { - std::pair child; - child.first = child.second.read(g); - guis.insert(child); + guis.emplace(g["id"], gui_definition(g)); } default_gui = guis.find("default"); @@ -521,59 +523,52 @@ void load_settings() current_gui->second.activate(); } -void register_widget( - const std::string& id, std::function f, const char* key) +void register_widget(const std::string& id, widget_parser_t f, const char* key) { registered_widget_types()[id] = {f, key}; } -void load_widget_definitions(gui_definition& gui, - const std::string& definition_type, - const std::vector& definitions) -{ - DBG_GUI_P << "Load definition '" << definition_type << "'.\n"; - gui.load_widget_definitions(definition_type, definitions); -} - resolution_definition_ptr get_control(const std::string& control_type, const std::string& definition) { - const gui_definition::styled_widget_definition_map::const_iterator + const auto& current_types = current_gui->second.widget_types; + const auto& default_types = default_gui->second.widget_types; + #ifdef GUI2_EXPERIMENTAL_LISTBOX - control_definition = (control_type == "list") - ? current_gui->second.control_definition.find("listbox") - : current_gui->second.control_definition.find(control_type); + const auto widget_definitions = (control_type == "list") + ? current_types.find("listbox") + : current_types.find(control_type); #else - control_definition - = current_gui->second.control_definition.find(control_type); + const auto widget_definitions + = current_types.find(control_type); #endif std::map::const_iterator control; - if(control_definition == current_gui->second.control_definition.end()) { + if(widget_definitions == current_types.end()) { goto fallback; } - control = control_definition->second.find(definition); + control = widget_definitions->second.find(definition); - if(control == control_definition->second.end()) { + if(control == widget_definitions->second.end()) { fallback: bool found_fallback = false; if(current_gui != default_gui) { #ifdef GUI2_EXPERIMENTAL_LISTBOX - auto default_control_definition = (control_type == "list") - ? default_gui->second.control_definition.find("listbox") - : default_gui->second.control_definition.find(control_type); + auto default_widget_definitions = (control_type == "list") + ? default_types.find("listbox") + : default_types.find(control_type); #else - auto default_control_definition - = default_gui->second.control_definition.find(control_type); + auto default_widget_definitions + = default_types.find(control_type); #endif - VALIDATE(control_definition != current_gui->second.control_definition.end(), + VALIDATE(widget_definitions != current_types.end(), formatter() << "Type '" << control_type << "' is unknown."); - control = default_control_definition->second.find(definition); - found_fallback = control != default_control_definition->second.end(); + control = default_widget_definitions->second.find(definition); + found_fallback = control != default_widget_definitions->second.end(); } if(!found_fallback) { @@ -589,47 +584,51 @@ resolution_definition_ptr get_control(const std::string& control_type, const std const auto& resolutions = (*control->second).resolutions; - for(auto itor = resolutions.begin(); itor != resolutions.end(); ++itor) { - if((settings::screen_width <= (**itor).window_width && - settings::screen_height <= (**itor).window_height) || itor == resolutions.end() - 1) - { - return *itor; + VALIDATE(!resolutions.empty(), + formatter() << "Control: type '" << control_type << "' definition '" << definition << "' has no resolutions.\n"); + + for(const auto& res : resolutions) { + if(settings::screen_width <= res->window_width && settings::screen_height <= res->window_height) { + return res; } } - FAIL(formatter() << "Control: type '" << control_type << "' definition '" << definition - << "' has no resolutions.\n"); + // If no matching resolution was found, return the last definition. + return resolutions.back(); } -std::vector::const_iterator get_window_builder(const std::string& type) +const builder_window::window_resolution& get_window_builder(const std::string& type) { window::update_screen_size(); - std::map::const_iterator window = current_gui->second.window_types.find(type); + auto window = current_gui->second.window_types.find(type); if(window == current_gui->second.window_types.end()) { - if(current_gui != default_gui) { - window = default_gui->second.window_types.find(type); + // Current GUI is the default one and no window type was found. Throw. + if(current_gui == default_gui) { + throw window_builder_invalid_id(); + } - if(window == default_gui->second.window_types.end()) { - throw window_builder_invalid_id(); - } - } else if(window == current_gui->second.window_types.end()) { + // Else, try again to find the window, this time in the default GUI. + window = default_gui->second.window_types.find(type); + + if(window == default_gui->second.window_types.end()) { throw window_builder_invalid_id(); } } const auto& resolutions = window->second.resolutions; - for(auto itor = resolutions.begin(); itor != resolutions.end(); ++itor) { - if((settings::screen_width <= itor->window_width && - settings::screen_height <= itor->window_height) || itor == resolutions.end() - 1) - { - return itor; + VALIDATE(!resolutions.empty(), formatter() << "Window '" << type << "' has no resolutions.\n"); + + for(const auto& res : resolutions) { + if(settings::screen_width <= res.window_width && settings::screen_height <= res.window_height) { + return res; } } - FAIL(formatter() << "Window '" << type << "' has no resolutions.\n"); + // If no matching resolution was found, return the last builder. + return resolutions.back(); } /*WIKI @@ -650,21 +649,21 @@ bool add_single_widget_definition(const std::string& widget_type, const std::str throw std::invalid_argument("widget '" + widget_type + "' doesn't exist"); } - if(gui.control_definition[widget_type].find(definition_id) != gui.control_definition[widget_type].end()) { + if(gui.widget_types[widget_type].find(definition_id) != gui.widget_types[widget_type].end()) { return false; } - gui.control_definition[widget_type].emplace(definition_id, parser->second.parser(cfg)); + gui.widget_types[widget_type].emplace(definition_id, parser->second.parser(cfg)); return true; } void remove_single_widget_definition(const std::string& widget_type, const std::string& definition_id) { - auto& gui = default_gui->second; - auto it = gui.control_definition[widget_type].find(definition_id); + auto& definition_map = default_gui->second.widget_types[widget_type]; + auto it = definition_map.find(definition_id); - if(it != gui.control_definition[widget_type].end()) { - gui.control_definition[widget_type].erase(it); + if(it != definition_map.end()) { + definition_map.erase(it); } } diff --git a/src/gui/widgets/settings.hpp b/src/gui/widgets/settings.hpp index f8906b8fe4ee..fa55ff8af1d0 100644 --- a/src/gui/widgets/settings.hpp +++ b/src/gui/widgets/settings.hpp @@ -31,7 +31,7 @@ namespace gui2 { -struct gui_definition; +class gui_definition; class game_tip; /** Do we wish to use the new library or not. */ @@ -67,8 +67,11 @@ class unit_test_access_only static std::vector get_registered_window_list(); }; +/** Function type alias for @ref register_widget. */ +using widget_parser_t = std::function; + /** - * Registers a widgets. + * Registers a widget. * * This function registers the available widgets defined in WML. All widgets * need to register themselves before @ref gui2::init) is called. @@ -78,9 +81,10 @@ class unit_test_access_only * * @param id The id of the widget to register. * @param functor The function to parse the definition config. - * @param key the tagname to read the widgetsdeiniftion from the game config, nullptr means use the default [_definition]. + * @param key The tagname from which to read the widget's definition in the game config. + * If nullptr the default [_definition] is used. */ -void register_widget(const std::string& id, std::function f, const char* key = nullptr); +void register_widget(const std::string& id, widget_parser_t f, const char* key = nullptr); /** * Loads the definitions of a widget. @@ -97,8 +101,6 @@ void load_widget_definitions( const std::string& definition_type, const std::vector& definitions); - - resolution_definition_ptr get_control(const std::string& control_type, const std::string& definition); @@ -112,10 +114,9 @@ struct window_builder_invalid_id }; /** - * Returns an interator to the requested builder. + * Returns an reference to the requested builder. * - * The builder is determined by the @p type and the current screen - * resolution. + * The builder is determined by the @p type and the current screen resolution. * * @pre There is a valid builder for @p type at the * current resolution. @@ -127,8 +128,7 @@ struct window_builder_invalid_id * * @returns An iterator to the requested builder. */ -std::vector::const_iterator -get_window_builder(const std::string& type); +const builder_window::window_resolution& get_window_builder(const std::string& type); /** Loads the setting for the theme. */ void load_settings();