The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
hotkey_handler.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2016 by Chris Beck <[email protected]>
3  Part of the Battle for Wesnoth Project http://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 "formula/string_utils.hpp"
19 #include "game_display.hpp"
20 #include "game_errors.hpp"
23 #include "game_preferences.hpp"
24 #include "game_state.hpp"
26 #include "hotkey/hotkey_item.hpp"
27 #include "play_controller.hpp"
28 #include "preferences_display.hpp"
29 #include "savegame.hpp"
30 #include "saved_game.hpp"
31 #include "whiteboard/manager.hpp"
32 #include "wmi_pager.hpp"
33 
34 #include "units/unit.hpp"
35 
37 
39  : play_controller_(pc)
40  , menu_handler_(pc.get_menu_handler())
41  , mouse_handler_(pc.get_mouse_handler_base())
42  , saved_game_(sg)
43  , savenames_()
44  , wml_commands_()
45  , wml_command_pager_(new wmi_pager())
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 
64 bool play_controller::hotkey_handler::browse() const { return play_controller_.is_browsing(); }
65 bool play_controller::hotkey_handler::linger() const { return play_controller_.is_lingering(); }
66 
67 const team & play_controller::hotkey_handler::viewing_team() const { return play_controller_.get_teams_const()[gui()->viewing_team()]; }
68 bool play_controller::hotkey_handler::viewing_team_is_playing() const { return gui()->viewing_team() == gui()->playing_team(); }
69 
71  menu_handler_.objectives(gui()->viewing_team()+1);
72 }
73 
75  menu_handler_.show_statistics(gui()->viewing_team()+1);
76 }
77 
80 }
81 
84 }
85 
87  play_controller_.save_game();
88 }
89 
91  play_controller_.save_replay();
92 }
93 
95  play_controller_.save_map();
96 }
97 
99  play_controller_.load_game();
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  mouse_handler_.move_action(browse());
127 }
128 
131 }
133  mouse_handler_.select_hex(gui()->mouseover_hex(), false);
134 }
135 
137  int x = gui()->get_location_x(gui()->mouseover_hex());
138  int y = gui()->get_location_y(gui()->mouseover_hex());
139 
140  SDL_MouseButtonEvent event;
141 
142  event.button = 3;
143  event.x = x + 30;
144  event.y = y + 30;
145  event.which = 0;
146  event.state = SDL_PRESSED;
147 
148  mouse_handler_.mouse_press(event, true);
149 }
150 
151 
153  mouse_handler_.cycle_units(browse());
154 }
155 
158 }
159 
162 }
163 
166 }
167 
169  play_controller_.undo();
170 }
171 
173  play_controller_.redo();
174 }
175 
177  menu_handler_.show_enemy_moves(ignore_units, play_controller_.current_side());
178 }
179 
181  menu_handler_.goto_leader(play_controller_.current_side());
182 }
183 
186 }
187 
190 }
191 
194 }
195 
198 }
199 
202 }
203 
205 {
207 
208  if (preferences::turbo())
209  {
210  utils::string_map symbols;
212  gui()->announce(std::string(_("Accelerated speed enabled!")) + "\n" + vgettext("(press $hk to disable)", symbols), font::NORMAL_COLOR);
213  }
214  else
215  {
216  gui()->announce(_("Accelerated speed disabled!"), font::NORMAL_COLOR);
217  }
218 }
219 
221 {
222  play_controller_.set_scroll_up(on);
223 }
224 
226 {
227  play_controller_.set_scroll_down(on);
228 }
229 
231 {
232  play_controller_.set_scroll_left(on);
233 }
234 
236 {
237  play_controller_.set_scroll_right(on);
238 }
239 
241 {
242  hotkey::HOTKEY_COMMAND command = cmd.id;
243  if(index >= 0) {
244  unsigned i = static_cast<unsigned>(index);
245  if(i < savenames_.size() && !savenames_[i].empty()) {
246  // Load the game by throwing load_game_exception
247  load_autosave(savenames_[i]);
248 
249  } else if ( i < wml_commands_.size() && wml_commands_[i] ) {
250  if (!wml_command_pager_->capture(*wml_commands_[i])) {
251  wml_commands_[i]->fire_event(mouse_handler_.get_last_hex(), gamestate().gamedata_);
252  } else { //relaunch the menu
253  show_menu(gui()->get_theme().context_menu()->items(),last_context_menu_x_,last_context_menu_y_,true, *gui());
254  }
255  return true;
256  }
257  }
258  int prefixlen = wml_menu_hotkey_prefix.length();
259  if(command == hotkey::HOTKEY_WML && cmd.command.compare(0, prefixlen, wml_menu_hotkey_prefix) == 0)
260  {
261  std::string name = cmd.command.substr(prefixlen);
263 
264  gamestate().get_wml_menu_items().fire_item(name, hex, gamestate().gamedata_, gamestate(), gamestate().board_.units_);
265  /// @todo Shouldn't the function return at this point?
266  }
267  return command_executor::execute_command(cmd, index, press);
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:
320  case hotkey::HOTKEY_NULL:
323  case hotkey::LUA_CONSOLE:
328  return true;
329 
330  // Commands that have some preconditions:
333 
336  return !linger() && play_controller_.enemies_visible();
337 
339  return !play_controller_.is_networked_mp(); // Can only load games if not in a network game
340 
342  return true;
343 
344  case hotkey::HOTKEY_REDO:
345  return play_controller_.can_redo();
346  case hotkey::HOTKEY_UNDO:
347  return play_controller_.can_undo();
348 
350  return menu_handler_.current_unit().valid();
351 
353  return mouse_handler_.get_last_hex().valid();
354 
356  return !events::commands_disabled &&
358  !(menu_handler_.current_unit()->unrenamable()) &&
359  menu_handler_.current_unit()->side() == gui()->viewing_side() &&
360  play_controller_.get_teams_const()[menu_handler_.current_unit()->side() - 1].is_local_human();
361 
362  default:
363  return false;
364  }
365 }
366 
367 
368 static void trim_items(std::vector<std::string>& newitems) {
369  if (newitems.size() > 5) {
370  std::vector<std::string> subitems;
371  subitems.push_back(newitems[0]);
372  subitems.push_back(newitems[1]);
373  subitems.push_back(newitems[newitems.size() / 3]);
374  subitems.push_back(newitems[newitems.size() * 2 / 3]);
375  subitems.push_back(newitems.back());
376  newitems = subitems;
377  }
378 }
379 
381 {
382  const compression::format comp_format =
384 
385  savenames_.clear();
386  for (unsigned int i = 0; i < items.size(); ++i) {
387  if (items[i] == "AUTOSAVES") {
388  items.erase(items.begin() + i);
389  std::vector<std::string> newitems;
390  std::vector<std::string> newsaves;
391  for (unsigned int turn = play_controller_.turn(); turn != 0; turn--) {
392  std::string name = saved_game_.classification().label + "-" + _("Auto-Save") + std::to_string(turn);
393  if (savegame::save_game_exists(name, comp_format)) {
394  newsaves.push_back(
395  name + compression::format_extension(comp_format));
396  newitems.push_back(_("Back to Turn ") + std::to_string(turn));
397  }
398  }
399 
400  const std::string& start_name = saved_game_.classification().label;
401  if(savegame::save_game_exists(start_name, comp_format)) {
402  newsaves.push_back(
403  start_name + compression::format_extension(comp_format));
404  newitems.push_back(_("Back to Start"));
405  }
406 
407  // Make sure list doesn't get too long: keep top two,
408  // midpoint and bottom.
409  trim_items(newitems);
410  trim_items(newsaves);
411 
412  items.insert(items.begin()+i, newitems.begin(), newitems.end());
413  savenames_.insert(savenames_.end(), newsaves.begin(), newsaves.end());
414  break;
415  }
416  savenames_.push_back("");
417  }
418 }
419 
421 {
422  wml_commands_.clear();
423  for (unsigned int i = 0; i < items.size(); ++i) {
424  if (items[i] == "wml") {
425  std::vector<std::string> newitems;
426 
427  // Replace this placeholder entry with available menu items.
428  items.erase(items.begin() + i);
429  wml_command_pager_->update_ref(&gamestate().get_wml_menu_items());
430  wml_command_pager_->get_items(mouse_handler_.get_last_hex(),
432  wml_commands_, newitems);
433  items.insert(items.begin()+i, newitems.begin(), newitems.end());
434  // End the "for" loop.
435  break;
436  }
437  // Pad the commands with null pointers (keeps the indices of items and
438  // wml_commands_ synced).
439  wml_commands_.push_back(const_item_ptr());
440  }
441 }
442 
443 void play_controller::hotkey_handler::show_menu(const std::vector<std::string>& items_arg, int xloc, int yloc, bool context_menu, display& disp)
444 {
445  if (context_menu)
446  {
447  last_context_menu_x_ = xloc;
448  last_context_menu_y_ = yloc;
449  }
450 
451  std::vector<std::string> items = items_arg;
452  const hotkey::hotkey_command* cmd;
453  std::vector<std::string>::iterator i = items.begin();
454  while(i != items.end()) {
455  if (*i == "AUTOSAVES") {
456  // Autosave visibility is similar to LOAD_GAME hotkey
457 
458  ++i; continue; //cmd = &hotkey::hotkey_command::get_command_by_command(hotkey::HOTKEY_LOAD_GAME);
459  } else {
460  cmd = &hotkey::get_hotkey_command(*i);
461  }
462  // Remove commands that can't be executed or don't belong in this type of menu
463  if(*i != "wml" && (!can_execute_command(*cmd) || (context_menu && !in_context_menu(cmd->id)))) {
464  i = items.erase(i);
465  continue;
466  }
467  ++i;
468  }
469 
470  // Add special non-hotkey items to the menu and remember their indices
471  expand_autosaves(items);
472  expand_wml_commands(items);
473 
474  if(items.empty())
475  return;
476 
477  command_executor::show_menu(items, xloc, yloc, context_menu, disp);
478 }
479 
481 {
482  switch(command) {
483  // Only display these if the mouse is over a castle or keep tile
486  case hotkey::HOTKEY_RECALL: {
487  // last_hex_ is set by mouse_events::mouse_motion
488  const map_location & last_hex = mouse_handler_.get_last_hex();
489  const int viewing_side = gui()->viewing_side();
490 
491  // A quick check to save us having to create the future map and
492  // possibly loop through all units.
493  if ( !play_controller_.get_map_const().is_keep(last_hex) &&
494  !play_controller_.get_map_const().is_castle(last_hex) )
495  return false;
496 
497  wb::future_map future; /* lasts until method returns. */
498 
499  return gamestate().side_can_recruit_on(viewing_side, last_hex);
500  }
501  default:
502  return true;
503  }
504 }
505 
507 {
508  if(index >= 0 && index < static_cast<int>(wml_commands_.size())) {
509  const const_item_ptr wmi = wml_commands_[index];
510  if ( wmi ) {
511  return wmi->image();
512  }
513  }
514  return command_executor::get_action_image(command, index);
515 }
516 
518 {
519  switch(command) {
520 
532  return (gui()->get_zoom_factor() == 1.0) ? hotkey::ACTION_ON : hotkey::ACTION_OFF;
534  return viewing_team().auto_shroud_updates() ? hotkey::ACTION_OFF : hotkey::ACTION_ON;
535  default:
537  }
538 }
539 
541 {
542  throw game::load_game_exception(filename, false, false, false, "", true);
543 }
static const config & get_theme(const config &game_config, std::string theme_name)
void set_turbo(bool ison)
void goto_leader(int side_num)
bool minimap_draw_units()
hotkey_handler(play_controller &, saved_game &)
virtual void scroll_up(bool on)
virtual void show_menu(const std::vector< std::string > &items_arg, int xloc, int yloc, bool context_menu, display &disp)
void mouse_press(const SDL_MouseButtonEvent &event, const bool browse)
std::string label
Name of the game (e.g.
void expand_wml_commands(std::vector< std::string > &items)
Replaces "wml" in items with all active WML menu items for the current field.
events::mouse_handler mouse_handler_
virtual hotkey::ACTION_STATE get_action_state(hotkey::HOTKEY_COMMAND command, int index) const
bool fire_item(const std::string &id, const map_location &hex, game_data &gamedata, filter_context &fc, unit_map &units) const
Fires the menu item with the given id.
bool minimap_movement_coding()
virtual void scroll_left(bool on)
General purpose widgets.
Stores all information related to functions that can be bound to hotkeys.
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
const std::vector< std::string > items
const map_location & get_last_hex() const
virtual std::string get_action_image(hotkey::HOTKEY_COMMAND, int index) const
This file implements all the hotkey handling and menu details for play controller.
const SDL_Color NORMAL_COLOR
Definition: font.cpp:564
void select_hex(const map_location &hex, const bool browse, const bool highlight=true, const bool fire_event=true)
void show_statistics(int side_num)
events::menu_handler menu_handler_
bool in_context_menu(hotkey::HOTKEY_COMMAND command) const
Determines whether the command should be in the context menu or not.
bool minimap_draw_villages()
saved_game & saved_game_
unit_map units_
Definition: game_board.hpp:63
virtual void scroll_down(bool on)
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
virtual void scroll_right(bool on)
std::map< std::string, t_string > string_map
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:368
bool valid() const
Definition: location.hpp:69
Applies the planned unit map for the duration of the struct's life.
Definition: manager.hpp:249
size_t turn() const
void status_table(int selected=0)
static bool execute_command(std::string &command_line)
Definition: sdl2.cpp:104
bool save_game_exists(const std::string &name, compression::format compressed)
Returns true if there is already a savegame with that name.
Definition: savegame.cpp:61
void expand_autosaves(std::vector< std::string > &items)
virtual bool can_execute_command(const hotkey::hotkey_command &command, int index=-1) const
Check if a command can be executed.
static void trim_items(std::vector< std::string > &newitems)
const team & viewing_team() const
static const std::string wml_menu_hotkey_prefix
virtual void show_enemy_moves(bool ignore_units)
Encapsulates the map of the game.
Definition: location.hpp:38
void cycle_back_units(const bool browse)
Declarations for a container for wml_menu_item.
Various functions related to the creation of units (recruits, recalls, and placed units)...
std::string format_extension(format compression_format)
Definition: compression.hpp:27
virtual void load_autosave(const std::string &filename)
const std::string command
The command is unique.
Exception used to signal that the user has decided to abort a game, and to load another game instead...
Definition: game_errors.hpp:62
GLuint index
Definition: glew.h:1782
void terrain_description(mouse_handler &mousehandler)
size_t i
Definition: function.cpp:1057
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
game_data gamedata_
Definition: game_state.hpp:48
std::string get_names(std::string id)
Returns a comma-separated string of hotkey names.
void objectives(int side_num)
void cycle_units(const bool browse, const bool reverse=false)
void show_menu(const std::vector< std::string > &items_arg, int xloc, int yloc, bool context_menu, display &disp)
std::string vgettext(const char *msgid, const utils::string_map &symbols)
GLuint const GLchar * name
Definition: glew.h:1782
compression::format save_compression_format()
unit_map::iterator current_unit()
game_state & gamestate()
bool minimap_draw_terrain()
cl_event event
Definition: glew.h:3070
const hotkey::HOTKEY_COMMAND id
the names are strange: the "hotkey::HOTKEY_COMMAND" is named id, and the string to identify the objec...
game_display * gui() const
game_classification & classification()
Definition: saved_game.hpp:54
void show_enemy_moves(bool ignore_units, int side_num)
game_board board_
Definition: game_state.hpp:49
virtual bool execute_command(const hotkey::hotkey_command &command, int index=-1, bool press=true)
bool valid() const
Definition: map.hpp:229
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
const hotkey_command & get_hotkey_command(const std::string &command)
returns the hotkey_command with the given name
GLsizei const GLcharARB ** string
Definition: glew.h:4503
virtual bool in_context_menu(hotkey::HOTKEY_COMMAND command) const
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()
std::string linger
Definition: game_config.cpp:84
game_events::wmi_container & get_wml_menu_items()
Definition: game_state.cpp:385