The Battle for Wesnoth  1.17.12+dev
hotkey_handler.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2022
3  by Chris Beck <render787@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
17 
18 #include "actions/create.hpp"
19 #include "font/standard_colors.hpp"
20 #include "formula/string_utils.hpp"
21 #include "game_display.hpp"
22 #include "game_errors.hpp"
25 #include "preferences/game.hpp"
26 #include "game_state.hpp"
28 #include "hotkey/hotkey_item.hpp"
29 #include "map/map.hpp"
30 #include "play_controller.hpp"
31 #include "preferences/display.hpp"
32 #include "savegame.hpp"
33 #include "saved_game.hpp"
34 #include "whiteboard/manager.hpp"
35 
36 #include "units/unit.hpp"
37 
38 const std::string play_controller::hotkey_handler::wml_menu_hotkey_prefix = "wml_menu:";
39 
41  : play_controller_(pc)
42  , menu_handler_(pc.get_menu_handler())
43  , mouse_handler_(pc.get_mouse_handler_base())
44  , saved_game_(sg)
45  , savenames_()
46  , wml_commands_()
47  , last_context_menu_x_(0)
48  , last_context_menu_y_(0)
49 {}
50 
52 
54  return &play_controller_.get_display();
55 }
56 
58  return play_controller_.gamestate();
59 }
60 
62  return play_controller_.gamestate();
63 }
64 
67 
70 
73 }
74 
77 }
78 
81 }
82 
85 }
86 
89 }
90 
93 }
94 
97 }
98 
101 }
102 
105 }
106 
108  int x = gui()->get_location_x(gui()->mouseover_hex());
109  int y = gui()->get_location_y(gui()->mouseover_hex());
110 
111  SDL_MouseButtonEvent event;
112 
113  event.button = 1;
114  event.x = x + 30;
115  event.y = y + 30;
116  event.which = 0;
117  event.state = SDL_PRESSED;
118 
119  mouse_handler_.mouse_press(event, false);
120 }
121 
124 }
125 
127  auto touched_hex = gui()->mouseover_hex();
128  mouse_handler_.touch_action(touched_hex, false);
129 }
130 
133 }
134 
137 }
139  mouse_handler_.select_hex(gui()->mouseover_hex(), false);
140 }
141 
143  int x = gui()->get_location_x(gui()->mouseover_hex());
144  int y = gui()->get_location_y(gui()->mouseover_hex());
145 
146  SDL_MouseButtonEvent event;
147 
148  event.button = 3;
149  event.x = x + 30;
150  event.y = y + 30;
151  event.which = 0;
152  event.state = SDL_PRESSED;
153 
154  mouse_handler_.mouse_press(event, true);
155 }
156 
157 
160 }
161 
164 }
165 
168 }
169 
172 }
173 
176 }
177 
180 }
181 
184 }
185 
188 }
189 
192 }
193 
196 }
197 
200 }
201 
204 }
205 
208 }
209 
212 }
213 
215 {
217 
219  ao.discard_previous = true;
220 
221  if (preferences::turbo())
222  {
223  utils::string_map symbols;
225  gui()->announce(_("Accelerated speed enabled!") + "\n" + VGETTEXT("(press $hk to disable)", symbols), font::NORMAL_COLOR, ao);
226  }
227  else
228  {
229  gui()->announce(_("Accelerated speed disabled!"), font::NORMAL_COLOR, ao);
230  }
231 }
232 
234 {
236 }
237 
239 {
241 }
242 
244 {
246 }
247 
249 {
251 }
252 
254 {
255  hotkey::HOTKEY_COMMAND command = cmd.command;
256  if(index >= 0) {
257  unsigned i = static_cast<unsigned>(index);
258  if(i < savenames_.size() && !savenames_[i].empty()) {
259  // Load the game by throwing load_game_exception
261 
262  } else if ( i < wml_commands_.size() && wml_commands_[i] ) {
264  return true;
265  }
266  }
267  int prefixlen = wml_menu_hotkey_prefix.length();
268  if(command == hotkey::HOTKEY_WML && cmd.id.compare(0, prefixlen, wml_menu_hotkey_prefix) == 0)
269  {
270  std::string name = cmd.id.substr(prefixlen);
272 
274  name, hex, gamestate().gamedata_, gamestate(), play_controller_.get_units(), !press);
275  }
276  return command_executor::do_execute_command(cmd, index, press, release);
277 }
278 
280 {
281  if(index >= 0) {
282  unsigned i = static_cast<unsigned>(index);
283  if((i < savenames_.size() && !savenames_[i].empty())
284  || (i < wml_commands_.size() && wml_commands_[i])) {
285  return true;
286  }
287  }
288  switch(cmd.command) {
289 
290  // Commands we can always do:
307  case hotkey::HOTKEY_MUTE:
315  case hotkey::HOTKEY_HELP:
331  case hotkey::HOTKEY_NULL:
334  case hotkey::LUA_CONSOLE:
340  return true;
341 
343  std::size_t humans_notme_cnt = 0;
344  for(const auto& t : play_controller_.get_teams()) {
345  if(t.is_network_human()) {
346  ++humans_notme_cnt;
347  }
348  }
349 
350  return !(humans_notme_cnt < 1 || play_controller_.is_linger_mode() || play_controller_.is_observer());
351  }
352  // Commands that have some preconditions:
355 
358  return !linger() && play_controller_.enemies_visible();
359 
361  return !play_controller_.is_networked_mp(); // Can only load games if not in a network game
362 
367  return true;
368 
369  case hotkey::HOTKEY_REDO:
370  return play_controller_.can_redo();
371  case hotkey::HOTKEY_UNDO:
372  return play_controller_.can_undo();
373 
375  return menu_handler_.current_unit().valid();
376 
378  return mouse_handler_.get_last_hex().valid();
379 
381  return !events::commands_disabled &&
383  !(menu_handler_.current_unit()->unrenamable()) &&
384  menu_handler_.current_unit()->side() == gui()->viewing_side() &&
385  play_controller_.get_teams()[menu_handler_.current_unit()->side() - 1].is_local_human();
386 
387  default:
388  return false;
389  }
390 }
391 
392 template<typename T>
393 static void trim_items(std::vector<T>& newitems)
394 {
395  if(newitems.size() > 5) {
396  std::vector<T> subitems;
397  subitems.push_back(std::move(newitems[0]));
398  subitems.push_back(std::move(newitems[1]));
399  subitems.push_back(std::move(newitems[newitems.size() / 3]));
400  subitems.push_back(std::move(newitems[newitems.size() * 2 / 3]));
401  subitems.push_back(std::move(newitems.back()));
402  newitems = subitems;
403  }
404 }
405 
407 {
409 
410  savenames_.resize(i);
411 
412  auto pos = items.erase(items.begin() + i);
413  std::vector<config> newitems;
414  std::vector<std::string> newsaves;
415 
417  savegame::autosave_savegame autosave(saved_game_, compression_format);
418  savegame::scenariostart_savegame scenariostart_save(saved_game_, compression_format);
419 
420  const std::string start_name = scenariostart_save.create_filename();
421 
422  for(unsigned int turn = play_controller_.turn(); turn != 0; turn--) {
423  const std::string name = autosave.create_filename(turn);
424 
425  if(savegame::save_game_exists(name, comp_format)) {
426  newsaves.emplace_back(name + compression::format_extension(comp_format));
427  newitems.emplace_back("label", _("Back to Turn ") + std::to_string(turn));
428  }
429  }
430 
431  if(savegame::save_game_exists(start_name, comp_format)) {
432  newsaves.emplace_back(start_name + compression::format_extension(comp_format));
433  newitems.emplace_back("label", _("Back to Start"));
434  }
435 
436  // Make sure list doesn't get too long: keep top two, midpoint and bottom.
437  trim_items(newitems);
438  trim_items(newsaves);
439 
440  items.insert(pos, newitems.begin(), newitems.end());
441  savenames_.insert(savenames_.end(), newsaves.begin(), newsaves.end());
442 }
443 
445 {
446  // Pad the commands with null pointers (keeps the indices of items and wml_commands_ synced).
447  wml_commands_.resize(i);
448 
449  auto pos = items.erase(items.begin() + i);
450  std::vector<config> newitems;
451 
454 
455  // Replace this placeholder entry with available menu items.
456  items.insert(pos, newitems.begin(), newitems.end());
457 }
458 
459 void play_controller::hotkey_handler::show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& disp)
460 {
461  if(context_menu) {
462  last_context_menu_x_ = xloc;
463  last_context_menu_y_ = yloc;
464  }
465 
466  std::vector<config> items;
467  for(const auto& item : items_arg) {
468  const std::string& id = item["id"];
470 
471  if(id == "wml" || (can_execute_command(command) && (!context_menu || in_context_menu(command.command)))) {
472  items.emplace_back("id", id);
473  }
474  }
475 
476  // Add special non-hotkey items to the menu and remember their indices
477  // Iterate in reverse to avoid also iterating over the new inserted items
478  savenames_.clear();
479  wml_commands_.clear();
480 
481  for(int i = items.size() - 1; i >= 0; i--) {
482  if(items[i]["id"] == "AUTOSAVES") {
483  expand_autosaves(items, i);
484  } else if(items[i]["id"] == "wml") {
485  expand_wml_commands(items, i);
486  }
487  }
488 
489  if(items.empty()) {
490  return;
491  }
492 
493  command_executor::show_menu(items, xloc, yloc, context_menu, disp);
494 }
495 
497 {
498  switch(command) {
499  // Only display these if the mouse is over a castle or keep tile
502  case hotkey::HOTKEY_RECALL: {
503  // last_hex_ is set by mouse_events::mouse_motion
504  const map_location & last_hex = mouse_handler_.get_last_hex();
505  const int viewing_side = gui()->viewing_side();
506 
507  // A quick check to save us having to create the future map and
508  // possibly loop through all units.
509  if ( !play_controller_.get_map().is_keep(last_hex) &&
510  !play_controller_.get_map().is_castle(last_hex) )
511  return false;
512 
513  wb::future_map future; /* lasts until method returns. */
514 
515  return gamestate().side_can_recruit_on(viewing_side, last_hex);
516  }
517  default:
518  return true;
519  }
520 }
521 
523 {
524  if(index >= 0 && index < static_cast<int>(wml_commands_.size())) {
525  const const_item_ptr wmi = wml_commands_[index];
526  if ( wmi ) {
527  return wmi->image();
528  }
529  }
530  return command_executor::get_action_image(command, index);
531 }
532 
534 {
535  switch(command) {
536 
548  return (gui()->get_zoom_factor() == 1.0) ? hotkey::ACTION_ON : hotkey::ACTION_OFF;
551  default:
553  }
554 }
555 
556 void play_controller::hotkey_handler::load_autosave(const std::string& filename)
557 {
559 }
virtual void search() override
virtual void toggle_accelerated_speed() override
const map_location & mouseover_hex() const
Definition: display.hpp:296
void set_turbo(bool ison)
Definition: general.cpp:474
const team & viewing_team() const
bool is_keep(const map_location &loc) const
Definition: map.cpp:72
bool discard_previous
An announcement according these options should replace the previous announce (typical of fast announc...
Definition: display.hpp:604
void set_scroll_up(bool on)
virtual void toggle_grid() override
void goto_leader(int side_num)
void set_scroll_down(bool on)
bool minimap_draw_units()
Definition: general.cpp:855
Class for start-of-scenario saves.
Definition: savegame.hpp:305
hotkey_handler(play_controller &, saved_game &)
virtual void unit_list() override
std::map< std::string, t_string > string_map
void expand_autosaves(std::vector< config > &items, int i)
void show_menu(const std::vector< config > &items_arg, int xloc, int yloc, bool context_menu, display &disp) override
bool is_castle(const map_location &loc) const
Definition: map.cpp:70
const unit_map & get_units() const
game_events::wmi_manager & get_wml_menu_items()
Definition: game_state.cpp:416
virtual void show_chat_log() override
virtual void select_hex() override
game_display & get_display() override
Get a reference to a display member a derived class uses.
static std::shared_ptr< save_index_class > default_saves_dir()
Returns an instance for managing saves in filesystem::get_saves_dir()
Definition: save_index.cpp:210
bool minimap_movement_coding()
Definition: general.cpp:835
Class for autosaves.
Definition: savegame.hpp:279
virtual void load_game() override
virtual void select_and_action() override
bool enemies_visible() const
Stores all information related to functions that can be bound to hotkeys.
const std::vector< std::string > items
int viewing_side() const
Definition: display.hpp:113
const gamemap & get_map() const
HOTKEY_COMMAND command
The command associated with this hotkey.
std::string id
The unique ID.
static std::string _(const char *str)
Definition: gettext.hpp:93
This file implements all the hotkey handling and menu details for play controller.
void select_hex(const map_location &hex, const bool browse, const bool highlight=true, const bool fire_event=true)
virtual bool can_execute_command(const hotkey::hotkey_command &command, int index=-1) const override
Check if a command can be executed.
bool fire_item(const std::string &id, const map_location &hex, game_data &gamedata, filter_context &fc, unit_map &units, bool is_key_hold_repeat=false) const
Fires the menu item with the given id.
Definition: wmi_manager.cpp:79
play_controller & play_controller_
References to parent object / constituents.
void show_statistics(int side_num)
virtual void move_action() override
virtual void objectives() override
bool can_undo() const
void touch_action(const map_location hex, bool browse)
std::vector< std::string > savenames_
virtual void mouse_press(const SDL_MouseButtonEvent &event, const bool browse)
void expand_wml_commands(std::vector< config > &items, int i)
Replaces "wml" in items with all active WML menu items for the current field.
virtual void deselect_hex() override
bool is_lingering() const
virtual void show_enemy_moves(bool ignore_units) override
bool minimap_draw_villages()
Definition: general.cpp:865
std::string get_names(const std::string &id)
Returns a comma-separated string of hotkey names.
const map_location & get_last_hex() const
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:75
virtual void show_statistics() override
virtual void terrain_description() override
virtual void save_replay() override
virtual void undo() override
virtual void preferences() override
virtual void speak() override
bool is_linger_mode() const
virtual void save_game() override
Applies the planned unit map for the duration of the struct&#39;s life.
Definition: manager.hpp:252
bool in_context_menu(hotkey::HOTKEY_COMMAND command) const
Determines whether the command should be in the context menu or not.
bool valid() const
Definition: location.hpp:89
events::menu_handler & menu_handler_
std::string create_filename() const
Build the filename according to the specific savegame&#39;s needs.
Definition: savegame.hpp:180
std::vector< team > & get_teams()
std::shared_ptr< const game_events::wml_menu_item > const_item_ptr
A smart pointer used when retrieving menu items.
virtual void right_mouse_click() override
int show_menu(lua_State *L)
Displays a popup menu at the current mouse position Best used from a [set_menu_item], to show a submenu.
Definition: lua_gui2.cpp:185
virtual void unit_description() override
virtual void scroll_up(bool on) override
Declarations for a container for wml_menu_item.
static const std::string wml_menu_hotkey_prefix
bool is_browsing() const override
const color_t NORMAL_COLOR
bool is_observer() const
Encapsulates the map of the game.
Definition: location.hpp:38
bool auto_shroud_updates() const
Definition: team.hpp:326
void cycle_back_units(const bool browse)
Various functions related to the creation of units (recruits, recalls, and placed units)...
std::string format_extension(format compression_format)
Definition: compression.hpp:24
virtual void left_mouse_click() override
virtual void scroll_left(bool on) override
Exception used to signal that the user has decided to abortt a game, and to load another game instead...
Definition: savegame.hpp:83
virtual bool do_execute_command(const hotkey::hotkey_command &command, int index=-1, bool press=true, bool release=false) override
virtual bool is_networked_mp() const
virtual void load_autosave(const std::string &filename)
std::size_t i
Definition: function.cpp:968
virtual void cycle_units() override
void announce(const std::string &msg, const color_t &color=font::GOOD_COLOR, const announce_options &options=announce_options())
Announce a message prominently.
Definition: display.cpp:1624
Holds options for calls to function &#39;announce&#39; (announce).
Definition: display.hpp:594
virtual void redo() override
std::size_t playing_team() const
The playing team is the team whose turn it is.
Definition: display.hpp:107
void terrain_description(mouse_handler &mousehandler)
int get_location_y(const map_location &loc) const
Definition: display.cpp:736
void set_scroll_right(bool on)
game_data gamedata_
Definition: game_state.hpp:46
events::mouse_handler & mouse_handler_
virtual void scroll_down(bool on) override
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:72
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
virtual void status_table() override
void cycle_units(const bool browse, const bool reverse=false)
bool can_redo() const
void get_items(const map_location &hex, std::vector< std::shared_ptr< const wml_menu_item >> &items, std::vector< config > &descriptions, filter_context &fc, game_data &gamedata, unit_map &units) const
Returns the menu items that can be shown for the given location.
compression::format save_compression_format()
Definition: game.cpp:844
void set_scroll_left(bool on)
bool side_can_recruit_on(int side, map_location loc) const
Checks if any of the sides leaders can recruit at a location.
Definition: game_state.cpp:399
int get_location_x(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:731
virtual void goto_leader() override
unit_map::iterator current_unit()
std::vector< const_item_ptr > wml_commands_
game_state & gamestate()
double t
Definition: astarsearch.cpp:65
bool minimap_draw_terrain()
Definition: general.cpp:875
void show_enemy_moves(bool ignore_units, int side_num)
virtual hotkey::ACTION_STATE get_action_state(hotkey::HOTKEY_COMMAND command, int index) const override
std::size_t viewing_team() const
The viewing team is the team currently viewing the game.
Definition: display.hpp:112
virtual void cycle_back_units() override
virtual std::string get_action_image(hotkey::HOTKEY_COMMAND, int index) const override
int current_side() const
Returns the number of the side whose turn it is.
bool turbo()
Definition: general.cpp:465
game_display * gui() const
virtual void scroll_right(bool on) override
virtual void touch_hex() override
std::size_t turn() const
bool save_game_exists(std::string name, compression::format compressed)
Returns true if there is already a savegame with this name, looking only in the default save director...
Definition: savegame.cpp:62
virtual void toggle_ellipses() override
bool valid() const
Definition: map.hpp:274
const hotkey_command & get_hotkey_command(const std::string &command)
returns the hotkey_command with the given name
virtual void save_map() override
static void trim_items(std::vector< T > &newitems)
virtual void show_help() override
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:414
static const hotkey_command & get_command_by_command(HOTKEY_COMMAND command)
the execute_command argument was changed from HOTKEY_COMMAND to hotkey_command, to be able to call it...
void move_action(bool browse)
Overridden in derived class.
void select_or_action(bool browse)
bool minimap_terrain_coding()
Definition: general.cpp:845