1 /*
2 Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
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
15 #include "hotkey/command_executor.hpp"
16 #include "hotkey/hotkey_item.hpp"
17
18 #include "gui/dialogs/lua_interpreter.hpp"
19 #include "gui/dialogs/message.hpp"
20 #include "gui/dialogs/screenshot_notification.hpp"
21 #include "gui/dialogs/transient_message.hpp"
22 #include "gui/dialogs/drop_down_menu.hpp"
23 #include "gui/widgets/retval.hpp"
24 #include "filesystem.hpp"
25 #include "gettext.hpp"
26 #include "log.hpp"
27 #include "preferences/general.hpp"
28 #include "game_end_exceptions.hpp"
29 #include "display.hpp"
30 #include "quit_confirmation.hpp"
31 #include "sdl/surface.hpp"
32 #include "show_dialog.hpp"
33 #include "../resources.hpp"
34 #include "../playmp_controller.hpp"
35
36 #include "utils/functional.hpp"
37
38 #include <SDL2/SDL_image.h>
39
40 #include <cassert>
41 #include <ios>
42 #include <set>
43
44 static lg::log_domain log_config("config");
45 static lg::log_domain log_hotkey("hotkey");
46 #define ERR_G LOG_STREAM(err, lg::general())
47 #define WRN_G LOG_STREAM(warn, lg::general())
48 #define LOG_G LOG_STREAM(info, lg::general())
49 #define DBG_G LOG_STREAM(debug, lg::general())
50 #define ERR_CF LOG_STREAM(err, log_config)
51 #define LOG_HK LOG_STREAM(info, log_hotkey)
52
53 namespace {
54
make_screenshot(const std::string & name,bool map_screenshot)55 void make_screenshot(const std::string& name, bool map_screenshot)
56 {
57 surface screenshot = display::get_singleton()->screenshot(map_screenshot);
58 if(screenshot) {
59 std::string filename = filesystem::get_screenshot_dir() + "/" + name + "_";
60 filename = filesystem::get_next_filename(filename, ".png");
61 gui2::dialogs::screenshot_notification::display(filename, screenshot);
62 }
63 }
64 }
65 namespace hotkey {
66
67 static void event_queue(const SDL_Event& event, command_executor* executor);
68
do_execute_command(const hotkey_command & cmd,int,bool press,bool release)69 bool command_executor::do_execute_command(const hotkey_command& cmd, int /*index*/, bool press, bool release)
70 {
71 // hotkey release handling
72 if (release) {
73 switch(cmd.id) {
74 // release a scroll key, un-apply scrolling in the given direction
75 case HOTKEY_SCROLL_UP:
76 scroll_up(false);
77 break;
78 case HOTKEY_SCROLL_DOWN:
79 scroll_down(false);
80 break;
81 case HOTKEY_SCROLL_LEFT:
82 scroll_left(false);
83 break;
84 case HOTKEY_SCROLL_RIGHT:
85 scroll_right(false);
86 break;
87 default:
88 return false; // nothing else handles a hotkey release
89 }
90
91 return true;
92 }
93
94 // handling of hotkeys which activate even on hold events
95 switch(cmd.id) {
96 case HOTKEY_REPEAT_RECRUIT:
97 repeat_recruit();
98 return true;
99 case HOTKEY_SCROLL_UP:
100 scroll_up(true);
101 return true;
102 case HOTKEY_SCROLL_DOWN:
103 scroll_down(true);
104 return true;
105 case HOTKEY_SCROLL_LEFT:
106 scroll_left(true);
107 return true;
108 case HOTKEY_SCROLL_RIGHT:
109 scroll_right(true);
110 return true;
111 default:
112 break;
113 }
114
115 if(!press) {
116 return false; // nothing else handles hotkey hold events
117 }
118
119 // hotkey press handling
120 switch(cmd.id) {
121 case HOTKEY_CYCLE_UNITS:
122 cycle_units();
123 break;
124 case HOTKEY_CYCLE_BACK_UNITS:
125 cycle_back_units();
126 break;
127 case HOTKEY_ENDTURN:
128 end_turn();
129 break;
130 case HOTKEY_UNIT_HOLD_POSITION:
131 unit_hold_position();
132 break;
133 case HOTKEY_END_UNIT_TURN:
134 end_unit_turn();
135 break;
136 case HOTKEY_LEADER:
137 goto_leader();
138 break;
139 case HOTKEY_UNDO:
140 undo();
141 break;
142 case HOTKEY_REDO:
143 redo();
144 break;
145 case HOTKEY_TERRAIN_DESCRIPTION:
146 terrain_description();
147 break;
148 case HOTKEY_UNIT_DESCRIPTION:
149 unit_description();
150 break;
151 case HOTKEY_RENAME_UNIT:
152 rename_unit();
153 break;
154 case HOTKEY_SAVE_GAME:
155 save_game();
156 break;
157 case HOTKEY_SAVE_REPLAY:
158 save_replay();
159 break;
160 case HOTKEY_SAVE_MAP:
161 save_map();
162 break;
163 case HOTKEY_LOAD_GAME:
164 load_game();
165 break;
166 case HOTKEY_TOGGLE_ELLIPSES:
167 toggle_ellipses();
168 break;
169 case HOTKEY_TOGGLE_GRID:
170 toggle_grid();
171 break;
172 case HOTKEY_STATUS_TABLE:
173 status_table();
174 break;
175 case HOTKEY_RECALL:
176 recall();
177 break;
178 case HOTKEY_LABEL_SETTINGS:
179 label_settings();
180 break;
181 case HOTKEY_RECRUIT:
182 recruit();
183 break;
184 case HOTKEY_SPEAK:
185 speak();
186 break;
187 case HOTKEY_SPEAK_ALLY:
188 whisper();
189 break;
190 case HOTKEY_SPEAK_ALL:
191 shout();
192 break;
193 case HOTKEY_CREATE_UNIT:
194 create_unit();
195 break;
196 case HOTKEY_CHANGE_SIDE:
197 change_side();
198 break;
199 case HOTKEY_KILL_UNIT:
200 kill_unit();
201 break;
202 case HOTKEY_PREFERENCES:
203 preferences();
204 break;
205 case HOTKEY_OBJECTIVES:
206 objectives();
207 break;
208 case HOTKEY_UNIT_LIST:
209 unit_list();
210 break;
211 case HOTKEY_STATISTICS:
212 show_statistics();
213 break;
214 case HOTKEY_STOP_NETWORK:
215 stop_network();
216 break;
217 case HOTKEY_START_NETWORK:
218 start_network();
219 break;
220 case HOTKEY_LABEL_TEAM_TERRAIN:
221 label_terrain(true);
222 break;
223 case HOTKEY_LABEL_TERRAIN:
224 label_terrain(false);
225 break;
226 case HOTKEY_CLEAR_LABELS:
227 clear_labels();
228 break;
229 case HOTKEY_SHOW_ENEMY_MOVES:
230 show_enemy_moves(false);
231 break;
232 case HOTKEY_BEST_ENEMY_MOVES:
233 show_enemy_moves(true);
234 break;
235 case HOTKEY_DELAY_SHROUD:
236 toggle_shroud_updates();
237 break;
238 case HOTKEY_UPDATE_SHROUD:
239 update_shroud_now();
240 break;
241 case HOTKEY_CONTINUE_MOVE:
242 continue_move();
243 break;
244 case HOTKEY_SEARCH:
245 search();
246 break;
247 case HOTKEY_HELP:
248 show_help();
249 break;
250 case HOTKEY_CHAT_LOG:
251 show_chat_log();
252 break;
253 case HOTKEY_USER_CMD:
254 user_command();
255 break;
256 case HOTKEY_CUSTOM_CMD:
257 custom_command();
258 break;
259 case HOTKEY_AI_FORMULA:
260 ai_formula();
261 break;
262 case HOTKEY_CLEAR_MSG:
263 clear_messages();
264 break;
265 case HOTKEY_LANGUAGE:
266 change_language();
267 break;
268 case HOTKEY_REPLAY_PLAY:
269 play_replay();
270 break;
271 case HOTKEY_REPLAY_RESET:
272 reset_replay();
273 break;
274 case HOTKEY_REPLAY_STOP:
275 stop_replay();
276 break;
277 case HOTKEY_REPLAY_NEXT_TURN:
278 replay_next_turn();
279 break;
280 case HOTKEY_REPLAY_NEXT_SIDE:
281 replay_next_side();
282 break;
283 case HOTKEY_REPLAY_NEXT_MOVE:
284 replay_next_move();
285 break;
286 case HOTKEY_REPLAY_SHOW_EVERYTHING:
287 replay_show_everything();
288 break;
289 case HOTKEY_REPLAY_SHOW_EACH:
290 replay_show_each();
291 break;
292 case HOTKEY_REPLAY_SHOW_TEAM1:
293 replay_show_team1();
294 break;
295 case HOTKEY_REPLAY_SKIP_ANIMATION:
296 replay_skip_animation();
297 break;
298 case HOTKEY_REPLAY_EXIT:
299 replay_exit();
300 break;
301 case HOTKEY_WB_TOGGLE:
302 whiteboard_toggle();
303 break;
304 case HOTKEY_WB_EXECUTE_ACTION:
305 whiteboard_execute_action();
306 break;
307 case HOTKEY_WB_EXECUTE_ALL_ACTIONS:
308 whiteboard_execute_all_actions();
309 break;
310 case HOTKEY_WB_DELETE_ACTION:
311 whiteboard_delete_action();
312 break;
313 case HOTKEY_WB_BUMP_UP_ACTION:
314 whiteboard_bump_up_action();
315 break;
316 case HOTKEY_WB_BUMP_DOWN_ACTION:
317 whiteboard_bump_down_action();
318 break;
319 case HOTKEY_WB_SUPPOSE_DEAD:
320 whiteboard_suppose_dead();
321 break;
322 case HOTKEY_SELECT_HEX:
323 select_hex();
324 break;
325 case HOTKEY_DESELECT_HEX:
326 deselect_hex();
327 break;
328 case HOTKEY_MOVE_ACTION:
329 move_action();
330 break;
331 case HOTKEY_SELECT_AND_ACTION:
332 select_and_action();
333 break;
334 case HOTKEY_TOUCH_HEX:
335 touch_hex();
336 break;
337 case HOTKEY_ACCELERATED:
338 toggle_accelerated_speed();
339 break;
340 case LUA_CONSOLE:
341 lua_console();
342 break;
343 case HOTKEY_ZOOM_IN:
344 zoom_in();
345 break;
346 case HOTKEY_ZOOM_OUT:
347 zoom_out();
348 break;
349 case HOTKEY_ZOOM_DEFAULT:
350 zoom_default();
351 break;
352 case HOTKEY_MAP_SCREENSHOT:
353 map_screenshot();
354 break;
355 case HOTKEY_QUIT_TO_DESKTOP:
356 quit_confirmation::quit_to_desktop();
357 break;
358 case HOTKEY_QUIT_GAME:
359 quit_confirmation::quit_to_title();
360 break;
361 case HOTKEY_SURRENDER:
362 surrender_game();
363 break;
364 case HOTKEY_MINIMAP_DRAW_TERRAIN:
365 preferences::toggle_minimap_draw_terrain();
366 recalculate_minimap();
367 break;
368 case HOTKEY_MINIMAP_CODING_TERRAIN:
369 preferences::toggle_minimap_terrain_coding();
370 recalculate_minimap();
371 break;
372 case HOTKEY_MINIMAP_CODING_UNIT:
373 preferences::toggle_minimap_movement_coding();
374 recalculate_minimap();
375 break;
376 case HOTKEY_MINIMAP_DRAW_UNITS:
377 preferences::toggle_minimap_draw_units();
378 recalculate_minimap();
379 break;
380 case HOTKEY_MINIMAP_DRAW_VILLAGES:
381 preferences::toggle_minimap_draw_villages();
382 recalculate_minimap();
383 break;
384 default:
385 return false;
386 }
387 return true;
388 }
389
surrender_game()390 void command_executor::surrender_game() {
391 if(gui2::show_message(_("Surrender"), _("Do you really want to surrender the game?"), gui2::dialogs::message::yes_no_buttons) != gui2::retval::CANCEL) {
392 playmp_controller* pmc = dynamic_cast<playmp_controller*>(resources::controller);
393 if(pmc && !pmc->is_linger_mode() && !pmc->is_observer()) {
394 pmc->surrender(display::get_singleton()->viewing_team());
395 }
396 }
397 }
398
show_menu(const std::vector<config> & items_arg,int xloc,int yloc,bool,display & gui)399 void command_executor::show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool /*context_menu*/, display& gui)
400 {
401 std::vector<config> items = items_arg;
402 if (items.empty()) return;
403
404 get_menu_images(gui, items);
405
406 int res = -1;
407 {
408 SDL_Rect pos {xloc, yloc, 1, 1};
409 gui2::dialogs::drop_down_menu mmenu(pos, items, -1, true, false); // TODO: last value should be variable
410 if(mmenu.show()) {
411 res = mmenu.selected_item();
412 }
413 } // This will kill the dialog.
414 if (res < 0 || size_t(res) >= items.size()) return;
415
416 const theme::menu* submenu = gui.get_theme().get_menu_item(items[res]["id"]);
417 if (submenu) {
418 int y,x;
419 SDL_GetMouseState(&x,&y);
420 this->show_menu(submenu->items(), x, y, submenu->is_context(), gui);
421 } else {
422 const hotkey::hotkey_command& cmd = hotkey::get_hotkey_command(items[res]["id"]);
423 do_execute_command(cmd, res);
424 set_button_state();
425 }
426 }
427
execute_action(const std::vector<std::string> & items_arg,int,int,bool,display &)428 void command_executor::execute_action(const std::vector<std::string>& items_arg, int /*xloc*/, int /*yloc*/, bool /*context_menu*/, display&)
429 {
430 std::vector<std::string> items = items_arg;
431 if (items.empty()) {
432 return;
433 }
434
435 std::vector<std::string>::iterator i = items.begin();
436 while(i != items.end()) {
437 const hotkey_command &command = hotkey::get_hotkey_command(*i);
438 if (can_execute_command(command)) {
439 do_execute_command(command);
440 set_button_state();
441 }
442 ++i;
443 }
444 }
445
get_menu_image(display & disp,const std::string & command,int index) const446 std::string command_executor::get_menu_image(display& disp, const std::string& command, int index) const {
447
448 // TODO: Find a way to do away with the fugly special markup
449 if(command[0] == '&') {
450 size_t n = command.find_first_of('=');
451 if(n != std::string::npos)
452 return command.substr(1, n - 1);
453 }
454
455 const std::string base_image_name = "icons/action/" + command + "_25.png";
456 const std::string pressed_image_name = "icons/action/" + command + "_25-pressed.png";
457
458 const hotkey::HOTKEY_COMMAND hk = hotkey::get_id(command);
459 const hotkey::ACTION_STATE state = get_action_state(hk, index);
460
461 const theme::menu* menu = disp.get_theme().get_menu_item(command);
462 if (menu) {
463 return "icons/arrows/short_arrow_right_25.png~CROP(3,3,18,18)"; // TODO should not be hardcoded
464 }
465
466 if (filesystem::file_exists(game_config::path + "/images/" + base_image_name)) {
467 switch (state) {
468 case ACTION_ON:
469 case ACTION_SELECTED:
470 return pressed_image_name + "~CROP(3,3,18,18)";
471 default:
472 return base_image_name + "~CROP(3,3,18,18)";
473 }
474 }
475
476 switch (get_action_state(hk, index)) {
477 case ACTION_ON:
478 return game_config::images::checked_menu;
479 case ACTION_OFF:
480 return game_config::images::unchecked_menu;
481 case ACTION_SELECTED:
482 return game_config::images::selected_menu;
483 case ACTION_DESELECTED:
484 return game_config::images::deselected_menu;
485 default: return get_action_image(hk, index);
486 }
487 }
488
get_menu_images(display & disp,std::vector<config> & items)489 void command_executor::get_menu_images(display& disp, std::vector<config>& items)
490 {
491 for(size_t i = 0; i < items.size(); ++i) {
492 config& item = items[i];
493
494 const std::string& item_id = item["id"];
495 const hotkey::HOTKEY_COMMAND hk = hotkey::get_id(item_id);
496
497 //see if this menu item has an associated image
498 std::string img(get_menu_image(disp, item_id, i));
499 if (img.empty() == false) {
500 item["icon"] = img;
501 }
502
503 const theme::menu* menu = disp.get_theme().get_menu_item(item_id);
504 if(menu) {
505 item["label"] = menu->title();
506 } else if(hk != hotkey::HOTKEY_NULL) {
507 std::string desc = hotkey::get_description(item_id);
508 if(hk == HOTKEY_ENDTURN) {
509 const theme::action *b = disp.get_theme().get_action_item("button-endturn");
510 if (b) {
511 desc = b->title();
512 }
513 }
514
515 item["label"] = desc;
516 item["details"] = hotkey::get_names(item_id);
517 } else if(item["label"].empty()) {
518 // If no matching hotkey was found and a custom label wasn't already set, treat
519 // the id as a plaintext description. This is because either type of value can
520 // be written to the id field by the WMI manager. The plaintext description is
521 // used in the case the menu item specifies the relevant entry is *not* a hotkey.
522 item["label"] = item_id;
523 }
524 }
525 }
526
mbutton_event(const SDL_Event & event,command_executor * executor)527 void mbutton_event(const SDL_Event& event, command_executor* executor)
528 {
529 event_queue(event, executor);
530
531 /* Run mouse events immediately.
532
533 This is necessary because the sidebar doesn't allow set_button_state() to be called after a
534 button has received the mouse press event but before it has received the mouse release event.
535 When https://github.com/wesnoth/wesnoth/pull/2872 delayed the processing of input events,
536 set_button_state() ended up being called at such a time. However, if we run the event handlers
537 now, the button (if any) hasn't received the press event yet and we can call set_button_state()
538 safely.
539
540 See https://github.com/wesnoth/wesnoth/issues/2884 */
541
542 run_events(executor);
543 }
544
jbutton_event(const SDL_Event & event,command_executor * executor)545 void jbutton_event(const SDL_Event& event, command_executor* executor)
546 {
547 event_queue(event, executor);
548 }
549
jhat_event(const SDL_Event & event,command_executor * executor)550 void jhat_event(const SDL_Event& event, command_executor* executor)
551 {
552 event_queue(event, executor);
553 }
554
key_event(const SDL_Event & event,command_executor * executor)555 void key_event(const SDL_Event& event, command_executor* executor)
556 {
557 if (!executor) return;
558 event_queue(event,executor);
559 }
560
keyup_event(const SDL_Event &,command_executor * executor)561 void keyup_event(const SDL_Event&, command_executor* executor)
562 {
563 if(!executor) return;
564 executor->handle_keyup();
565 }
566
run_events(command_executor * executor)567 void run_events(command_executor* executor)
568 {
569 if(!executor) return;
570 bool commands_ran = executor->run_queued_commands();
571 if(commands_ran) {
572 executor->set_button_state();
573 }
574 }
575
event_queue(const SDL_Event & event,command_executor * executor)576 static void event_queue(const SDL_Event& event, command_executor* executor)
577 {
578 if (!executor) return;
579 executor->queue_command(event);
580 }
581
queue_command(const SDL_Event & event,int index)582 void command_executor::queue_command(const SDL_Event& event, int index)
583 {
584 LOG_HK << "event 0x" << std::hex << event.type << std::dec << std::endl;
585 if(event.type == SDL_TEXTINPUT) {
586 LOG_HK << "SDL_TEXTINPUT \"" << event.text.text << "\"\n";
587 }
588
589 const hotkey_ptr hk = get_hotkey(event);
590 if(!hk->active() || hk->is_disabled()) {
591 return;
592 }
593
594 const hotkey_command& command = hotkey::get_hotkey_command(hk->get_command());
595 bool keypress = (event.type == SDL_KEYDOWN || event.type == SDL_TEXTINPUT) &&
596 !press_event_sent_;
597 bool press = keypress ||
598 (event.type == SDL_JOYBUTTONDOWN || event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_FINGERDOWN);
599 bool release = event.type == SDL_KEYUP;
600 if(press) {
601 LOG_HK << "sending press event (keypress = " <<
602 std::boolalpha << keypress << std::noboolalpha << ")\n";
603 }
604 if(keypress) {
605 press_event_sent_ = true;
606 }
607
608 command_queue_.emplace_back(command, index, press, release);
609 }
610
execute_command_wrap(const command_executor::queued_command & command)611 void command_executor::execute_command_wrap(const command_executor::queued_command& command)
612 {
613 if (!can_execute_command(*command.command, command.index)
614 || do_execute_command(*command.command, command.index, command.press, command.release)) {
615 return;
616 }
617
618 if (!command.press) {
619 return; // none of the commands here respond to a key release
620 }
621
622 switch (command.command->id) {
623 case HOTKEY_FULLSCREEN:
624 CVideo::get_singleton().toggle_fullscreen();
625 break;
626 case HOTKEY_SCREENSHOT:
627 make_screenshot(_("Screenshot"), false);
628 break;
629 case HOTKEY_ANIMATE_MAP:
630 preferences::set_animate_map(!preferences::animate_map());
631 break;
632 case HOTKEY_MOUSE_SCROLL:
633 preferences::enable_mouse_scroll(!preferences::mouse_scroll_enabled());
634 break;
635 case HOTKEY_MUTE:
636 {
637 // look if both is not playing
638 static struct before_muted_s
639 {
640 bool playing_sound,playing_music;
641 before_muted_s() : playing_sound(false),playing_music(false){}
642 } before_muted;
643 if (preferences::music_on() || preferences::sound_on())
644 {
645 // then remember settings and mute both
646 before_muted.playing_sound = preferences::sound_on();
647 before_muted.playing_music = preferences::music_on();
648 preferences::set_sound(false);
649 preferences::set_music(false);
650 }
651 else
652 {
653 // then set settings before mute
654 preferences::set_sound(before_muted.playing_sound);
655 preferences::set_music(before_muted.playing_music);
656 }
657 }
658 break;
659 default:
660 DBG_G << "command_executor: unknown command number " << command.command->id << ", ignoring.\n";
661 break;
662 }
663 }
664
665 // Removes duplicate commands caused by both SDL_KEYDOWN and SDL_TEXTINPUT triggering hotkeys.
666 // See https://github.com/wesnoth/wesnoth/issues/1736
filter_command_queue()667 std::vector<command_executor::queued_command> command_executor::filter_command_queue()
668 {
669 std::vector<queued_command> filtered_commands;
670
671 /** A command plus "key released" flag. Otherwise, we will filter out key releases that are preceded by a keypress. */
672 using command_with_keyrelease = std::pair<const hotkey_command*, bool>;
673 std::set<command_with_keyrelease> seen_commands;
674
675 for(const queued_command& cmd : command_queue_) {
676 command_with_keyrelease command_key(cmd.command, cmd.release);
677 if(seen_commands.find(command_key) == seen_commands.end()) {
678 seen_commands.insert(command_key);
679 filtered_commands.push_back(cmd);
680 }
681 }
682
683 command_queue_.clear();
684
685 return filtered_commands;
686 }
687
run_queued_commands()688 bool command_executor::run_queued_commands()
689 {
690 std::vector<queued_command> commands = filter_command_queue();
691 for(const queued_command& cmd : commands) {
692 execute_command_wrap(cmd);
693 }
694
695 return !commands.empty();
696 }
697
set_button_state()698 void command_executor_default::set_button_state()
699 {
700 display& disp = get_display();
701 for (const theme::menu& menu : disp.get_theme().menus()) {
702
703 std::shared_ptr<gui::button> button = disp.find_menu_button(menu.get_id());
704 if (!button) continue;
705 bool enabled = false;
706 for (const auto& command : menu.items()) {
707
708 const hotkey::hotkey_command& command_obj = hotkey::get_hotkey_command(command["id"]);
709 bool can_execute = can_execute_command(command_obj);
710 if (can_execute) {
711 enabled = true;
712 break;
713 }
714 }
715 button->enable(enabled);
716 }
717
718 for (const theme::action& action : disp.get_theme().actions()) {
719
720 std::shared_ptr<gui::button> button = disp.find_action_button(action.get_id());
721 if (!button) continue;
722 bool enabled = false;
723 int i = 0;
724 for (const std::string& command : action.items()) {
725
726 const hotkey::hotkey_command& command_obj = hotkey::get_hotkey_command(command);
727 std::string tooltip = action.tooltip(i);
728 if (filesystem::file_exists(game_config::path + "/images/icons/action/" + command + "_25.png" ))
729 button->set_overlay("icons/action/" + command);
730 if (!tooltip.empty())
731 button->set_tooltip_string(tooltip);
732
733 bool can_execute = can_execute_command(command_obj);
734 i++;
735 if (!can_execute) continue;
736 enabled = true;
737
738 ACTION_STATE state = get_action_state(command_obj.id, -1);
739 switch (state) {
740 case ACTION_SELECTED:
741 case ACTION_ON:
742 button->set_check(true);
743 break;
744 case ACTION_OFF:
745 case ACTION_DESELECTED:
746 button->set_check(false);
747 break;
748 case ACTION_STATELESS:
749 break;
750 default:
751 break;
752 }
753
754 break;
755 }
756 button->enable(enabled);
757 }
758 }
759
recalculate_minimap()760 void command_executor_default::recalculate_minimap()
761 {
762 get_display().recalculate_minimap();
763 }
764
lua_console()765 void command_executor_default::lua_console()
766 {
767 if (get_display().in_game()) {
768 gui2::dialogs::lua_interpreter::display(gui2::dialogs::lua_interpreter::GAME);
769 } else {
770 command_executor::lua_console();
771 }
772
773 }
774
lua_console()775 void command_executor::lua_console()
776 {
777 gui2::dialogs::lua_interpreter::display(gui2::dialogs::lua_interpreter::APP);
778 }
779
zoom_in()780 void command_executor_default::zoom_in()
781 {
782 if(!get_display().view_locked()) {
783 get_display().set_zoom(true);
784 }
785 }
786
zoom_out()787 void command_executor_default::zoom_out()
788 {
789 if(!get_display().view_locked()) {
790 get_display().set_zoom(false);
791 }
792 }
793
zoom_default()794 void command_executor_default::zoom_default()
795 {
796 if(!get_display().view_locked()) {
797 get_display().set_default_zoom();
798 }
799 }
800
map_screenshot()801 void command_executor_default::map_screenshot()
802 {
803 make_screenshot(_("Map-Screenshot"), true);
804 }
805 }
806