mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-21 16:52:21 +00:00
Refactor hotkey_handler::do_execute_command
previously, when showing a menu, the hotkey handler would generate menu items, and then track the index they are in, which means they had to keep track of which items were inserted at which position, which made the code rather complicated. Now the hoteky handler generates a informative command id string for each of those those generated menu items which is then passed back to do_execute_command. To do this we change, the parameter of do_execute_command and related functions to use a new struct type, (the parameter used to be just a HOTKEY_COMMAND enum, then (when wml command hoeky were added) it changes to hotkey_command structs, but didn't really match the uses of that function since is also used with menu items that aren't hotkey commands) The new struct is also easier to pass around and should also make future refactors of this funcction easier. With this there are in particular no longer two different codepaths for wml menu items fired via hotkeys and wml menu items fired via the right click menu. This removed also a few codes that i think are now unnecessary, in particular for old markup, and codes that uses the "id" for label (the code that generates the menu items now simply sets the "label" attribute).
This commit is contained in:
parent
d159f3e70d
commit
17a1bbd777
@ -451,10 +451,10 @@ void controller_base::show_menu(
|
||||
std::vector<config> items;
|
||||
for(const config& c : items_arg) {
|
||||
const std::string& id = c["id"];
|
||||
const hotkey::hotkey_command& command = hotkey::get_hotkey_command(id);
|
||||
const hotkey::ui_command cmd = hotkey::ui_command(id);
|
||||
|
||||
if(cmd_exec->can_execute_command(command) && (!context_menu || in_context_menu(command.command))) {
|
||||
items.emplace_back("id", id);
|
||||
if(cmd_exec->can_execute_command(cmd) && (!context_menu || in_context_menu(cmd))) {
|
||||
items.emplace_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,8 +474,8 @@ void controller_base::execute_action(const std::vector<std::string>& items_arg,
|
||||
|
||||
std::vector<std::string> items;
|
||||
for(const std::string& item : items_arg) {
|
||||
const hotkey::hotkey_command& command = hotkey::get_hotkey_command(item);
|
||||
if(cmd_exec->can_execute_command(command)) {
|
||||
hotkey::ui_command cmd = hotkey::ui_command(item);
|
||||
if(cmd_exec->can_execute_command(cmd)) {
|
||||
items.push_back(item);
|
||||
}
|
||||
}
|
||||
@ -487,7 +487,7 @@ void controller_base::execute_action(const std::vector<std::string>& items_arg,
|
||||
cmd_exec->execute_action(items, xloc, yloc, context_menu, get_display());
|
||||
}
|
||||
|
||||
bool controller_base::in_context_menu(hotkey::HOTKEY_COMMAND /*command*/) const
|
||||
bool controller_base::in_context_menu(const hotkey::ui_command& /*command*/) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ class mouse_handler_base;
|
||||
namespace hotkey
|
||||
{
|
||||
class command_executor;
|
||||
struct ui_command;
|
||||
}
|
||||
|
||||
namespace soundsource
|
||||
@ -170,7 +171,7 @@ protected:
|
||||
virtual void show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& disp);
|
||||
virtual void execute_action(const std::vector<std::string>& items_arg, int xloc, int yloc, bool context_menu);
|
||||
|
||||
virtual bool in_context_menu(hotkey::HOTKEY_COMMAND command) const;
|
||||
virtual bool in_context_menu(const hotkey::ui_command& cmd) const;
|
||||
|
||||
void long_touch_callback(int x, int y);
|
||||
|
||||
|
@ -235,10 +235,11 @@ void editor_controller::custom_tods_dialog()
|
||||
context_manager_->refresh_all();
|
||||
}
|
||||
|
||||
bool editor_controller::can_execute_command(const hotkey::hotkey_command& cmd, int index) const
|
||||
bool editor_controller::can_execute_command(const hotkey::ui_command& cmd) const
|
||||
{
|
||||
using namespace hotkey; //reduce hotkey:: clutter
|
||||
switch(cmd.command) {
|
||||
int index = cmd.index;
|
||||
switch(cmd.hotkey_command) {
|
||||
case HOTKEY_NULL:
|
||||
if (index >= 0) {
|
||||
unsigned i = static_cast<unsigned>(index);
|
||||
@ -447,9 +448,11 @@ bool editor_controller::can_execute_command(const hotkey::hotkey_command& cmd, i
|
||||
}
|
||||
}
|
||||
|
||||
hotkey::ACTION_STATE editor_controller::get_action_state(hotkey::HOTKEY_COMMAND command, int index) const {
|
||||
hotkey::ACTION_STATE editor_controller::get_action_state(const hotkey::ui_command& cmd) const
|
||||
{
|
||||
using namespace hotkey;
|
||||
switch (command) {
|
||||
int index = cmd.index;
|
||||
switch (cmd.hotkey_command) {
|
||||
|
||||
case HOTKEY_EDITOR_UNIT_TOGGLE_LOYAL:
|
||||
{
|
||||
@ -508,7 +511,7 @@ hotkey::ACTION_STATE editor_controller::get_action_state(hotkey::HOTKEY_COMMAND
|
||||
case HOTKEY_EDITOR_TOOL_UNIT:
|
||||
case HOTKEY_EDITOR_TOOL_VILLAGE:
|
||||
case HOTKEY_EDITOR_TOOL_ITEM:
|
||||
return toolkit_->is_mouse_action_set(command) ? ACTION_ON : ACTION_OFF;
|
||||
return toolkit_->is_mouse_action_set(cmd.hotkey_command) ? ACTION_ON : ACTION_OFF;
|
||||
case HOTKEY_EDITOR_DRAW_COORDINATES:
|
||||
return gui_->debug_flag_set(display::DEBUG_COORDINATES) ? ACTION_ON : ACTION_OFF;
|
||||
case HOTKEY_EDITOR_DRAW_TERRAIN_CODES:
|
||||
@ -580,19 +583,20 @@ hotkey::ACTION_STATE editor_controller::get_action_state(hotkey::HOTKEY_COMMAND
|
||||
}
|
||||
return ACTION_ON;
|
||||
default:
|
||||
return command_executor::get_action_state(command, index);
|
||||
return command_executor::get_action_state(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
bool editor_controller::do_execute_command(const hotkey::hotkey_command& cmd, int index, bool press, bool release)
|
||||
bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool press, bool release)
|
||||
{
|
||||
hotkey::HOTKEY_COMMAND command = cmd.command;
|
||||
hotkey::HOTKEY_COMMAND command = cmd.hotkey_command;
|
||||
SCOPE_ED;
|
||||
using namespace hotkey;
|
||||
int index = cmd.index;
|
||||
|
||||
// nothing here handles release; fall through to base implementation
|
||||
if (!press) {
|
||||
return hotkey::command_executor::do_execute_command(cmd, index, press, release);
|
||||
return hotkey::command_executor::do_execute_command(cmd, press, release);
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
@ -988,7 +992,7 @@ bool editor_controller::do_execute_command(const hotkey::hotkey_command& cmd, in
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return hotkey::command_executor::do_execute_command(cmd, index, press, release);
|
||||
return hotkey::command_executor::do_execute_command(cmd, press, release);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1008,10 +1012,11 @@ void editor_controller::show_menu(const std::vector<config>& items_arg, int xloc
|
||||
std::vector<config> items;
|
||||
for(const auto& c : items_arg) {
|
||||
const std::string& id = c["id"];
|
||||
const hotkey::hotkey_command& command = hotkey::get_hotkey_command(id);
|
||||
|
||||
if((can_execute_command(command) && (!context_menu || in_context_menu(command.command)))
|
||||
|| command.command == hotkey::HOTKEY_NULL)
|
||||
const hotkey::ui_command cmd = hotkey::ui_command(hotkey::get_hotkey_command(id));
|
||||
|
||||
if((can_execute_command(cmd) && (!context_menu || in_context_menu(cmd)))
|
||||
|| cmd.hotkey_command == hotkey::HOTKEY_NULL)
|
||||
{
|
||||
items.emplace_back("id", id);
|
||||
}
|
||||
|
@ -103,13 +103,13 @@ class editor_controller : public controller_base,
|
||||
void save_map() override {context_manager_->save_map();}
|
||||
|
||||
/** command_executor override */
|
||||
bool can_execute_command(const hotkey::hotkey_command& command, int index = -1) const override;
|
||||
bool can_execute_command(const hotkey::ui_command& command) const override;
|
||||
|
||||
/** command_executor override */
|
||||
hotkey::ACTION_STATE get_action_state(hotkey::HOTKEY_COMMAND command, int index) const override;
|
||||
hotkey::ACTION_STATE get_action_state(const hotkey::ui_command& command) const override;
|
||||
|
||||
/** command_executor override */
|
||||
bool do_execute_command(const hotkey::hotkey_command& command, int index = -1, bool press = true, bool release = false) override;
|
||||
bool do_execute_command(const hotkey::ui_command& command, bool press = true, bool release = false) override;
|
||||
|
||||
/** controller_base override */
|
||||
void show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& disp) override;
|
||||
|
@ -114,12 +114,19 @@ public:
|
||||
|
||||
/**
|
||||
* The text to put in a menu for this item.
|
||||
* This will be either translated text or a hotkey identifier.
|
||||
*/
|
||||
std::string menu_text() const
|
||||
{
|
||||
return description_.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* The UI action id to be used in theme wml, menu items and hotkeys .
|
||||
*/
|
||||
std::string hotkey_id() const
|
||||
{
|
||||
// The space is to prevent accidental hotkey binding.
|
||||
return use_hotkey_ ? hotkey_id_ : description_.str() + ' ';
|
||||
return hotkey_id_;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,15 +107,13 @@ bool wmi_manager::fire_item(
|
||||
* Returns the menu items that can be shown for the given location.
|
||||
*
|
||||
* @param hex The current hex.
|
||||
* @param[out] items Pointers to applicable menu items will be pushed onto @a items.
|
||||
* @param[out] descriptions Menu item text will be pushed onto @a descriptions (in the same order as @a items).
|
||||
* @param[out] items Menu items. consisting of menu text, menu icons, and action ids.
|
||||
* @param fc Used to check whether the menu's filter matches.
|
||||
* @param gamedata Used to check whether to show if selecting is required.
|
||||
* @param units Used to highlight a unit if needed.
|
||||
*/
|
||||
void wmi_manager::get_items(const map_location& hex,
|
||||
std::vector<std::shared_ptr<const wml_menu_item>>& items,
|
||||
std::vector<config>& descriptions,
|
||||
std::vector<config>& items,
|
||||
filter_context& fc,
|
||||
game_data& gamedata,
|
||||
unit_map& units) const
|
||||
@ -142,8 +140,7 @@ void wmi_manager::get_items(const map_location& hex,
|
||||
if(item->use_wml_menu() && (!item->is_synced() || resources::controller->can_use_synced_wml_menu())
|
||||
&& item->can_show(hex, gamedata, fc)) {
|
||||
// Include this item.
|
||||
items.push_back(item);
|
||||
descriptions.emplace_back("id", item->menu_text());
|
||||
items.emplace_back("id", item->hotkey_id() , "label", item->menu_text(), "icon", item->image());
|
||||
}
|
||||
}
|
||||
gamedata.get_variable("x1") = x1;
|
||||
|
@ -73,8 +73,7 @@ public:
|
||||
|
||||
/** Returns the menu items that can be shown for the given location. */
|
||||
void get_items(const map_location& hex,
|
||||
std::vector<std::shared_ptr<const wml_menu_item>>& items,
|
||||
std::vector<config>& descriptions,
|
||||
std::vector<config>& items,
|
||||
filter_context& fc,
|
||||
game_data& gamedata,
|
||||
unit_map& units) const;
|
||||
|
@ -70,11 +70,11 @@ namespace hotkey {
|
||||
|
||||
static void event_queue(const SDL_Event& event, command_executor* executor);
|
||||
|
||||
bool command_executor::do_execute_command(const hotkey_command& cmd, int /*index*/, bool press, bool release)
|
||||
bool command_executor::do_execute_command(const hotkey::ui_command& cmd, bool press, bool release)
|
||||
{
|
||||
// hotkey release handling
|
||||
if (release) {
|
||||
switch(cmd.command) {
|
||||
switch(cmd.hotkey_command) {
|
||||
// release a scroll key, un-apply scrolling in the given direction
|
||||
case HOTKEY_SCROLL_UP:
|
||||
scroll_up(false);
|
||||
@ -96,7 +96,7 @@ bool command_executor::do_execute_command(const hotkey_command& cmd, int /*inde
|
||||
}
|
||||
|
||||
// handling of hotkeys which activate even on hold events
|
||||
switch(cmd.command) {
|
||||
switch(cmd.hotkey_command) {
|
||||
case HOTKEY_REPEAT_RECRUIT:
|
||||
repeat_recruit();
|
||||
return true;
|
||||
@ -121,7 +121,7 @@ bool command_executor::do_execute_command(const hotkey_command& cmd, int /*inde
|
||||
}
|
||||
|
||||
// hotkey press handling
|
||||
switch(cmd.command) {
|
||||
switch(cmd.hotkey_command) {
|
||||
case HOTKEY_CYCLE_UNITS:
|
||||
cycle_units();
|
||||
break;
|
||||
@ -427,14 +427,15 @@ void command_executor::show_menu(const std::vector<config>& items_arg, int xloc,
|
||||
} // This will kill the dialog.
|
||||
if (res < 0 || std::size_t(res) >= items.size()) return;
|
||||
|
||||
const theme::menu* submenu = gui.get_theme().get_menu_item(items[res]["id"]);
|
||||
std::string id = items[res]["id"];
|
||||
const theme::menu* submenu = gui.get_theme().get_menu_item(id);
|
||||
if (submenu) {
|
||||
int y,x;
|
||||
sdl::get_mouse_state(&x,&y);
|
||||
this->show_menu(submenu->items(), x, y, submenu->is_context(), gui);
|
||||
} else {
|
||||
const hotkey::hotkey_command& cmd = hotkey::get_hotkey_command(items[res]["id"]);
|
||||
do_execute_command(cmd, res);
|
||||
hotkey::ui_command cmd = hotkey::ui_command(id, res);
|
||||
do_execute_command(cmd);
|
||||
set_button_state();
|
||||
}
|
||||
}
|
||||
@ -448,29 +449,22 @@ void command_executor::execute_action(const std::vector<std::string>& items_arg,
|
||||
|
||||
std::vector<std::string>::iterator i = items.begin();
|
||||
while(i != items.end()) {
|
||||
const hotkey_command &command = hotkey::get_hotkey_command(*i);
|
||||
if (can_execute_command(command)) {
|
||||
do_execute_command(command);
|
||||
hotkey::ui_command cmd = hotkey::ui_command(*i);
|
||||
if (can_execute_command(cmd)) {
|
||||
do_execute_command(cmd);
|
||||
set_button_state();
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
std::string command_executor::get_menu_image(display& disp, const std::string& command, int index) const {
|
||||
|
||||
// TODO: Find a way to do away with the fugly special markup
|
||||
if(command[0] == '&') {
|
||||
std::size_t n = command.find_first_of('=');
|
||||
if(n != std::string::npos)
|
||||
return command.substr(1, n - 1);
|
||||
}
|
||||
|
||||
std::string command_executor::get_menu_image(display& disp, const std::string& command, int index) const
|
||||
{
|
||||
const std::string base_image_name = "icons/action/" + command + "_25.png";
|
||||
const std::string pressed_image_name = "icons/action/" + command + "_25-pressed.png";
|
||||
|
||||
const hotkey::HOTKEY_COMMAND hk = hotkey::get_hotkey_command(command).command;
|
||||
const hotkey::ACTION_STATE state = get_action_state(hk, index);
|
||||
hotkey::ui_command cmd = hotkey::ui_command(command, index);
|
||||
const hotkey::ACTION_STATE state = get_action_state(cmd);
|
||||
|
||||
const theme::menu* menu = disp.get_theme().get_menu_item(command);
|
||||
if (menu) {
|
||||
@ -487,7 +481,7 @@ std::string command_executor::get_menu_image(display& disp, const std::string& c
|
||||
}
|
||||
}
|
||||
|
||||
switch (get_action_state(hk, index)) {
|
||||
switch (get_action_state(cmd)) {
|
||||
case ACTION_ON:
|
||||
return game_config::images::checked_menu;
|
||||
case ACTION_OFF:
|
||||
@ -496,7 +490,7 @@ std::string command_executor::get_menu_image(display& disp, const std::string& c
|
||||
return game_config::images::selected_menu;
|
||||
case ACTION_DESELECTED:
|
||||
return game_config::images::deselected_menu;
|
||||
default: return get_action_image(hk, index);
|
||||
default: return get_action_image(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,12 +522,6 @@ void command_executor::get_menu_images(display& disp, std::vector<config>& items
|
||||
|
||||
item["label"] = desc;
|
||||
item["details"] = hotkey::get_names(item_id);
|
||||
} else if(item["label"].empty()) {
|
||||
// If no matching hotkey was found and a custom label wasn't already set, treat
|
||||
// the id as a plaintext description. This is because either type of value can
|
||||
// be written to the id field by the WMI manager. The plaintext description is
|
||||
// used in the case the menu item specifies the relevant entry is *not* a hotkey.
|
||||
item["label"] = item_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -625,8 +613,9 @@ void command_executor::queue_command(const SDL_Event& event, int index)
|
||||
|
||||
void command_executor::execute_command_wrap(const command_executor::queued_command& command)
|
||||
{
|
||||
if (!can_execute_command(*command.command, command.index)
|
||||
|| do_execute_command(*command.command, command.index, command.press, command.release)) {
|
||||
auto ui_cmd = hotkey::ui_command(*command.command, command.index);
|
||||
if (!can_execute_command(ui_cmd)
|
||||
|| do_execute_command(ui_cmd, command.press, command.release)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -687,7 +676,7 @@ void command_executor_default::set_button_state()
|
||||
bool enabled = false;
|
||||
for (const auto& command : menu.items()) {
|
||||
|
||||
const hotkey::hotkey_command& command_obj = hotkey::get_hotkey_command(command["id"]);
|
||||
ui_command command_obj = ui_command(command["id"].str());
|
||||
bool can_execute = can_execute_command(command_obj);
|
||||
if (can_execute) {
|
||||
enabled = true;
|
||||
@ -705,7 +694,7 @@ void command_executor_default::set_button_state()
|
||||
int i = 0;
|
||||
for (const std::string& command : action.items()) {
|
||||
|
||||
const hotkey::hotkey_command& command_obj = hotkey::get_hotkey_command(command);
|
||||
ui_command command_obj = ui_command(command);
|
||||
std::string tooltip = action.tooltip(i);
|
||||
if (filesystem::file_exists(game_config::path + "/images/icons/action/" + command + "_25.png" ))
|
||||
button->set_overlay("icons/action/" + command);
|
||||
@ -717,7 +706,7 @@ void command_executor_default::set_button_state()
|
||||
if (!can_execute) continue;
|
||||
enabled = true;
|
||||
|
||||
ACTION_STATE state = get_action_state(command_obj.command, -1);
|
||||
ACTION_STATE state = get_action_state(command_obj);
|
||||
switch (state) {
|
||||
case ACTION_SELECTED:
|
||||
case ACTION_ON:
|
||||
|
@ -26,6 +26,38 @@ namespace hotkey {
|
||||
|
||||
enum ACTION_STATE { ACTION_STATELESS, ACTION_ON, ACTION_OFF, ACTION_SELECTED, ACTION_DESELECTED };
|
||||
|
||||
/// Used as the main paramneter for can_execute_command/do_execute_command
|
||||
/// These functions are used to execute hotkeys but also to execute menu items,
|
||||
/// (Most menu items point to the same action as a hotkey but not all)
|
||||
struct ui_command
|
||||
{
|
||||
/// The hotkey::HOTKEY_COMMAND associated with this action, HOTKEY_NULL for actions that don't allow hotkey binding.
|
||||
/// different actions of the ame type might have the same HOTKEY_COMMAND (like different wml menu items that allow
|
||||
// hotkey bindings.). This is prefered to be used for comparision over id (for example being an enum makes it
|
||||
/// imposible to make typos in the id and its faster, plus c++ unfortunateley doesn't allow switch statements with
|
||||
// strings)
|
||||
hotkey::HOTKEY_COMMAND hotkey_command;
|
||||
/// The string command, never empty, describes the action uniquely. when the action is the result of a menu click
|
||||
// this matches the id element of the clicked item (the id paraemter of show_menu)
|
||||
std::string id;
|
||||
/// When this action was the result of a menu click, this is the index of the clicked item in the menu.
|
||||
int index;
|
||||
ui_command(hotkey::HOTKEY_COMMAND hotkey_command, std::string_view id, int index = -1)
|
||||
: hotkey_command(hotkey_command)
|
||||
, id(id)
|
||||
, index(index)
|
||||
{ }
|
||||
explicit ui_command(const hotkey::hotkey_command& cmd, int index = -1)
|
||||
: ui_command(cmd.command, cmd.id, index)
|
||||
{ }
|
||||
// the string @param id references must live longer than this object.
|
||||
explicit ui_command(std::string_view id, int index = -1)
|
||||
: ui_command(hotkey::HOTKEY_NULL, id, index)
|
||||
{
|
||||
hotkey_command = hotkey::get_hotkey_command(std::string(id)).command;
|
||||
}
|
||||
};
|
||||
|
||||
// Abstract base class for objects that implement the ability
|
||||
// to execute hotkey commands.
|
||||
class command_executor
|
||||
@ -125,9 +157,9 @@ public:
|
||||
|
||||
// execute_command's parameter is changed to "hotkey_command& command" and this not maybe that is too inconsistent.
|
||||
// Gets the action's image (if any). Displayed left of the action text in menus.
|
||||
virtual std::string get_action_image(hotkey::HOTKEY_COMMAND /*command*/, int /*index*/) const { return ""; }
|
||||
virtual std::string get_action_image(const hotkey::ui_command&) const { return ""; }
|
||||
// Does the action control a toggle switch? If so, return the state of the action (on or off).
|
||||
virtual ACTION_STATE get_action_state(hotkey::HOTKEY_COMMAND /*command*/, int /*index*/) const { return ACTION_STATELESS; }
|
||||
virtual ACTION_STATE get_action_state(const hotkey::ui_command&) const { return ACTION_STATELESS; }
|
||||
// Returns the appropriate menu image. Checkable items will get a checked/unchecked image.
|
||||
std::string get_menu_image(display& disp, const std::string& command, int index=-1) const;
|
||||
// Returns a vector of images for a given menu.
|
||||
@ -136,13 +168,13 @@ public:
|
||||
virtual void show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& gui);
|
||||
void execute_action(const std::vector<std::string>& items_arg, int xloc, int yloc, bool context_menu, display& gui);
|
||||
|
||||
virtual bool can_execute_command(const hotkey_command& command, int index=-1) const = 0;
|
||||
virtual bool can_execute_command(const hotkey::ui_command& command) const = 0;
|
||||
void queue_command(const SDL_Event& event, int index = -1);
|
||||
bool run_queued_commands();
|
||||
void execute_quit_command()
|
||||
{
|
||||
const hotkey_command& quit_hotkey = hotkey_command::get_command_by_command(hotkey::HOTKEY_QUIT_GAME);
|
||||
do_execute_command(quit_hotkey);
|
||||
do_execute_command(ui_command(quit_hotkey));
|
||||
}
|
||||
|
||||
void handle_keyup()
|
||||
@ -151,7 +183,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool do_execute_command(const hotkey_command& command, int index=-1, bool press=true, bool release=false);
|
||||
virtual bool do_execute_command(const hotkey::ui_command& command, bool press=true, bool release=false);
|
||||
|
||||
private:
|
||||
struct queued_command
|
||||
|
@ -302,7 +302,7 @@ constexpr std::array<hotkey_command_temp, HOTKEY_NULL - 1> master_hotkey_list {{
|
||||
{ LUA_CONSOLE, "global__lua__console", N_("Show Lua Console"), false, scope_game | scope_editor | scope_main, HKCAT_DEBUG, ""},
|
||||
|
||||
//This list item must stay at the end since it is used as terminator for iterating.
|
||||
{ HOTKEY_NULL, "null", N_("Unrecognized Command"), true, SCOPE_COUNT, HKCAT_PLACEHOLDER, "" }
|
||||
{ HOTKEY_NULL, "null", N_("Unrecognized Command"), true, 0, HKCAT_PLACEHOLDER, "" }
|
||||
}};
|
||||
|
||||
const std::set<HOTKEY_COMMAND> toggle_commands {
|
||||
|
@ -33,17 +33,21 @@
|
||||
#include "saved_game.hpp"
|
||||
#include "whiteboard/manager.hpp"
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
namespace balg = boost::algorithm;
|
||||
|
||||
#include "units/unit.hpp"
|
||||
|
||||
const std::string play_controller::hotkey_handler::wml_menu_hotkey_prefix = "wml_menu:";
|
||||
|
||||
static const std::string quickload_prefix = "quickload:";
|
||||
|
||||
play_controller::hotkey_handler::hotkey_handler(play_controller & pc, saved_game & sg)
|
||||
: play_controller_(pc)
|
||||
, menu_handler_(pc.get_menu_handler())
|
||||
, mouse_handler_(pc.get_mouse_handler_base())
|
||||
, saved_game_(sg)
|
||||
, savenames_()
|
||||
, wml_commands_()
|
||||
, last_context_menu_x_(0)
|
||||
, last_context_menu_y_(0)
|
||||
{}
|
||||
@ -250,42 +254,28 @@ void play_controller::hotkey_handler::scroll_right(bool on)
|
||||
play_controller_.set_scroll_right(on);
|
||||
}
|
||||
|
||||
bool play_controller::hotkey_handler::do_execute_command(const hotkey::hotkey_command& cmd, int index, bool press, bool release)
|
||||
bool play_controller::hotkey_handler::do_execute_command(const hotkey::ui_command& cmd, bool press, bool release)
|
||||
{
|
||||
hotkey::HOTKEY_COMMAND command = cmd.command;
|
||||
if(index >= 0) {
|
||||
unsigned i = static_cast<unsigned>(index);
|
||||
if(i < savenames_.size() && !savenames_[i].empty()) {
|
||||
// Load the game by throwing load_game_exception
|
||||
load_autosave(savenames_[i]);
|
||||
|
||||
} else if ( i < wml_commands_.size() && wml_commands_[i] ) {
|
||||
wml_commands_[i]->fire_event(mouse_handler_.get_last_hex(), gamestate().gamedata_);
|
||||
return true;
|
||||
}
|
||||
if(balg::starts_with(cmd.id, quickload_prefix)) {
|
||||
std::string savename = std::string(cmd.id.substr(quickload_prefix.size()));
|
||||
// Load the game by throwing load_game_exception
|
||||
load_autosave(savename, false);
|
||||
}
|
||||
int prefixlen = wml_menu_hotkey_prefix.length();
|
||||
if(command == hotkey::HOTKEY_WML && cmd.id.compare(0, prefixlen, wml_menu_hotkey_prefix) == 0)
|
||||
{
|
||||
std::string name = cmd.id.substr(prefixlen);
|
||||
// TODO c++20: Use string::starts_with
|
||||
// wml commands that don't allow hotkey bindings use hotkey::HOTKEY_NULL. othes use HOTKEY_WML
|
||||
if(balg::starts_with(cmd.id, wml_menu_hotkey_prefix)) {
|
||||
std::string name = std::string(cmd.id.substr(wml_menu_hotkey_prefix.length()));
|
||||
const map_location& hex = mouse_handler_.get_last_hex();
|
||||
|
||||
return gamestate().get_wml_menu_items().fire_item(
|
||||
name, hex, gamestate().gamedata_, gamestate(), play_controller_.get_units(), !press);
|
||||
}
|
||||
return command_executor::do_execute_command(cmd, index, press, release);
|
||||
return command_executor::do_execute_command(cmd, press, release);
|
||||
}
|
||||
|
||||
bool play_controller::hotkey_handler::can_execute_command(const hotkey::hotkey_command& cmd, int index) const
|
||||
bool play_controller::hotkey_handler::can_execute_command(const hotkey::ui_command& cmd) const
|
||||
{
|
||||
if(index >= 0) {
|
||||
unsigned i = static_cast<unsigned>(index);
|
||||
if((i < savenames_.size() && !savenames_[i].empty())
|
||||
|| (i < wml_commands_.size() && wml_commands_[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
switch(cmd.command) {
|
||||
switch(cmd.hotkey_command) {
|
||||
|
||||
// Commands we can always do:
|
||||
case hotkey::HOTKEY_LEADER:
|
||||
@ -328,7 +318,7 @@ bool play_controller::hotkey_handler::can_execute_command(const hotkey::hotkey_c
|
||||
case hotkey::HOTKEY_MINIMAP_DRAW_UNITS:
|
||||
case hotkey::HOTKEY_MINIMAP_DRAW_TERRAIN:
|
||||
case hotkey::HOTKEY_MINIMAP_DRAW_VILLAGES:
|
||||
case hotkey::HOTKEY_NULL:
|
||||
case hotkey::HOTKEY_NULL: // HOTKEY_NULL is used for menu items that don't allow hotkey bindings (for example load autosave, wml menu items and menus)
|
||||
case hotkey::HOTKEY_SAVE_REPLAY:
|
||||
case hotkey::HOTKEY_LABEL_SETTINGS:
|
||||
case hotkey::LUA_CONSOLE:
|
||||
@ -403,53 +393,53 @@ static void trim_items(std::vector<T>& newitems)
|
||||
}
|
||||
}
|
||||
|
||||
void play_controller::hotkey_handler::expand_autosaves(std::vector<config>& items, int i)
|
||||
{
|
||||
template<typename F>
|
||||
static void foreach_autosave(int turn, saved_game& sg, F func) {
|
||||
|
||||
const compression::format comp_format = preferences::save_compression_format();
|
||||
|
||||
savenames_.resize(i);
|
||||
|
||||
auto pos = items.erase(items.begin() + i);
|
||||
std::vector<config> newitems;
|
||||
std::vector<std::string> newsaves;
|
||||
|
||||
compression::format compression_format = preferences::save_compression_format();
|
||||
savegame::autosave_savegame autosave(saved_game_, compression_format);
|
||||
savegame::scenariostart_savegame scenariostart_save(saved_game_, compression_format);
|
||||
savegame::autosave_savegame autosave(sg, compression_format);
|
||||
savegame::scenariostart_savegame scenariostart_save(sg, compression_format);
|
||||
|
||||
const std::string start_name = scenariostart_save.create_filename();
|
||||
|
||||
for(unsigned int turn = play_controller_.turn(); turn != 0; turn--) {
|
||||
for(; turn != 0; turn--) {
|
||||
const std::string name = autosave.create_filename(turn);
|
||||
|
||||
if(savegame::save_game_exists(name, comp_format)) {
|
||||
newsaves.emplace_back(name + compression::format_extension(comp_format));
|
||||
newitems.emplace_back("label", _("Back to Turn ") + std::to_string(turn));
|
||||
func(turn, name + compression::format_extension(comp_format));
|
||||
}
|
||||
}
|
||||
|
||||
if(savegame::save_game_exists(start_name, comp_format)) {
|
||||
newsaves.emplace_back(start_name + compression::format_extension(comp_format));
|
||||
newitems.emplace_back("label", _("Back to Start"));
|
||||
func(0, start_name + compression::format_extension(comp_format));
|
||||
}
|
||||
}
|
||||
|
||||
void play_controller::hotkey_handler::expand_autosaves(std::vector<config>& items, int i)
|
||||
{
|
||||
auto pos = items.erase(items.begin() + i);
|
||||
std::vector<config> newitems;
|
||||
|
||||
foreach_autosave(play_controller_.turn(), saved_game_, [&](int turn, const std::string& filename) {
|
||||
// TODO: should this use variable substitution instead?
|
||||
std::string label = turn > 0 ? _("Back to Turn ") + std::to_string(turn) : _("Back to Start");
|
||||
newitems.emplace_back("label", label, "id", quickload_prefix + filename);
|
||||
});
|
||||
// Make sure list doesn't get too long: keep top two, midpoint and bottom.
|
||||
trim_items(newitems);
|
||||
trim_items(newsaves);
|
||||
|
||||
items.insert(pos, newitems.begin(), newitems.end());
|
||||
savenames_.insert(savenames_.end(), newsaves.begin(), newsaves.end());
|
||||
}
|
||||
|
||||
void play_controller::hotkey_handler::expand_wml_commands(std::vector<config>& items, int i)
|
||||
{
|
||||
// Pad the commands with null pointers (keeps the indices of items and wml_commands_ synced).
|
||||
wml_commands_.resize(i);
|
||||
|
||||
auto pos = items.erase(items.begin() + i);
|
||||
std::vector<config> newitems;
|
||||
|
||||
gamestate().get_wml_menu_items().get_items(mouse_handler_.get_last_hex(), wml_commands_, newitems,
|
||||
gamestate().get_wml_menu_items().get_items(mouse_handler_.get_last_hex(), newitems,
|
||||
gamestate(), gamestate().gamedata_, play_controller_.get_units());
|
||||
|
||||
// Replace this placeholder entry with available menu items.
|
||||
@ -465,19 +455,17 @@ void play_controller::hotkey_handler::show_menu(const std::vector<config>& items
|
||||
|
||||
std::vector<config> items;
|
||||
for(const auto& item : items_arg) {
|
||||
const std::string& id = item["id"];
|
||||
const hotkey::hotkey_command& command = hotkey::get_hotkey_command(id);
|
||||
|
||||
if(id == "wml" || (can_execute_command(command) && (!context_menu || in_context_menu(command.command)))) {
|
||||
std::string id = item["id"];
|
||||
hotkey::ui_command cmd = hotkey::ui_command(id);
|
||||
|
||||
if(id == "wml" || (can_execute_command(cmd) && (!context_menu || in_context_menu(cmd)))) {
|
||||
items.emplace_back("id", id);
|
||||
}
|
||||
}
|
||||
|
||||
// Add special non-hotkey items to the menu and remember their indices
|
||||
// Iterate in reverse to avoid also iterating over the new inserted items
|
||||
savenames_.clear();
|
||||
wml_commands_.clear();
|
||||
|
||||
// Iterate in reverse to avoid also iterating over the new inserted items
|
||||
for(int i = items.size() - 1; i >= 0; i--) {
|
||||
if(items[i]["id"] == "AUTOSAVES") {
|
||||
expand_autosaves(items, i);
|
||||
@ -493,9 +481,9 @@ void play_controller::hotkey_handler::show_menu(const std::vector<config>& items
|
||||
command_executor::show_menu(items, xloc, yloc, context_menu, disp);
|
||||
}
|
||||
|
||||
bool play_controller::hotkey_handler::in_context_menu(hotkey::HOTKEY_COMMAND command) const
|
||||
bool play_controller::hotkey_handler::in_context_menu(const hotkey::ui_command& cmd) const
|
||||
{
|
||||
switch(command) {
|
||||
switch(cmd.hotkey_command) {
|
||||
// Only display these if the mouse is over a castle or keep tile
|
||||
case hotkey::HOTKEY_RECRUIT:
|
||||
case hotkey::HOTKEY_REPEAT_RECRUIT:
|
||||
@ -519,20 +507,14 @@ bool play_controller::hotkey_handler::in_context_menu(hotkey::HOTKEY_COMMAND com
|
||||
}
|
||||
}
|
||||
|
||||
std::string play_controller::hotkey_handler::get_action_image(hotkey::HOTKEY_COMMAND command, int index) const
|
||||
std::string play_controller::hotkey_handler::get_action_image(const hotkey::ui_command& cmd) const
|
||||
{
|
||||
if(index >= 0 && index < static_cast<int>(wml_commands_.size())) {
|
||||
const const_item_ptr wmi = wml_commands_[index];
|
||||
if ( wmi ) {
|
||||
return wmi->image();
|
||||
}
|
||||
}
|
||||
return command_executor::get_action_image(command, index);
|
||||
return command_executor::get_action_image(cmd);
|
||||
}
|
||||
|
||||
hotkey::ACTION_STATE play_controller::hotkey_handler::get_action_state(hotkey::HOTKEY_COMMAND command, int /*index*/) const
|
||||
hotkey::ACTION_STATE play_controller::hotkey_handler::get_action_state(const hotkey::ui_command& cmd) const
|
||||
{
|
||||
switch(command) {
|
||||
switch(cmd.hotkey_command) {
|
||||
|
||||
case hotkey::HOTKEY_MINIMAP_DRAW_VILLAGES:
|
||||
return (preferences::minimap_draw_villages()) ? hotkey::ACTION_ON : hotkey::ACTION_OFF;
|
||||
|
@ -59,13 +59,10 @@ private:
|
||||
// Expand AUTOSAVES in the menu items, setting the real savenames.
|
||||
void expand_autosaves(std::vector<config>& items, int i);
|
||||
|
||||
std::vector<std::string> savenames_;
|
||||
|
||||
/**
|
||||
* Replaces "wml" in @a items with all active WML menu items for the current field.
|
||||
*/
|
||||
void expand_wml_commands(std::vector<config>& items, int i);
|
||||
std::vector<const_item_ptr> wml_commands_;
|
||||
int last_context_menu_x_;
|
||||
int last_context_menu_y_;
|
||||
|
||||
@ -121,18 +118,18 @@ public:
|
||||
virtual void replay_skip_animation() override
|
||||
{ return play_controller_.toggle_skipping_replay(); }
|
||||
|
||||
virtual std::string get_action_image(hotkey::HOTKEY_COMMAND, int index) const override;
|
||||
virtual std::string get_action_image(const hotkey::ui_command&) const override;
|
||||
virtual void load_autosave(const std::string& filename, bool start_replay = false);
|
||||
virtual hotkey::ACTION_STATE get_action_state(hotkey::HOTKEY_COMMAND command, int index) const override;
|
||||
virtual hotkey::ACTION_STATE get_action_state(const hotkey::ui_command&) const override;
|
||||
/** Check if a command can be executed. */
|
||||
virtual bool can_execute_command(const hotkey::hotkey_command& command, int index=-1) const override;
|
||||
virtual bool do_execute_command(const hotkey::hotkey_command& command, int index=-1, bool press=true, bool release=false) override;
|
||||
virtual bool can_execute_command(const hotkey::ui_command& command) const override;
|
||||
virtual bool do_execute_command(const hotkey::ui_command& command, bool press=true, bool release=false) override;
|
||||
void show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& disp) override;
|
||||
|
||||
/**
|
||||
* Determines whether the command should be in the context menu or not.
|
||||
* Independent of whether or not we can actually execute the command.
|
||||
*/
|
||||
bool in_context_menu(hotkey::HOTKEY_COMMAND command) const;
|
||||
bool in_context_menu(const hotkey::ui_command& cmd) const;
|
||||
|
||||
};
|
||||
|
@ -43,9 +43,9 @@ void playmp_controller::hotkey_handler::stop_network(){
|
||||
playmp_controller_.stop_network();
|
||||
}
|
||||
|
||||
bool playmp_controller::hotkey_handler::can_execute_command(const hotkey::hotkey_command& cmd, int index) const
|
||||
bool playmp_controller::hotkey_handler::can_execute_command(const hotkey::ui_command& cmd) const
|
||||
{
|
||||
hotkey::HOTKEY_COMMAND command = cmd.command;
|
||||
hotkey::HOTKEY_COMMAND command = cmd.hotkey_command;
|
||||
bool res = true;
|
||||
switch (command){
|
||||
case hotkey::HOTKEY_ENDTURN:
|
||||
@ -57,7 +57,7 @@ bool playmp_controller::hotkey_handler::can_execute_command(const hotkey::hotkey
|
||||
}
|
||||
else
|
||||
{
|
||||
return playsingle_controller::hotkey_handler::can_execute_command(cmd, index);
|
||||
return playsingle_controller::hotkey_handler::can_execute_command(cmd);
|
||||
}
|
||||
case hotkey::HOTKEY_SPEAK:
|
||||
case hotkey::HOTKEY_SPEAK_ALLY:
|
||||
@ -72,7 +72,7 @@ bool playmp_controller::hotkey_handler::can_execute_command(const hotkey::hotkey
|
||||
res = is_observer() && !playmp_controller_.network_processing_stopped_;
|
||||
break;
|
||||
default:
|
||||
return playsingle_controller::hotkey_handler::can_execute_command(cmd, index);
|
||||
return playsingle_controller::hotkey_handler::can_execute_command(cmd);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -37,6 +37,6 @@ public:
|
||||
virtual void shout() override;
|
||||
virtual void start_network() override;
|
||||
virtual void stop_network() override;
|
||||
virtual bool can_execute_command(const hotkey::hotkey_command& command, int index=-1) const override;
|
||||
virtual bool can_execute_command(const hotkey::ui_command& command) const override;
|
||||
|
||||
};
|
||||
|
@ -35,6 +35,10 @@
|
||||
|
||||
#include "units/unit.hpp"
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
namespace balg = boost::algorithm;
|
||||
|
||||
playsingle_controller::hotkey_handler::hotkey_handler(playsingle_controller & pc, saved_game & sg)
|
||||
: play_controller::hotkey_handler(pc, sg)
|
||||
, playsingle_controller_(pc)
|
||||
@ -185,35 +189,34 @@ void playsingle_controller::hotkey_handler::whiteboard_suppose_dead()
|
||||
whiteboard_manager_->save_suppose_dead(*curr_unit,loc);
|
||||
}
|
||||
|
||||
hotkey::ACTION_STATE playsingle_controller::hotkey_handler::get_action_state(hotkey::HOTKEY_COMMAND command, int index) const
|
||||
hotkey::ACTION_STATE playsingle_controller::hotkey_handler::get_action_state(const hotkey::ui_command& cmd) const
|
||||
{
|
||||
switch(command) {
|
||||
switch(cmd.hotkey_command) {
|
||||
case hotkey::HOTKEY_WB_TOGGLE:
|
||||
return whiteboard_manager_->is_active() ? hotkey::ACTION_ON : hotkey::ACTION_OFF;
|
||||
default:
|
||||
return play_controller::hotkey_handler::get_action_state(command, index);
|
||||
return play_controller::hotkey_handler::get_action_state(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
bool playsingle_controller::hotkey_handler::can_execute_command(const hotkey::hotkey_command& cmd, int index) const
|
||||
bool playsingle_controller::hotkey_handler::can_execute_command(const hotkey::ui_command& cmd) const
|
||||
{
|
||||
hotkey::HOTKEY_COMMAND command = cmd.command;
|
||||
hotkey::HOTKEY_COMMAND command = cmd.hotkey_command;
|
||||
bool res = true;
|
||||
int prefixlen = wml_menu_hotkey_prefix.length();
|
||||
switch (command){
|
||||
|
||||
case hotkey::HOTKEY_NULL:
|
||||
case hotkey::HOTKEY_WML:
|
||||
{
|
||||
int prefixlen = wml_menu_hotkey_prefix.length();
|
||||
if(cmd.id.compare(0, prefixlen, wml_menu_hotkey_prefix) != 0) {
|
||||
return false;
|
||||
if(cmd.id.compare(0, prefixlen, wml_menu_hotkey_prefix) == 0) {
|
||||
game_events::wmi_manager::item_ptr item = gamestate().get_wml_menu_items().get_item(std::string(cmd.id.substr(prefixlen)));
|
||||
if(!item) {
|
||||
return false;
|
||||
}
|
||||
return !item->is_synced() || play_controller_.can_use_synced_wml_menu();
|
||||
}
|
||||
return play_controller::hotkey_handler::can_execute_command(cmd);
|
||||
|
||||
game_events::wmi_manager::item_ptr item = gamestate().get_wml_menu_items().get_item(cmd.id.substr(prefixlen));
|
||||
if(!item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !item->is_synced() || play_controller_.can_use_synced_wml_menu();
|
||||
}
|
||||
case hotkey::HOTKEY_SAVE_GAME:
|
||||
return !events::commands_disabled || (playsingle_controller_.is_replay() && events::commands_disabled < 2);
|
||||
@ -298,11 +301,11 @@ bool playsingle_controller::hotkey_handler::can_execute_command(const hotkey::ho
|
||||
case hotkey::HOTKEY_REPLAY_SHOW_EACH:
|
||||
case hotkey::HOTKEY_REPLAY_SHOW_TEAM1:
|
||||
case hotkey::HOTKEY_REPLAY_RESET:
|
||||
return playsingle_controller_.get_replay_controller() && playsingle_controller_.get_replay_controller()->can_execute_command(cmd, index);
|
||||
return playsingle_controller_.get_replay_controller() && playsingle_controller_.get_replay_controller()->can_execute_command(cmd);
|
||||
case hotkey::HOTKEY_REPLAY_EXIT:
|
||||
return playsingle_controller_.is_replay() && (!playsingle_controller_.is_networked_mp() || resources::recorder->at_end());
|
||||
default:
|
||||
return play_controller::hotkey_handler::can_execute_command(cmd, index);
|
||||
return play_controller::hotkey_handler::can_execute_command(cmd);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
virtual void recruit() override;
|
||||
virtual void repeat_recruit() override;
|
||||
virtual void recall() override;
|
||||
virtual bool can_execute_command(const hotkey::hotkey_command& command, int index=-1) const override;
|
||||
virtual bool can_execute_command(const hotkey::ui_command& cmd) const override;
|
||||
virtual void toggle_shroud_updates() override;
|
||||
virtual void update_shroud_now() override;
|
||||
virtual void end_turn() override;
|
||||
@ -94,5 +94,5 @@ public:
|
||||
{ return playsingle_controller_.reset_replay(); }
|
||||
virtual void replay_exit() override;
|
||||
virtual void load_autosave(const std::string& filename, bool start_replay = false) override;
|
||||
virtual hotkey::ACTION_STATE get_action_state(hotkey::HOTKEY_COMMAND command, int index) const override;
|
||||
virtual hotkey::ACTION_STATE get_action_state(const hotkey::ui_command&) const override;
|
||||
};
|
||||
|
@ -202,9 +202,9 @@ void replay_controller::play_side_impl()
|
||||
}
|
||||
return;
|
||||
}
|
||||
bool replay_controller::can_execute_command(const hotkey::hotkey_command& cmd, int) const
|
||||
bool replay_controller::can_execute_command(const hotkey::ui_command& cmd) const
|
||||
{
|
||||
switch(cmd.command) {
|
||||
switch(cmd.hotkey_command) {
|
||||
case hotkey::HOTKEY_REPLAY_SKIP_ANIMATION:
|
||||
return true;
|
||||
case hotkey::HOTKEY_REPLAY_SHOW_EVERYTHING:
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
|
||||
bool recorder_at_end() const;
|
||||
bool should_stop() const { return stop_condition_->should_stop(); }
|
||||
bool can_execute_command(const hotkey::hotkey_command& cmd, int index) const;
|
||||
bool can_execute_command(const hotkey::ui_command& cmd) const;
|
||||
bool is_controlling_view() const {
|
||||
return vision_.has_value();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user