hotkeys.cpp

Go to the documentation of this file.
00001 /* $Id: hotkeys.cpp 26501 2008-05-09 22:44:58Z mordante $ */
00002 /*
00003    Copyright (C) 2003 - 2008 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 #include "global.hpp"
00016 
00017 #define GETTEXT_DOMAIN "wesnoth-lib"
00018 
00019 #include "config.hpp"
00020 #include "construct_dialog.hpp"
00021 #include "display.hpp"
00022 #include "events.hpp"
00023 #include "hotkeys.hpp"
00024 #include "game_config.hpp"
00025 #include "game_errors.hpp"
00026 #include "gettext.hpp"
00027 #include "filesystem.hpp"
00028 #include "log.hpp"
00029 #include "menu_events.hpp"
00030 #include "preferences_display.hpp"
00031 #include "show_dialog.hpp"
00032 #include "util.hpp"
00033 #include "video.hpp"
00034 #include "wesconfig.h"
00035 #include "wml_separators.hpp"
00036 #include "SDL.h"
00037 
00038 #include <algorithm>
00039 #include <cstdlib>
00040 #include <map>
00041 
00042 #define ERR_G LOG_STREAM(err, general)
00043 #define LOG_G LOG_STREAM(info, general)
00044 #define DBG_G LOG_STREAM(debug, general)
00045 #define ERR_CONFIG LOG_STREAM(err, config)
00046 
00047 namespace {
00048 
00049 const struct {
00050     hotkey::HOTKEY_COMMAND id;
00051     const char* command;
00052     const char* description;
00053     bool hidden;
00054 } hotkey_list_[] = {
00055     { hotkey::HOTKEY_CYCLE_UNITS, "cycle", N_("Next Unit"), false },
00056     { hotkey::HOTKEY_CYCLE_BACK_UNITS, "cycleback", N_("Previous Unit"), false },
00057     { hotkey::HOTKEY_UNIT_HOLD_POSITION, "holdposition", N_("Hold Position"), false},
00058     { hotkey::HOTKEY_END_UNIT_TURN, "endunitturn", N_("End Unit Turn"), false },
00059     { hotkey::HOTKEY_LEADER, "leader", N_("Leader"), false },
00060     { hotkey::HOTKEY_UNDO, "undo", N_("Undo"), false },
00061     { hotkey::HOTKEY_REDO, "redo", N_("Redo"), false },
00062     { hotkey::HOTKEY_ZOOM_IN, "zoomin", N_("Zoom In"), false },
00063     { hotkey::HOTKEY_ZOOM_OUT, "zoomout", N_("Zoom Out"), false },
00064     { hotkey::HOTKEY_ZOOM_DEFAULT, "zoomdefault", N_("Default Zoom"), false },
00065     { hotkey::HOTKEY_FULLSCREEN, "fullscreen", N_("Toggle Full Screen"), false },
00066     { hotkey::HOTKEY_SCREENSHOT, "screenshot", N_("Screenshot"), false },
00067     { hotkey::HOTKEY_MAP_SCREENSHOT, "mapscreenshot", N_("Map Screenshot"), false },
00068     { hotkey::HOTKEY_ACCELERATED, "accelerated", N_("Accelerated"), false },
00069     { hotkey::HOTKEY_UNIT_DESCRIPTION, "describeunit", N_("Unit Description"), false },
00070     { hotkey::HOTKEY_RENAME_UNIT, "renameunit", N_("Rename Unit"), false },
00071     { hotkey::HOTKEY_SAVE_GAME, "save", N_("Save Game"), false },
00072     { hotkey::HOTKEY_SAVE_REPLAY, "savereplay", N_("Save Replay"), false },
00073     { hotkey::HOTKEY_SAVE_MAP, "savemap", N_("Save The Map"), false },
00074     { hotkey::HOTKEY_LOAD_GAME, "load", N_("Load Game"), false },
00075     { hotkey::HOTKEY_RECRUIT, "recruit", N_("Recruit"), false },
00076     { hotkey::HOTKEY_REPEAT_RECRUIT, "repeatrecruit", N_("Repeat Recruit"), false },
00077     { hotkey::HOTKEY_RECALL, "recall", N_("Recall"), false },
00078     { hotkey::HOTKEY_ENDTURN, "endturn", N_("End Turn"), false },
00079     { hotkey::HOTKEY_TOGGLE_GRID, "togglegrid", N_("Toggle Grid"), false },
00080     { hotkey::HOTKEY_MOUSE_SCROLL, "mousescroll", N_("Mouse Scrolling"), false },
00081     { hotkey::HOTKEY_STATUS_TABLE, "statustable", N_("Status Table"), false },
00082     { hotkey::HOTKEY_MUTE, "mute", N_("Mute"), false },
00083     { hotkey::HOTKEY_SPEAK, "speak", N_("Speak"), false },
00084     { hotkey::HOTKEY_CREATE_UNIT, "createunit", N_("Create Unit (Debug!)"), false },
00085     { hotkey::HOTKEY_CHANGE_UNIT_SIDE, "changeside", N_("Change Unit Side (Debug!)"), false },
00086     { hotkey::HOTKEY_PREFERENCES, "preferences", N_("Preferences"), false },
00087     { hotkey::HOTKEY_OBJECTIVES, "objectives", N_("Scenario Objectives"), false },
00088     { hotkey::HOTKEY_UNIT_LIST, "unitlist", N_("Unit List"), false },
00089     { hotkey::HOTKEY_STATISTICS, "statistics", N_("Statistics"), false },
00090     { hotkey::HOTKEY_QUIT_GAME, "quit", N_("Quit Game"), false },
00091     { hotkey::HOTKEY_LABEL_TEAM_TERRAIN, "labelteamterrain", N_("Set Team Label"), false },
00092     { hotkey::HOTKEY_LABEL_TERRAIN, "labelterrain", N_("Set Label"), false },
00093     { hotkey::HOTKEY_CLEAR_LABELS, "clearlabels", N_("Clear Labels"), false },
00094     { hotkey::HOTKEY_SHOW_ENEMY_MOVES, "showenemymoves", N_("Show Enemy Moves"), false },
00095     { hotkey::HOTKEY_BEST_ENEMY_MOVES, "bestenemymoves", N_("Best Possible Enemy Moves"), false },
00096     { hotkey::HOTKEY_PLAY_REPLAY, "playreplay", N_("Play"), false },
00097     { hotkey::HOTKEY_RESET_REPLAY, "resetreplay", N_("Reset"), false },
00098     { hotkey::HOTKEY_STOP_REPLAY, "stopreplay", N_("Stop"), false },
00099     { hotkey::HOTKEY_REPLAY_NEXT_TURN, "replaynextturn", N_("Next Turn"), false },
00100     { hotkey::HOTKEY_REPLAY_NEXT_SIDE, "replaynextside", N_("Next Side"), false },
00101     { hotkey::HOTKEY_REPLAY_SHOW_EVERYTHING, "replayshoweverything",
00102       N_("Full map"), false },
00103     { hotkey::HOTKEY_REPLAY_SHOW_EACH, "replayshoweach",
00104       N_("Each team"), false },
00105     { hotkey::HOTKEY_REPLAY_SHOW_TEAM1, "replayshowteam1",
00106       N_("Team 1"), false },
00107     { hotkey::HOTKEY_REPLAY_SKIP_ANIMATION, "replayskipanimation", N_("Skip animation"), false },
00108 
00109     { hotkey::HOTKEY_EDIT_SET_TERRAIN, "editsetterrain", N_("Set Terrain"),true },
00110     { hotkey::HOTKEY_EDIT_QUIT, "editquit", N_("Quit Editor"),true },
00111     { hotkey::HOTKEY_EDIT_NEW_MAP, "editnewmap", N_("New Map"),true },
00112     { hotkey::HOTKEY_EDIT_LOAD_MAP, "editloadmap", N_("Load Map"),true },
00113     { hotkey::HOTKEY_EDIT_SAVE_MAP, "editsavemap", N_("Save Map"),true },
00114     { hotkey::HOTKEY_EDIT_SAVE_AS, "editsaveas", N_("Save As"),true },
00115     { hotkey::HOTKEY_EDIT_SET_START_POS, "editsetstartpos", N_("Set Player's keep"),true },
00116     { hotkey::HOTKEY_EDIT_FLOOD_FILL, "editfloodfill", N_("Flood Fill"),true },
00117     { hotkey::HOTKEY_EDIT_FILL_SELECTION, "editfillselection", N_("Fill Selection"),true },
00118     { hotkey::HOTKEY_EDIT_ROTATE_SELECTION, "editrotateselection", N_("Rotate Selection"),true },
00119     { hotkey::HOTKEY_EDIT_CUT, "editcut", N_("Cut"),true },
00120     { hotkey::HOTKEY_EDIT_COPY, "editcopy", N_("Copy"),true },
00121     { hotkey::HOTKEY_EDIT_PASTE, "editpaste", N_("Paste"),true },
00122     { hotkey::HOTKEY_EDIT_REVERT, "editrevert", N_("Revert from Disk"),true },
00123     { hotkey::HOTKEY_EDIT_RESIZE, "editresize", N_("Resize Map"),true },
00124     { hotkey::HOTKEY_EDIT_FLIP, "editflip", N_("Flip Map"),true },
00125     { hotkey::HOTKEY_EDIT_SELECT_ALL, "editselectall", N_("Select All"),true },
00126     { hotkey::HOTKEY_EDIT_DRAW, "editdraw", N_("Draw Terrain"),true },
00127     { hotkey::HOTKEY_EDIT_REFRESH, "editrefresh", N_("Refresh Image Cache"), true },
00128     { hotkey::HOTKEY_EDIT_AUTO_UPDATE, "editautoupdate", N_("Delay transition updates"), true },
00129     { hotkey::HOTKEY_EDIT_UPDATE, "editupdate", N_("Update transitions"), true },
00130 
00131     { hotkey::HOTKEY_DELAY_SHROUD, "delayshroud", N_("Delay Shroud Updates"), false },
00132     { hotkey::HOTKEY_UPDATE_SHROUD, "updateshroud", N_("Update Shroud Now"), false },
00133     { hotkey::HOTKEY_CONTINUE_MOVE, "continue", N_("Continue Move"), false },
00134     { hotkey::HOTKEY_SEARCH, "search", N_("Find Label or Unit"), false },
00135     { hotkey::HOTKEY_SPEAK_ALLY, "speaktoally", N_("Speak to Ally"), false },
00136     { hotkey::HOTKEY_SPEAK_ALL, "speaktoall", N_("Speak to All"), false },
00137     { hotkey::HOTKEY_HELP, "help", N_("Help"), false },
00138     { hotkey::HOTKEY_CHAT_LOG, "chatlog", N_("View Chat Log"), false },
00139     { hotkey::HOTKEY_LANGUAGE, "changelanguage", N_("Change the language"), true },
00140 
00141     { hotkey::HOTKEY_USER_CMD, "command", N_("Enter user command"), false },
00142     { hotkey::HOTKEY_CUSTOM_CMD, "customcommand", N_("Custom command"), false },
00143     { hotkey::HOTKEY_AI_FORMULA, "aiformula", N_("Run AI formula"), false },
00144     { hotkey::HOTKEY_CLEAR_MSG, "clearmessages", N_("Clear messages"), false },
00145 #ifdef USRCMD2
00146     { hotkey::HOTKEY_USER_CMD_2, "usercommand#2", N_("User-Command#2"), false },
00147     { hotkey::HOTKEY_USER_CMD_3, "usercommand#3", N_("User-Command#3"), false },
00148 #endif
00149     { hotkey::HOTKEY_NULL, NULL, NULL, true }
00150 };
00151 
00152 std::vector<hotkey::hotkey_item> hotkeys_;
00153 hotkey::hotkey_item null_hotkey_;
00154 
00155 }
00156 
00157 namespace hotkey {
00158 
00159 static void key_event_execute(display& disp, const SDL_KeyboardEvent& event, command_executor* executor);
00160 
00161 const std::string CLEARED_TEXT = "__none__";
00162 
00163 hotkey_item::hotkey_item(HOTKEY_COMMAND id, 
00164         const std::string& command, const std::string& description, bool hidden) :
00165     id_(id), 
00166     command_(command), 
00167     description_(description), 
00168     type_(UNBOUND),
00169     character_(0),
00170     ctrl_(false), 
00171     alt_(false), 
00172     cmd_(false),
00173     keycode_(0),
00174     shift_(false), 
00175     hidden_(hidden)
00176 {
00177 }
00178 
00179 // There are two kinds of "key" values.  One refers to actual keys, like
00180 // F1 or SPACE.  The other refers to characters produced, eg 'M' or ':'.
00181 // For the latter, specifying shift+; doesn't make sense, because ; is
00182 // already shifted on French keyboards, for example.  You really want to
00183 // say ':', however that is typed.  However, when you say shift+SPACE,
00184 // you're really referring to the space bar, as shift+SPACE usually just
00185 // produces a SPACE character.
00186 void hotkey_item::load_from_config(const config& cfg)
00187 {
00188     const std::string& key = cfg["key"];
00189 
00190     alt_ = utils::string_bool(cfg["alt"]);
00191     cmd_ = utils::string_bool(cfg["cmd"]);
00192     ctrl_ = utils::string_bool(cfg["ctrl"]);
00193     shift_ = utils::string_bool(cfg["shift"]);
00194 
00195     if (!key.empty()) {
00196         // They may really want a specific key on the keyboard: we assume
00197         // that any single character keyname is a character.
00198         if (key == CLEARED_TEXT)
00199         {
00200             type_ = hotkey_item::CLEARED;
00201         }
00202         else if (key.size() > 1) {
00203             type_ = BY_KEYCODE;
00204 
00205             keycode_ = sdl_keysym_from_name(key);
00206             if (keycode_ == SDLK_UNKNOWN) {
00207                 if (tolower(key[0]) != 'f') {
00208                     ERR_CONFIG << "hotkey key '" << key << "' invalid\n";
00209                 } else {
00210                     int num = lexical_cast_default<int>
00211                         (std::string(key.begin()+1, key.end()), 1);
00212                     keycode_ = num + SDLK_F1 - 1;
00213                 }
00214             }
00215         } else if (key == " " || shift_
00216 #ifdef __APPLE__
00217                || alt_
00218 #endif
00219                ) {
00220             // Space must be treated as a key because shift-space
00221             // isn't a different character from space, and control key
00222             // makes it go weird.  shift=yes should never be specified
00223             // on single characters (eg. key=m, shift=yes would be
00224             // key=M), but we don't want to break old preferences
00225             // files.
00226             type_ = BY_KEYCODE;
00227             keycode_ = key[0];
00228         } else {
00229             type_ = BY_CHARACTER;
00230             character_ = key[0];
00231         }
00232     }
00233 }
00234 
00235 std::string hotkey_item::get_name() const
00236 {
00237     std::stringstream str;
00238     if (type_ == BY_CHARACTER) {
00239         if (alt_)
00240             str << "alt+";
00241         if (cmd_)
00242             str << "cmd+";
00243         if (ctrl_)
00244             str << "ctrl+";
00245         str << static_cast<char>(character_);
00246     } else if (type_ == BY_KEYCODE) {
00247         if (alt_)
00248             str << "alt+";
00249         if (ctrl_)
00250             str << "ctrl+";
00251         if (shift_)
00252             str << "shift+";
00253         if (cmd_)
00254             str << "cmd+";
00255         str << SDL_GetKeyName(SDLKey(keycode_));
00256     }
00257     return str.str();
00258 }
00259 
00260 void hotkey_item::set_description(const std::string& description)
00261 {
00262     description_ = description;
00263 }
00264 void hotkey_item::clear_hotkey()
00265 {
00266     type_ = CLEARED;
00267 }
00268 
00269 void hotkey_item::set_key(int character, int keycode, bool shift, bool ctrl, bool alt, bool cmd)
00270 {
00271     const std::string keyname = SDL_GetKeyName(SDLKey(keycode));
00272 
00273     LOG_G << "setting hotkey: char=" << lexical_cast<std::string>(character)
00274            << " keycode="  << lexical_cast<std::string>(keycode) << " "
00275            << (shift ? "shift," : "")
00276            << (ctrl ? "ctrl," : "")
00277            << (alt ? "alt," : "")
00278            << (cmd ? "cmd," : "")
00279            << "\n";
00280 
00281     // Sometimes control modifies by -64, ie ^A == 1.
00282     if (character < 64 && ctrl) {
00283         if (shift)
00284             character += 64;
00285         else
00286             character += 96;
00287         LOG_G << "Mapped to character " << lexical_cast<std::string>(character) << "\n";
00288     }
00289 
00290     // For some reason on Mac OS, if cmd and shift are down, the character doesn't get upper-cased
00291     if (cmd && character > 96 && character < 123 && shift)
00292         character -= 32;
00293 
00294     // We handle simple cases by character, others by the actual key.
00295     if (isprint(character) && !isspace(character)) {
00296         type_ = BY_CHARACTER;
00297         character_ = character;
00298         ctrl_ = ctrl;
00299         alt_ = alt;
00300         cmd_ = cmd;
00301         LOG_G << "type = BY_CHARACTER\n";
00302     } else {
00303         type_ = BY_KEYCODE;
00304         keycode_ = keycode;
00305         shift_ = shift;
00306         ctrl_ = ctrl;
00307         alt_ = alt;
00308         cmd_ = cmd;
00309         LOG_G << "type = BY_KEYCODE\n";
00310     }
00311 }
00312 
00313 manager::manager()
00314 {
00315     for (int i = 0; hotkey_list_[i].command; ++i) {
00316         hotkeys_.push_back(hotkey_item(hotkey_list_[i].id, hotkey_list_[i].command,
00317                 "", hotkey_list_[i].hidden));
00318     }
00319 }
00320 
00321 
00322 manager::~manager()
00323 {
00324     hotkeys_.clear();
00325 }
00326 
00327 void load_descriptions()
00328 {
00329     for (size_t i = 0; hotkey_list_[i].command; ++i) {
00330         if (i >= hotkeys_.size()) {
00331             ERR_G << "Hotkey list too short: " << hotkeys_.size() << "\n";
00332         }
00333         hotkeys_[i].set_description(dsgettext(PACKAGE "-lib", hotkey_list_[i].description));
00334     }
00335 }
00336 
00337 void load_hotkeys(const config& cfg)
00338 {
00339     const config::child_list& children = cfg.get_children("hotkey");
00340     for(config::child_list::const_iterator i = children.begin(); i != children.end(); ++i) {
00341         hotkey_item& h = get_hotkey((**i)["command"]);
00342 
00343         if(h.get_id() != HOTKEY_NULL) {
00344             h.load_from_config(**i);
00345         }
00346     }
00347 }
00348 
00349 void save_hotkeys(config& cfg)
00350 {
00351     cfg.clear_children("hotkey");
00352 
00353     for(std::vector<hotkey_item>::iterator i = hotkeys_.begin(); i != hotkeys_.end(); ++i) {
00354         if (i->hidden() || i->get_type() == hotkey_item::UNBOUND)
00355             continue;
00356 
00357         config& item = cfg.add_child("hotkey");
00358         item["command"] = i->get_command();
00359         
00360         if (i->get_type() == hotkey_item::CLEARED)
00361         {
00362             item["key"] = CLEARED_TEXT;
00363             continue;
00364         }
00365 
00366         if (i->get_type() == hotkey_item::BY_KEYCODE) {
00367             item["key"] = SDL_GetKeyName(SDLKey(i->get_keycode()));
00368             item["shift"] = i->get_shift() ? "yes" : "no";
00369         } else if (i->get_type() == hotkey_item::BY_CHARACTER) {
00370             item["key"] = std::string(1, static_cast<char>(i->get_character()));
00371         }
00372         item["alt"] = i->get_alt() ? "yes" : "no";
00373         item["ctrl"] = i->get_ctrl() ? "yes" : "no";
00374         item["cmd"] = i->get_cmd() ? "yes" : "no";
00375     }
00376 }
00377 
00378 hotkey_item& get_hotkey(HOTKEY_COMMAND id)
00379 {
00380     std::vector<hotkey_item>::iterator itor;
00381 
00382     for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
00383         if (itor->get_id() == id)
00384             break;
00385     }
00386 
00387     if (itor == hotkeys_.end())
00388         return null_hotkey_;
00389 
00390     return *itor;
00391 }
00392 
00393 hotkey_item& get_hotkey(const std::string& command)
00394 {
00395     std::vector<hotkey_item>::iterator itor;
00396 
00397     for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
00398         if (itor->get_command() == command)
00399             break;
00400     }
00401 
00402     if (itor == hotkeys_.end())
00403         return null_hotkey_;
00404 
00405     return *itor;
00406 }
00407 
00408 hotkey_item& get_hotkey(int character, int keycode, bool shift, bool ctrl, bool alt, bool cmd)
00409 {
00410     std::vector<hotkey_item>::iterator itor;
00411 
00412     DBG_G << "getting hotkey: char=" << lexical_cast<std::string>(character)
00413            << " keycode="  << lexical_cast<std::string>(keycode) << " "
00414            << (shift ? "shift," : "")
00415            << (ctrl ? "ctrl," : "")
00416            << (alt ? "alt," : "")
00417            << (cmd ? "cmd," : "")
00418            << "\n";
00419 
00420     // Sometimes control modifies by -64, ie ^A == 1.
00421     if (character < 64 && ctrl) {
00422         if (shift)
00423             character += 64;
00424         else
00425             character += 96;
00426         DBG_G << "Mapped to character " << lexical_cast<std::string>(character) << "\n";
00427     }
00428 
00429     // For some reason on Mac OS, if cmd and shift are down, the character doesn't get upper-cased
00430     if (cmd && character > 96 && character < 123 && shift)
00431         character -= 32;
00432 
00433     for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
00434         if (itor->get_type() == hotkey_item::BY_CHARACTER) {
00435             if (character == itor->get_character()) {
00436                 if (ctrl == itor->get_ctrl()
00437                     && alt == itor->get_alt()
00438                     && cmd == itor->get_cmd()) {
00439                     DBG_G << "Could match by character..." << "yes\n";
00440                     break;
00441                 }
00442                 DBG_G << "Could match by character..." << "but modifiers different\n";
00443             }
00444         } else if (itor->get_type() == hotkey_item::BY_KEYCODE) {
00445             if (keycode == itor->get_keycode()) {
00446                 if (shift == itor->get_shift()
00447                     && ctrl == itor->get_ctrl()
00448                     && alt == itor->get_alt()
00449                     && cmd == itor->get_cmd()) {
00450                     DBG_G << "Could match by keycode..." << "yes\n";
00451                     break;
00452                 }
00453                 DBG_G << "Could match by keycode..." << "but modifiers different\n";
00454             }
00455         }
00456     }
00457 
00458     if (itor == hotkeys_.end())
00459         return null_hotkey_;
00460 
00461     return *itor;
00462 }
00463 
00464 hotkey_item& get_hotkey(const SDL_KeyboardEvent& event)
00465 {
00466     return get_hotkey(event.keysym.unicode, event.keysym.sym,
00467             (event.keysym.mod & KMOD_SHIFT) != 0,
00468             (event.keysym.mod & KMOD_CTRL) != 0,
00469             (event.keysym.mod & KMOD_ALT) != 0,
00470             (event.keysym.mod & KMOD_LMETA) != 0
00471 #ifdef __APPLE__
00472             || (event.keysym.mod & KMOD_RMETA) != 0
00473 #endif
00474             );
00475 }
00476 
00477 static void _get_visible_hotkey_itor(int index, std::vector<hotkey_item>::iterator& itor)
00478 {
00479     int counter = 0;
00480     for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
00481         if (itor->hidden())
00482             continue;
00483 
00484         if (index == counter)
00485             break;
00486 
00487         counter++;
00488     }
00489 }
00490 
00491 hotkey_item& get_visible_hotkey(int index)
00492 {
00493 
00494     std::vector<hotkey_item>::iterator itor;
00495     _get_visible_hotkey_itor(index, itor);
00496     if (itor == hotkeys_.end())
00497         return null_hotkey_;
00498 
00499     return *itor;
00500 }
00501 
00502 std::vector<hotkey_item>& get_hotkeys()
00503 {
00504     return hotkeys_;
00505 }
00506 
00507 basic_handler::basic_handler(display* disp, command_executor* exec) : disp_(disp), exec_(exec) {}
00508 
00509 void basic_handler::handle_event(const SDL_Event& event)
00510 {
00511     if(event.type == SDL_KEYDOWN && disp_ != NULL) {
00512 
00513         //if we're in a dialog we only want to handle things that are explicitly handled
00514         //by the executor. If we're not in a dialog we can call the regular key event handler
00515         if(!gui::in_dialog()) {
00516             key_event(*disp_,event.key,exec_);
00517         } else if(exec_ != NULL) {
00518             key_event_execute(*disp_,event.key,exec_);
00519         }
00520     }
00521 }
00522 
00523 
00524 void key_event(display& disp, const SDL_KeyboardEvent& event, command_executor* executor)
00525 {
00526     if(event.keysym.sym == SDLK_ESCAPE && disp.in_game()) {
00527         ERR_G << "escape pressed..showing quit\n";
00528         const int res = gui::dialog(disp,_("Quit"),_("Do you really want to quit?"),gui::YES_NO).show();
00529         if(res == 0) {
00530             throw end_level_exception(QUIT);
00531         } else {
00532             return;
00533         }
00534     }
00535 
00536     key_event_execute(disp,event,executor);
00537 }
00538 
00539 void key_event_execute(display& disp, const SDL_KeyboardEvent& event, command_executor* executor)
00540 {
00541     const hotkey_item* hk = &get_hotkey(event);
00542 
00543 #if 0
00544     // This is not generally possible without knowing keyboard layout.
00545     if(hk->null()) {
00546         //no matching hotkey was found, but try an in-exact match.
00547         hk = &get_hotkey(event, true);
00548     }
00549 #endif
00550 
00551     if(hk->null())
00552         return;
00553 
00554     execute_command(disp,hk->get_id(),executor);
00555 }
00556 
00557 bool command_executor::execute_command(HOTKEY_COMMAND command, int /*index*/)
00558 {
00559     switch(command) {
00560         case HOTKEY_CYCLE_UNITS:
00561             cycle_units();
00562             break;
00563         case HOTKEY_CYCLE_BACK_UNITS:
00564             cycle_back_units();
00565             break;
00566         case HOTKEY_ENDTURN:
00567             end_turn();
00568             break;
00569         case HOTKEY_UNIT_HOLD_POSITION:
00570             unit_hold_position();
00571             break;
00572         case HOTKEY_END_UNIT_TURN:
00573             end_unit_turn();
00574             break;
00575         case HOTKEY_LEADER:
00576             goto_leader();
00577             break;
00578         case HOTKEY_UNDO:
00579             undo();
00580             break;
00581         case HOTKEY_REDO:
00582             redo();
00583             break;
00584         case HOTKEY_UNIT_DESCRIPTION:
00585             unit_description();
00586             break;
00587         case HOTKEY_RENAME_UNIT:
00588             rename_unit();
00589             break;
00590         case HOTKEY_SAVE_GAME:
00591             save_game();
00592             break;
00593         case HOTKEY_SAVE_REPLAY:
00594             save_replay();
00595             break;
00596         case HOTKEY_SAVE_MAP:
00597             save_map();
00598             break;
00599         case HOTKEY_LOAD_GAME:
00600             load_game();
00601             break;
00602         case HOTKEY_TOGGLE_GRID:
00603             toggle_grid();
00604             break;
00605         case HOTKEY_STATUS_TABLE:
00606             status_table();
00607             break;
00608         case HOTKEY_RECALL:
00609             recall();
00610             break;
00611         case HOTKEY_RECRUIT:
00612             recruit();
00613             break;
00614         case hotkey::HOTKEY_REPEAT_RECRUIT:
00615             repeat_recruit();
00616             break;
00617         case HOTKEY_SPEAK:
00618             speak();
00619             break;
00620         case HOTKEY_SPEAK_ALLY:
00621             whisper();
00622             break;
00623         case HOTKEY_SPEAK_ALL:
00624             shout();
00625             break;
00626         case HOTKEY_CREATE_UNIT:
00627             create_unit();
00628             break;
00629         case HOTKEY_CHANGE_UNIT_SIDE:
00630             change_unit_side();
00631             break;
00632         case HOTKEY_PREFERENCES:
00633             preferences();
00634             break;
00635         case HOTKEY_OBJECTIVES:
00636             objectives();
00637             break;
00638         case HOTKEY_UNIT_LIST:
00639             unit_list();
00640             break;
00641         case HOTKEY_STATISTICS:
00642             show_statistics();
00643             break;
00644         case HOTKEY_LABEL_TEAM_TERRAIN:
00645             label_terrain(true);
00646             break;
00647         case HOTKEY_LABEL_TERRAIN:
00648             label_terrain(false);
00649             break;
00650         case HOTKEY_CLEAR_LABELS:
00651             clear_labels();
00652             break;
00653         case HOTKEY_SHOW_ENEMY_MOVES:
00654             show_enemy_moves(false);
00655             break;
00656         case HOTKEY_BEST_ENEMY_MOVES:
00657             show_enemy_moves(true);
00658             break;
00659         case HOTKEY_DELAY_SHROUD:
00660             toggle_shroud_updates();
00661             break;
00662         case HOTKEY_UPDATE_SHROUD:
00663             update_shroud_now();
00664             break;
00665         case HOTKEY_CONTINUE_MOVE:
00666             continue_move();
00667             break;
00668         case HOTKEY_SEARCH:
00669             search();
00670             break;
00671         case HOTKEY_HELP:
00672             show_help();
00673             break;
00674         case HOTKEY_CHAT_LOG:
00675             show_chat_log();
00676             break;
00677         case HOTKEY_USER_CMD:
00678             user_command();
00679             break;
00680         case HOTKEY_CUSTOM_CMD:
00681             custom_command();
00682             break;
00683 //%%
00684         case HOTKEY_AI_FORMULA:
00685             std::cerr <<" run ai formula\n";
00686             ai_formula();
00687             break;
00688         case HOTKEY_CLEAR_MSG:
00689             clear_messages();
00690             break;
00691 #ifdef USRCMD2
00692         case HOTKEY_USER_CMD_2:
00693             //user_command();
00694             user_command_2();
00695             break;
00696         case HOTKEY_USER_CMD_3:
00697             user_command_3();
00698             break;
00699 #endif
00700 
00701         case HOTKEY_EDIT_SET_TERRAIN:
00702             edit_set_terrain();
00703             break;
00704         case HOTKEY_EDIT_QUIT:
00705             edit_quit();
00706             break;
00707          case HOTKEY_EDIT_NEW_MAP:
00708             edit_new_map();
00709             break;
00710          case HOTKEY_EDIT_LOAD_MAP:
00711             edit_load_map();
00712             break;
00713          case HOTKEY_EDIT_SAVE_MAP:
00714             edit_save_map();
00715             break;
00716          case HOTKEY_EDIT_SAVE_AS:
00717             edit_save_as();
00718             break;
00719          case HOTKEY_EDIT_SET_START_POS:
00720             edit_set_start_pos();
00721             break;
00722          case HOTKEY_EDIT_FLOOD_FILL:
00723             edit_flood_fill();
00724             break;
00725          case HOTKEY_EDIT_FILL_SELECTION:
00726             edit_fill_selection();
00727             break;
00728          case HOTKEY_EDIT_ROTATE_SELECTION:
00729             edit_rotate_selection();
00730             break;
00731          case HOTKEY_EDIT_CUT:
00732             edit_cut();
00733             break;
00734          case HOTKEY_EDIT_PASTE:
00735             edit_paste();
00736             break;
00737          case HOTKEY_EDIT_COPY:
00738             edit_copy();
00739             break;
00740          case HOTKEY_EDIT_REVERT:
00741             edit_revert();
00742             break;
00743          case HOTKEY_EDIT_RESIZE:
00744             edit_resize();
00745             break;
00746          case HOTKEY_EDIT_FLIP:
00747             edit_flip();
00748             break;
00749          case HOTKEY_EDIT_SELECT_ALL:
00750             edit_select_all();
00751             break;
00752          case HOTKEY_EDIT_DRAW:
00753             edit_draw();
00754             break;
00755          case HOTKEY_EDIT_REFRESH:
00756             edit_refresh();
00757             break;
00758          case HOTKEY_EDIT_UPDATE:
00759             edit_update();
00760             break;
00761          case HOTKEY_EDIT_AUTO_UPDATE:
00762             edit_auto_update();
00763             break;
00764 
00765          case HOTKEY_LANGUAGE:
00766             change_language();
00767             break;
00768          case HOTKEY_PLAY_REPLAY:
00769             play_replay();
00770              break;
00771          case HOTKEY_RESET_REPLAY:
00772             reset_replay();
00773              break;
00774          case HOTKEY_STOP_REPLAY:
00775              stop_replay();
00776              break;
00777          case HOTKEY_REPLAY_NEXT_TURN:
00778             replay_next_turn();
00779              break;
00780          case HOTKEY_REPLAY_NEXT_SIDE:
00781             replay_next_side();
00782              break;
00783          case HOTKEY_REPLAY_SHOW_EVERYTHING:
00784             replay_show_everything();
00785              break;
00786          case HOTKEY_REPLAY_SHOW_EACH:
00787             replay_show_each();
00788              break;
00789          case HOTKEY_REPLAY_SHOW_TEAM1:
00790             replay_show_team1();
00791              break;
00792          case HOTKEY_REPLAY_SKIP_ANIMATION:
00793             replay_skip_animation();
00794              break;
00795          default:
00796              return false;
00797     }
00798     return true;
00799 }
00800 
00801 void execute_command(display& disp, HOTKEY_COMMAND command, command_executor* executor, int index)
00802 {
00803     const int zoom_amount = 4;
00804     bool map_screenshot = false;
00805     
00806     if(executor != NULL) {
00807         if(!executor->can_execute_command(command, index) || executor->execute_command(command, index))
00808         return;
00809     }
00810     switch(command) {
00811         case HOTKEY_ZOOM_IN:
00812             disp.set_zoom(zoom_amount);
00813             break;
00814         case HOTKEY_ZOOM_OUT:
00815             disp.set_zoom(-zoom_amount);
00816             break;
00817         case HOTKEY_ZOOM_DEFAULT:
00818             disp.set_default_zoom();
00819             break;
00820         case HOTKEY_FULLSCREEN:
00821             preferences::set_fullscreen(!preferences::fullscreen());
00822             break;
00823         case HOTKEY_MAP_SCREENSHOT:
00824             if (!disp.in_game() && !disp.in_editor())
00825                 break;
00826             map_screenshot = true;
00827         case HOTKEY_SCREENSHOT: {
00828             std::string name = map_screenshot ? _("Map-Screenshot") : _("Screenshot");
00829             std::string filename = get_screenshot_dir() + "/" + name + "_";
00830             filename = get_next_filename(filename, ".bmp");
00831             int size = disp.screenshot(filename, map_screenshot);
00832             if (size > 0) {
00833                 std::stringstream res;
00834                 res << filename << " ( " << size/1000000 <<" "<< (size/1000)%1000 << " KB )";
00835                 gui::dialog(disp,_("Screenshot done"),res.str(),gui::MESSAGE).show();
00836             } else
00837                 gui::dialog(disp,_("Screenshot failed"),"",gui::MESSAGE).show();
00838             break;
00839         }
00840         case HOTKEY_MOUSE_SCROLL:
00841             preferences::enable_mouse_scroll(!preferences::mouse_scroll_enabled());
00842             break;
00843         case HOTKEY_ACCELERATED:
00844             preferences::set_turbo(!preferences::turbo());
00845             break;
00846         case HOTKEY_MUTE:
00847             {
00848                 // look if both is not playing
00849                 static struct before_muted_s
00850                 {
00851                     bool playing_sound,playing_music;
00852                     before_muted_s() : playing_sound(false),playing_music(false){}
00853                 } before_muted;
00854                 if (preferences::music_on() || preferences::sound_on())
00855                 {
00856                     //then remember settings and mute both
00857                     before_muted.playing_sound = preferences::sound_on();
00858                     before_muted.playing_music = preferences::music_on();
00859                     preferences::set_sound(false);
00860                     preferences::set_music(false);
00861                 }
00862                 else
00863                 {
00864                     //then set settings before mute
00865                     preferences::set_sound(before_muted.playing_sound);
00866                     preferences::set_music(before_muted.playing_music);
00867                 }
00868             }
00869             break;
00870         case HOTKEY_QUIT_GAME: {
00871             if(disp.in_game()) {
00872                 DBG_G << "is in game -- showing quit message\n";
00873                 const int res = gui::dialog(disp,_("Quit"),_("Do you really want to quit?"),gui::YES_NO).show();
00874                 if(res == 0) {
00875                     throw end_level_exception(QUIT);
00876                 }
00877             }
00878 
00879             break;
00880         }
00881         default:
00882             DBG_G << "command_executor: unknown command number " << command << ", ignoring.\n";
00883             break;
00884     }
00885 }
00886 
00887 void command_executor::show_menu(const std::vector<std::string>& items_arg, int xloc, int yloc, bool context_menu, display& gui)
00888 {
00889     std::vector<std::string> items = items_arg;
00890     if (can_execute_command(hotkey::get_hotkey(items.front()).get_id(), 0)){
00891         //if just one item is passed in, that means we should execute that item
00892         if(!context_menu && items.size() == 1 && items_arg.size() == 1) {
00893             hotkey::execute_command(gui,hotkey::get_hotkey(items.front()).get_id(),this);
00894             return;
00895         }
00896 
00897         std::vector<std::string> menu = get_menu_images(items);
00898 
00899         int res = 0;
00900         {
00901             gui::dialog mmenu = gui::dialog(gui,"","",
00902             gui::MESSAGE, gui::dialog::hotkeys_style);
00903             mmenu.set_menu(menu);
00904             res = mmenu.show(xloc, yloc);
00905         } // this will kill the dialog
00906         if (res < 0 || size_t(res) >= items.size())
00907             return;
00908 
00909         const hotkey::HOTKEY_COMMAND cmd = hotkey::get_hotkey(items[res]).get_id();
00910         hotkey::execute_command(gui,cmd,this,res);
00911     }
00912 }
00913 
00914 std::string command_executor::get_menu_image(hotkey::HOTKEY_COMMAND command, int index) const {
00915     switch(get_action_state(command)) {
00916         case ACTION_ON: return game_config::checked_menu_image;
00917         case ACTION_OFF: return game_config::unchecked_menu_image;
00918         default: return get_action_image(command, index);
00919     }
00920 }
00921 
00922 std::vector<std::string> command_executor::get_menu_images(const std::vector<std::string>& items){
00923     std::vector<std::string> result;
00924     bool has_image = false;
00925 
00926     for(size_t i = 0; i < items.size(); ++i) {
00927         std::string const& item = items[i];
00928         const hotkey::hotkey_item hk = hotkey::get_hotkey(item);
00929 
00930         std::stringstream str;
00931         //see if this menu item has an associated image
00932         std::string img(get_menu_image(hk.get_id(), i));
00933         if(img.empty() == false) {
00934             has_image = true;
00935             str << IMAGE_PREFIX << img << COLUMN_SEPARATOR;
00936         }
00937 
00938         if (hk.get_id() == hotkey::HOTKEY_NULL) {
00939             str << item.substr(0, item.find_last_not_of(' ') + 1) << COLUMN_SEPARATOR;
00940         } else {
00941             str << hk.get_description() << COLUMN_SEPARATOR << hk.get_name();
00942         }
00943 
00944         result.push_back(str.str());
00945     }
00946     //If any of the menu items have an image, create an image column
00947     if(has_image)
00948         for(std::vector<std::string>::iterator i = result.begin(); i != result.end(); ++i)
00949             if(*(i->begin()) != IMAGE_PREFIX)
00950                 i->insert(i->begin(), COLUMN_SEPARATOR);
00951     return result;
00952 }
00953 
00954 }

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs