The Battle for Wesnoth  1.15.2+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 
211 }
212 
214 {
216 
217  if (preferences::turbo())
218  {
219  utils::string_map symbols;
221  gui()->announce(_("Accelerated speed enabled!") + "\n" + VGETTEXT("(press $hk to disable)", symbols), font::NORMAL_COLOR);
222  }
223  else
224  {
225  gui()->announce(_("Accelerated speed disabled!"), font::NORMAL_COLOR);
226  }
227 }
228 
230 {
232 }
233 
235 {
237 }
238 
240 {
242 }
243 
245 {
247 }
248 
250 {
251  hotkey::HOTKEY_COMMAND command = cmd.id;
252  if(index >= 0) {
253  unsigned i = static_cast<unsigned>(index);
254  if(i < savenames_.size() && !savenames_[i].empty()) {
255  // Load the game by throwing load_game_exception
257 
258  } else if ( i < wml_commands_.size() && wml_commands_[i] ) {
260  return true;
261  }
262  }
263  int prefixlen = wml_menu_hotkey_prefix.length();
264  if(command == hotkey::HOTKEY_WML && cmd.command.compare(0, prefixlen, wml_menu_hotkey_prefix) == 0)
265  {
266  std::string name = cmd.command.substr(prefixlen);
268 
269  return gamestate().get_wml_menu_items().fire_item(name, hex, gamestate().gamedata_, gamestate(), gamestate().board_.units_, !press);
270  }
271  return command_executor::do_execute_command(cmd, index, press, release);
272 }
273 
275 {
276  if(index >= 0) {
277  unsigned i = static_cast<unsigned>(index);
278  if((i < savenames_.size() && !savenames_[i].empty())
279  || (i < wml_commands_.size() && wml_commands_[i])) {
280  return true;
281  }
282  }
283  switch(cmd.id) {
284 
285  // Commands we can always do:
302  case hotkey::HOTKEY_MUTE:
310  case hotkey::HOTKEY_HELP:
326  case hotkey::HOTKEY_NULL:
329  case hotkey::LUA_CONSOLE:
334  return true;
335 
337  std::size_t humans_notme_cnt = 0;
338  for(const auto& t : play_controller_.get_teams_const()) {
339  if(t.is_network_human()) {
340  ++humans_notme_cnt;
341  }
342  }
343 
344  return !(humans_notme_cnt < 1 || play_controller_.is_linger_mode() || play_controller_.is_observer());
345  }
346  // Commands that have some preconditions:
349 
352  return !linger() && play_controller_.enemies_visible();
353 
355  return !play_controller_.is_networked_mp(); // Can only load games if not in a network game
356 
361  return true;
362 
363  case hotkey::HOTKEY_REDO:
364  return play_controller_.can_redo();
365  case hotkey::HOTKEY_UNDO:
366  return play_controller_.can_undo();
367 
369  return menu_handler_.current_unit().valid();
370 
372  return mouse_handler_.get_last_hex().valid();
373 
375  return !events::commands_disabled &&
377  !(menu_handler_.current_unit()->unrenamable()) &&
378  menu_handler_.current_unit()->side() == gui()->viewing_side() &&
379  play_controller_.get_teams_const()[menu_handler_.current_unit()->side() - 1].is_local_human();
380 
381  default:
382  return false;
383  }
384 }
385 
386 template<typename T>
387 static void trim_items(std::vector<T>& newitems)
388 {
389  if(newitems.size() > 5) {
390  std::vector<T> subitems;
391  subitems.push_back(std::move(newitems[0]));
392  subitems.push_back(std::move(newitems[1]));
393  subitems.push_back(std::move(newitems[newitems.size() / 3]));
394  subitems.push_back(std::move(newitems[newitems.size() * 2 / 3]));
395  subitems.push_back(std::move(newitems.back()));
396  newitems = subitems;
397  }
398 }
399 
401 {
403 
404  savenames_.resize(i);
405 
406  auto pos = items.erase(items.begin() + i);
407  std::vector<config> newitems;
408  std::vector<std::string> newsaves;
409 
411  savegame::autosave_savegame autosave(saved_game_, compression_format);
412  savegame::scenariostart_savegame scenariostart_save(saved_game_, compression_format);
413 
414  const std::string start_name = scenariostart_save.create_filename();
415 
416  for(unsigned int turn = play_controller_.turn(); turn != 0; turn--) {
417  const std::string name = autosave.create_filename(turn);
418 
419  if(savegame::save_game_exists(name, comp_format)) {
420  newsaves.emplace_back(name + compression::format_extension(comp_format));
421  newitems.emplace_back("label", _("Back to Turn ") + std::to_string(turn));
422  }
423  }
424 
425  if(savegame::save_game_exists(start_name, comp_format)) {
426  newsaves.emplace_back(start_name + compression::format_extension(comp_format));
427  newitems.emplace_back("label", _("Back to Start"));
428  }
429 
430  // Make sure list doesn't get too long: keep top two, midpoint and bottom.
431  trim_items(newitems);
432  trim_items(newsaves);
433 
434  items.insert(pos, newitems.begin(), newitems.end());
435  savenames_.insert(savenames_.end(), newsaves.begin(), newsaves.end());
436 }
437 
439 {
440  // Pad the commands with null pointers (keeps the indices of items and wml_commands_ synced).
441  wml_commands_.resize(i);
442 
443  auto pos = items.erase(items.begin() + i);
444  std::vector<config> newitems;
445 
448 
449  // Replace this placeholder entry with available menu items.
450  items.insert(pos, newitems.begin(), newitems.end());
451 }
452 
453 void play_controller::hotkey_handler::show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& disp)
454 {
455  if(context_menu) {
456  last_context_menu_x_ = xloc;
457  last_context_menu_y_ = yloc;
458  }
459 
460  std::vector<config> items;
461  for(const auto& item : items_arg) {
462  const std::string& id = item["id"];
464 
465  if(id == "wml" || (can_execute_command(command) && (!context_menu || in_context_menu(command.id)))) {
466  items.emplace_back("id", id);
467  }
468  }
469 
470  // Add special non-hotkey items to the menu and remember their indices
471  // Iterate in reverse to avoid also iterating over the new inserted items
472  savenames_.clear();
473  wml_commands_.clear();
474 
475  for(int i = items.size() - 1; i >= 0; i--) {
476  if(items[i]["id"] == "AUTOSAVES") {
477  expand_autosaves(items, i);
478  } else if(items[i]["id"] == "wml") {
479  expand_wml_commands(items, i);
480  }
481  }
482 
483  if(items.empty()) {
484  return;
485  }
486 
487  command_executor::show_menu(items, xloc, yloc, context_menu, disp);
488 }
489 
491 {
492  switch(command) {
493  // Only display these if the mouse is over a castle or keep tile
496  case hotkey::HOTKEY_RECALL: {
497  // last_hex_ is set by mouse_events::mouse_motion
498  const map_location & last_hex = mouse_handler_.get_last_hex();
499  const int viewing_side = gui()->viewing_side();
500 
501  // A quick check to save us having to create the future map and
502  // possibly loop through all units.
503  if ( !play_controller_.get_map_const().is_keep(last_hex) &&
505  return false;
506 
507  wb::future_map future; /* lasts until method returns. */
508 
509  return gamestate().side_can_recruit_on(viewing_side, last_hex);
510  }
511  default:
512  return true;
513  }
514 }
515 
517 {
518  if(index >= 0 && index < static_cast<int>(wml_commands_.size())) {
519  const const_item_ptr wmi = wml_commands_[index];
520  if ( wmi ) {
521  return wmi->image();
522  }
523  }
524  return command_executor::get_action_image(command, index);
525 }
526 
528 {
529  switch(command) {
530 
542  return (gui()->get_zoom_factor() == 1.0) ? hotkey::ACTION_ON : hotkey::ACTION_OFF;
545  default:
547  }
548 }
549 
550 void play_controller::hotkey_handler::load_autosave(const std::string& filename)
551 {
554 }
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:795
Class for start-of-scenario saves.
Definition: savegame.hpp:314
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...
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:404
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:188
bool minimap_movement_coding()
Definition: general.cpp:775
Class for autosaves.
Definition: savegame.hpp:288
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_
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:805
std::string get_names(const std::string &id)
Returns a comma-separated string of hotkey names.
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
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: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:189
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:381
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:338
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:92
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:1771
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:749
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:387
int get_location_x(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:744
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:815
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 this name, looking only in the default save director...
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:785