The Battle for Wesnoth  1.15.0+dev
hotkey_handler.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
16 
17 #include "actions/create.hpp"
18 #include "font/standard_colors.hpp"
19 #include "formula/string_utils.hpp"
20 #include "game_display.hpp"
21 #include "game_errors.hpp"
24 #include "preferences/game.hpp"
25 #include "game_state.hpp"
27 #include "hotkey/hotkey_item.hpp"
28 #include "map/map.hpp"
29 #include "play_controller.hpp"
30 #include "preferences/display.hpp"
31 #include "savegame.hpp"
32 #include "saved_game.hpp"
33 #include "whiteboard/manager.hpp"
34 
35 #include "units/unit.hpp"
36 
37 const std::string play_controller::hotkey_handler::wml_menu_hotkey_prefix = "wml_menu:";
38 
40  : play_controller_(pc)
41  , menu_handler_(pc.get_menu_handler())
42  , mouse_handler_(pc.get_mouse_handler_base())
43  , saved_game_(sg)
44  , savenames_()
45  , wml_commands_()
46  , last_context_menu_x_(0)
47  , last_context_menu_y_(0)
48 {}
49 
51 
53  return &play_controller_.get_display();
54 }
55 
57  return play_controller_.gamestate();
58 }
59 
61  return play_controller_.gamestate();
62 }
63 
66 
69 
72 }
73 
76 }
77 
80 }
81 
84 }
85 
88 }
89 
92 }
93 
96 }
97 
100 }
101 
104 }
105 
107  int x = gui()->get_location_x(gui()->mouseover_hex());
108  int y = gui()->get_location_y(gui()->mouseover_hex());
109 
110  SDL_MouseButtonEvent event;
111 
112  event.button = 1;
113  event.x = x + 30;
114  event.y = y + 30;
115  event.which = 0;
116  event.state = SDL_PRESSED;
117 
118  mouse_handler_.mouse_press(event, false);
119 }
120 
123 }
124 
126  auto touched_hex = gui()->mouseover_hex();
127  mouse_handler_.touch_action(touched_hex, false);
128 }
129 
132 }
133 
136 }
138  mouse_handler_.select_hex(gui()->mouseover_hex(), false);
139 }
140 
142  int x = gui()->get_location_x(gui()->mouseover_hex());
143  int y = gui()->get_location_y(gui()->mouseover_hex());
144 
145  SDL_MouseButtonEvent event;
146 
147  event.button = 3;
148  event.x = x + 30;
149  event.y = y + 30;
150  event.which = 0;
151  event.state = SDL_PRESSED;
152 
153  mouse_handler_.mouse_press(event, true);
154 }
155 
156 
159 }
160 
163 }
164 
167 }
168 
171 }
172 
175 }
176 
179 }
180 
183 }
184 
187 }
188 
191 }
192 
195 }
196 
199 }
200 
203 }
204 
207 }
208 
210 {
212 
213  if (preferences::turbo())
214  {
215  utils::string_map symbols;
217  gui()->announce(_("Accelerated speed enabled!") + "\n" + VGETTEXT("(press $hk to disable)", symbols), font::NORMAL_COLOR);
218  }
219  else
220  {
221  gui()->announce(_("Accelerated speed disabled!"), font::NORMAL_COLOR);
222  }
223 }
224 
226 {
228 }
229 
231 {
233 }
234 
236 {
238 }
239 
241 {
243 }
244 
246 {
247  hotkey::HOTKEY_COMMAND command = cmd.id;
248  if(index >= 0) {
249  unsigned i = static_cast<unsigned>(index);
250  if(i < savenames_.size() && !savenames_[i].empty()) {
251  // Load the game by throwing load_game_exception
253 
254  } else if ( i < wml_commands_.size() && wml_commands_[i] ) {
256  return true;
257  }
258  }
259  int prefixlen = wml_menu_hotkey_prefix.length();
260  if(command == hotkey::HOTKEY_WML && cmd.command.compare(0, prefixlen, wml_menu_hotkey_prefix) == 0)
261  {
262  std::string name = cmd.command.substr(prefixlen);
264 
265  return gamestate().get_wml_menu_items().fire_item(name, hex, gamestate().gamedata_, gamestate(), gamestate().board_.units_, !press);
266  }
267  return command_executor::do_execute_command(cmd, index, press, release);
268 }
269 
271 {
272  if(index >= 0) {
273  unsigned i = static_cast<unsigned>(index);
274  if((i < savenames_.size() && !savenames_[i].empty())
275  || (i < wml_commands_.size() && wml_commands_[i])) {
276  return true;
277  }
278  }
279  switch(cmd.id) {
280 
281  // Commands we can always do:
298  case hotkey::HOTKEY_MUTE:
306  case hotkey::HOTKEY_HELP:
322  case hotkey::HOTKEY_NULL:
325  case hotkey::LUA_CONSOLE:
330  return true;
331 
333  std::size_t humans_notme_cnt = 0;
334  for(const auto& t : play_controller_.get_teams_const()) {
335  if(t.is_network_human()) {
336  ++humans_notme_cnt;
337  }
338  }
339 
340  return !(humans_notme_cnt < 1 || play_controller_.is_linger_mode() || play_controller_.is_observer());
341  }
342  // Commands that have some preconditions:
345 
348  return !linger() && play_controller_.enemies_visible();
349 
351  return !play_controller_.is_networked_mp(); // Can only load games if not in a network game
352 
354  return true;
355 
356  case hotkey::HOTKEY_REDO:
357  return play_controller_.can_redo();
358  case hotkey::HOTKEY_UNDO:
359  return play_controller_.can_undo();
360 
362  return menu_handler_.current_unit().valid();
363 
365  return mouse_handler_.get_last_hex().valid();
366 
368  return !events::commands_disabled &&
370  !(menu_handler_.current_unit()->unrenamable()) &&
371  menu_handler_.current_unit()->side() == gui()->viewing_side() &&
372  play_controller_.get_teams_const()[menu_handler_.current_unit()->side() - 1].is_local_human();
373 
374  default:
375  return false;
376  }
377 }
378 
379 template<typename T>
380 static void trim_items(std::vector<T>& newitems)
381 {
382  if(newitems.size() > 5) {
383  std::vector<T> subitems;
384  subitems.push_back(std::move(newitems[0]));
385  subitems.push_back(std::move(newitems[1]));
386  subitems.push_back(std::move(newitems[newitems.size() / 3]));
387  subitems.push_back(std::move(newitems[newitems.size() * 2 / 3]));
388  subitems.push_back(std::move(newitems.back()));
389  newitems = subitems;
390  }
391 }
392 
394 {
396 
397  savenames_.resize(i);
398 
399  auto pos = items.erase(items.begin() + i);
400  std::vector<config> newitems;
401  std::vector<std::string> newsaves;
402 
404  savegame::autosave_savegame autosave(saved_game_, compression_format);
405  savegame::scenariostart_savegame scenariostart_save(saved_game_, compression_format);
406 
407  const std::string start_name = scenariostart_save.create_filename();
408 
409  for(unsigned int turn = play_controller_.turn(); turn != 0; turn--) {
410  const std::string name = autosave.create_filename(turn);
411 
412  if(savegame::save_game_exists(name, comp_format)) {
413  newsaves.emplace_back(name + compression::format_extension(comp_format));
414  newitems.emplace_back("label", _("Back to Turn ") + std::to_string(turn));
415  }
416  }
417 
418  if(savegame::save_game_exists(start_name, comp_format)) {
419  newsaves.emplace_back(start_name + compression::format_extension(comp_format));
420  newitems.emplace_back("label", _("Back to Start"));
421  }
422 
423  // Make sure list doesn't get too long: keep top two, midpoint and bottom.
424  trim_items(newitems);
425  trim_items(newsaves);
426 
427  items.insert(pos, newitems.begin(), newitems.end());
428  savenames_.insert(savenames_.end(), newsaves.begin(), newsaves.end());
429 }
430 
432 {
433  // Pad the commands with null pointers (keeps the indices of items and wml_commands_ synced).
434  wml_commands_.resize(i);
435 
436  auto pos = items.erase(items.begin() + i);
437  std::vector<config> newitems;
438 
441 
442  // Replace this placeholder entry with available menu items.
443  items.insert(pos, newitems.begin(), newitems.end());
444 }
445 
446 void play_controller::hotkey_handler::show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& disp)
447 {
448  if(context_menu) {
449  last_context_menu_x_ = xloc;
450  last_context_menu_y_ = yloc;
451  }
452 
453  std::vector<config> items;
454  for(const auto& item : items_arg) {
455  const std::string& id = item["id"];
457 
458  if(id == "wml" || (can_execute_command(command) && (!context_menu || in_context_menu(command.id)))) {
459  items.emplace_back("id", id);
460  }
461  }
462 
463  // Add special non-hotkey items to the menu and remember their indices
464  // Iterate in reverse to avoid also iterating over the new inserted items
465  savenames_.clear();
466  wml_commands_.clear();
467 
468  for(int i = items.size() - 1; i >= 0; i--) {
469  if(items[i]["id"] == "AUTOSAVES") {
470  expand_autosaves(items, i);
471  } else if(items[i]["id"] == "wml") {
472  expand_wml_commands(items, i);
473  }
474  }
475 
476  if(items.empty()) {
477  return;
478  }
479 
480  command_executor::show_menu(items, xloc, yloc, context_menu, disp);
481 }
482 
484 {
485  switch(command) {
486  // Only display these if the mouse is over a castle or keep tile
489  case hotkey::HOTKEY_RECALL: {
490  // last_hex_ is set by mouse_events::mouse_motion
491  const map_location & last_hex = mouse_handler_.get_last_hex();
492  const int viewing_side = gui()->viewing_side();
493 
494  // A quick check to save us having to create the future map and
495  // possibly loop through all units.
496  if ( !play_controller_.get_map_const().is_keep(last_hex) &&
498  return false;
499 
500  wb::future_map future; /* lasts until method returns. */
501 
502  return gamestate().side_can_recruit_on(viewing_side, last_hex);
503  }
504  default:
505  return true;
506  }
507 }
508 
510 {
511  if(index >= 0 && index < static_cast<int>(wml_commands_.size())) {
512  const const_item_ptr wmi = wml_commands_[index];
513  if ( wmi ) {
514  return wmi->image();
515  }
516  }
517  return command_executor::get_action_image(command, index);
518 }
519 
521 {
522  switch(command) {
523 
535  return (gui()->get_zoom_factor() == 1.0) ? hotkey::ACTION_ON : hotkey::ACTION_OFF;
538  default:
540  }
541 }
542 
543 void play_controller::hotkey_handler::load_autosave(const std::string& filename)
544 {
545  throw savegame::load_game_exception(filename);
546 }
virtual void search() override
virtual void toggle_accelerated_speed() override
const map_location & mouseover_hex() const
Definition: display.hpp:285
void set_turbo(bool ison)
Definition: display.cpp:52
const team & viewing_team() const
bool is_keep(const map_location &loc) const
Definition: map.cpp:71
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:923
Class for start-of-scenario saves.
Definition: savegame.hpp:292
hotkey_handler(play_controller &, saved_game &)
virtual void unit_list() override
HOTKEY_COMMAND id
the names are strange: the "hotkey::HOTKEY_COMMAND" is named id, and the string to identify the objec...
void mouse_press(const SDL_MouseButtonEvent &event, const bool browse)
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:69
game_events::wmi_manager & get_wml_menu_items()
Definition: game_state.cpp:403
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.
bool minimap_movement_coding()
Definition: general.cpp:903
Class for autosaves.
Definition: savegame.hpp:266
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.
int viewing_side() const
Definition: display.hpp:103
const std::vector< std::string > items
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:78
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_
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:933
std::string get_names(const std::string &id)
Returns a comma-separated string of hotkey names.
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
const map_location & get_last_hex() const
unit_map units_
Definition: game_board.hpp:58
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
virtual void show_statistics() override
virtual void terrain_description() override
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
virtual void save_replay() override
virtual void undo() override
virtual void preferences() 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:251
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:93
events::menu_handler & menu_handler_
std::string create_filename() const
Build the filename according to the specific savegame&#39;s needs.
Definition: savegame.hpp:174
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:390
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:42
bool auto_shroud_updates() const
Definition: team.hpp:336
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:26
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:74
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:933
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:1748
std::string command
The command is unique.
virtual void redo() override
std::size_t playing_team() const
The playing team is the team whose turn it is.
Definition: display.hpp:97
void terrain_description(mouse_handler &mousehandler)
int get_location_y(const map_location &loc) const
Definition: display.cpp:726
void set_scroll_right(bool on)
game_data gamedata_
Definition: game_state.hpp:45
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:71
#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:885
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:386
int get_location_x(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:721
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:64
bool minimap_draw_terrain()
Definition: general.cpp:943
void show_enemy_moves(bool ignore_units, int side_num)
game_board board_
Definition: game_state.hpp:46
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:102
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:415
const gamemap & get_map_const() const
game_display * gui() const
virtual void scroll_right(bool on) override
virtual void touch_hex() override
std::size_t turn() const
const std::vector< team > & get_teams_const() const
bool save_game_exists(std::string name, compression::format compressed)
Returns true if there is already a savegame with that name.
Definition: savegame.cpp:61
virtual void toggle_ellipses() override
bool valid() const
Definition: map.hpp:276
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:371
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:913