From a688ab77b9f18db7fd34118267a3c59e9cf5584c Mon Sep 17 00:00:00 2001 From: Charles Dang Date: Tue, 24 Apr 2018 03:34:35 +1100 Subject: [PATCH] Some refactoring of preferences-related hotkey info storage (fixes #2953) This commit does a few things: First, it moves the hotkey category names out of the preferences dialog and into the more appropriate hotkey file. Each name is now properly mapped to its corresponding category enum, so we don't have to worry about that anymore. Second, it adds a new mapping of hotkey categories to commands so one can easily fetch a list of hotkeys in a given category. Third, it excludes categories with no hotkeys from the filter dropdown in the Prefs dialog (this is the part that actually fixes the bug above). This also includes a slight behavior change to hotkey type filtering. Previously, if a hotkey's category didn't match any of the ones listed in the dropdown, that hotkey's row visibility would be set to the toggle state of the first row in the filter dropdown. Now it gets set to false. (cherry-picked from commit 1942627052298aca366147fbf59ee0e268810875) --- src/gui/dialogs/preferences_dialog.cpp | 42 +++++++------------ src/gui/dialogs/preferences_dialog.hpp | 11 ++--- src/hotkey/hotkey_command.cpp | 58 ++++++++++++++++++++------ src/hotkey/hotkey_command.hpp | 18 +++++++- 4 files changed, 85 insertions(+), 44 deletions(-) diff --git a/src/gui/dialogs/preferences_dialog.cpp b/src/gui/dialogs/preferences_dialog.cpp index bdce1fa3d5d9..009bd1a59955 100644 --- a/src/gui/dialogs/preferences_dialog.cpp +++ b/src/gui/dialogs/preferences_dialog.cpp @@ -22,7 +22,6 @@ #include "formatter.hpp" #include "formula/string_utils.hpp" #include "preferences/game.hpp" -#include "hotkey/hotkey_command.hpp" #include "hotkey/hotkey_item.hpp" #include "preferences/credentials.hpp" #include "preferences/lobby.hpp" @@ -133,24 +132,12 @@ preferences_dialog::preferences_dialog(const config& game_cfg, const PREFERENCE_ return lhs["name"].t_str().str() < rhs["name"].t_str().str(); }); - cat_names_ = { - // TODO: This list needs to be synchronized with the hotkey::HOTKEY_CATEGORY enum - // Find some way to do that automatically - _("General"), - _("Saved Games"), - _("Map Commands"), - _("Unit Commands"), - _("Player Chat"), - _("Replay Control"), - _("Planning Mode"), - _("Scenario Editor"), - _("Editor Palettes"), - _("Editor Tools"), - _("Editor Clipboard"), - _("Debug Commands"), - _("Custom WML Commands"), - // HKCAT_PLACEHOLDER intentionally excluded (it shouldn't have any anyway) - }; + for(const auto& name : hotkey::get_category_names()) { + // Don't include categories with no hotkeys + if(!hotkey::get_hotkeys_by_category(name.first).empty()) { + cat_names_[name.first] = t_string(name.second, "wesnoth-lib"); + } + } } // Helper function to refresh resolution list @@ -745,7 +732,7 @@ void preferences_dialog::post_build(window& window) std::vector hotkey_category_entries; for(const auto& name : cat_names_) { - hotkey_category_entries.emplace_back("label", name, "checkbox", false); + hotkey_category_entries.emplace_back("label", name.second, "checkbox", false); } multimenu_button& hotkey_menu = find_widget(&window, "hotkey_category_menu", false); @@ -925,16 +912,19 @@ void preferences_dialog::hotkey_type_filter_callback(window& window) const for(std::size_t h = 0; h < visible_hotkeys_.size(); ++h) { int index = 0; - for(std::size_t i = 0; i < cat_names_.size(); ++i) { - hotkey::HOTKEY_CATEGORY cat = hotkey::HOTKEY_CATEGORY(i); - - if(visible_hotkeys_[h]->category == cat) { - index = i; + for(const auto& name : cat_names_) { + if(visible_hotkeys_[h]->category == name.first) { break; + } else { + ++index; } } - res[h] = toggle_states[index]; + if(index < toggle_states.size()) { + res[h] = toggle_states[index]; + } else { + res[h] = false; + } } } else { // Nothing selected. It means that *all* categories are shown. diff --git a/src/gui/dialogs/preferences_dialog.hpp b/src/gui/dialogs/preferences_dialog.hpp index c4dce89e17d6..4cfa67f51d5c 100644 --- a/src/gui/dialogs/preferences_dialog.hpp +++ b/src/gui/dialogs/preferences_dialog.hpp @@ -16,10 +16,11 @@ #pragma once #include "config.hpp" -#include "preferences/game.hpp" -#include "utils/make_enum.hpp" #include "gui/dialogs/modal_dialog.hpp" #include "gui/widgets/group.hpp" +#include "hotkey/hotkey_command.hpp" +#include "preferences/game.hpp" +#include "utils/make_enum.hpp" #include @@ -79,7 +80,7 @@ class preferences_dialog : public modal_dialog preferences_dialog(game_cfg, initial_view).show(); } - typedef std::vector t_visible_hotkeys; + typedef std::vector visible_hotkeys_t; private: /** Inherited from modal_dialog, implemented by REGISTER_DIALOG. */ @@ -136,9 +137,9 @@ class preferences_dialog : public modal_dialog int last_selected_item_; std::vector accl_speeds_; - t_visible_hotkeys visible_hotkeys_; + visible_hotkeys_t visible_hotkeys_; - std::vector cat_names_; + std::map cat_names_; // The page/tab index pairs for setting visible pages const std::pair& initial_index_; diff --git a/src/hotkey/hotkey_command.cpp b/src/hotkey/hotkey_command.cpp index 9c38c2a3a601..55ebcfbd90ed 100644 --- a/src/hotkey/hotkey_command.cpp +++ b/src/hotkey/hotkey_command.cpp @@ -30,9 +30,27 @@ static lg::log_domain log_config("config"); #define DBG_G LOG_STREAM(debug, lg::general()) #define ERR_CF LOG_STREAM(err, log_config) +namespace hotkey +{ namespace { -using namespace hotkey; +const category_name_map_t category_names { + { HKCAT_GENERAL, N_("General") }, + { HKCAT_SAVING, N_("Saved Games") }, + { HKCAT_MAP, N_("Map Commands") }, + { HKCAT_UNITS, N_("Unit Commands") }, + { HKCAT_CHAT, N_("Player Chat") }, + { HKCAT_REPLAY, N_("Replay Control") }, + { HKCAT_WHITEBOARD, N_("Planning Mode") }, + { HKCAT_SCENARIO, N_("Scenario Editor") }, + { HKCAT_PALETTE, N_("Editor Palettes") }, + { HKCAT_TOOLS, N_("Editor Tools") }, + { HKCAT_CLIPBOARD, N_("Editor Clipboard") }, + { HKCAT_DEBUG, N_("Debug Commands") }, + { HKCAT_CUSTOM, N_("Custom WML Commands") }, +}; + +std::map> hotkeys_by_category; // Make them global ? hk_scopes scope_game(1 << SCOPE_GAME); @@ -46,7 +64,7 @@ hk_scopes scope_main(1 << SCOPE_MAIN_MENU); // Since HOTKEY_NULL is the last entry in said enum, we can use its index to dynamically // size the array. // -std::array hotkey_list_ {{ +std::array master_hotkey_list {{ { HOTKEY_SCROLL_UP, "scroll-up", N_("Scroll Up"), false, scope_game | scope_editor, HKCAT_GENERAL, "" }, { HOTKEY_SCROLL_DOWN, "scroll-down", N_("Scroll Down"), false, scope_game | scope_editor, HKCAT_GENERAL, "" }, { HOTKEY_SCROLL_LEFT, "scroll-left", N_("Scroll Left"), false, scope_game | scope_editor, HKCAT_GENERAL, "" }, @@ -290,18 +308,16 @@ std::set toggle_commands { HOTKEY_SCROLL_RIGHT }; -// Contains copies of hotkey_list_ and all current active wml menu hotkeys +// Contains copies of master_hotkey_list and all current active wml menu hotkeys // TODO: Maybe known_hotkeys is not a fitting name anymore. std::vector known_hotkeys; -// Index map for known_hotkeys. Since known_hotkeys begins with hotkey_list_, they are also indexes for hotkey_list_. +// Index map for known_hotkeys. Since known_hotkeys begins with master_hotkey_list, they are also indexes for master_hotkey_list. std::map command_map_; hk_scopes scope_active_(0); } // end anon namespace -namespace hotkey -{ scope_changer::scope_changer() : prev_scope_active_(scope_active_) { @@ -496,8 +512,8 @@ const hotkey_command& hotkey_command::get_command_by_command(hotkey::HOTKEY_COMM const hotkey_command& get_hotkey_null() { - // It is the last entry in that array, and the indexes in hotkey_list_ and known_hotkeys are the same. - return known_hotkeys[hotkey_list_.size() - 1]; + // It is the last entry in that array, and the indexes in master_hotkey_list and known_hotkeys are the same. + return known_hotkeys[master_hotkey_list.size() - 1]; } void delete_all_wml_hotkeys() @@ -507,6 +523,8 @@ void delete_all_wml_hotkeys() known_hotkeys.pop_back(); } + + hotkeys_by_category[HKCAT_CUSTOM].clear(); } const std::string& get_description(const std::string& command) @@ -523,19 +541,24 @@ const std::string& get_tooltip(const std::string& command) void init_hotkey_commands() { known_hotkeys.clear(); + hotkeys_by_category.clear(); // Reserve enough space for the built-in hotkeys and 20 extra spaces for WML hotkeys. This is // to avoid reallocation of this huge vector when any of the latter are added. 20 is honestly // overkill, since there's really no reason to ever have near that many hotkey-enabled WML menu // items, but it doesn't cost us anything to have extra. - known_hotkeys.reserve(hotkey_list_.size() + 20); + known_hotkeys.reserve(master_hotkey_list.size() + 20); std::size_t i = 0; - for(hotkey_command_temp& cmd : hotkey_list_) { + for(const hotkey_command_temp& cmd : master_hotkey_list) { + // Initialize the full hotkey from the temp data. known_hotkeys.emplace_back(cmd); - command_map_[cmd.command] = i; - ++i; + // Note the known_hotkeys index associated with this command. + command_map_[cmd.command] = i++; + + // Record this hotkey's id in the appropriate category list. + hotkeys_by_category[cmd.category].push_back(cmd.id); } } @@ -548,4 +571,15 @@ HOTKEY_COMMAND get_id(const std::string& command) { return get_hotkey_command(command).id; } + +const category_name_map_t& get_category_names() +{ + return category_names; } + +std::list get_hotkeys_by_category(HOTKEY_CATEGORY category) +{ + return hotkeys_by_category[category]; +} + +} // namespace hotkey diff --git a/src/hotkey/hotkey_command.hpp b/src/hotkey/hotkey_command.hpp index 84d8d1b72e30..d236111af9f9 100644 --- a/src/hotkey/hotkey_command.hpp +++ b/src/hotkey/hotkey_command.hpp @@ -18,6 +18,8 @@ #include "tstring.hpp" #include +#include +#include #include class config; @@ -206,10 +208,24 @@ enum HOTKEY_CATEGORY { HKCAT_PLACEHOLDER // Keep this one last }; +using category_name_map_t = std::map; + +/** + * Returns the map of hotkey categories and their display names. + * + * These aren't translated and need be converted to a t_string before + * being displayed to the player. + */ +const category_name_map_t& get_category_names(); + +/** Returns a list of all the hotkeys belonging to the given category. */ +std::list get_hotkeys_by_category(HOTKEY_CATEGORY category); + typedef std::bitset hk_scopes; /// Do not use this outside hotkeys.cpp. -/// hotkey_command uses t_string which might cause bugs when used at program startup, so use this for the hotkey_list_ (and only there). +/// hotkey_command uses t_string which might cause bugs when used at program startup, +/// so use this for the master hotkey list (and only there). struct hotkey_command_temp { HOTKEY_COMMAND id;