mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-10 22:36:59 +00:00
1334 lines
41 KiB
C++
1334 lines
41 KiB
C++
/* $Id$ */
|
|
/*
|
|
Copyright (C) 2003 - 2012 by David White <dave@whitevine.net>
|
|
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY.
|
|
|
|
See the COPYING file for more details.
|
|
*/
|
|
|
|
#include "global.hpp"
|
|
|
|
#define GETTEXT_DOMAIN "wesnoth-lib"
|
|
|
|
#include "construct_dialog.hpp"
|
|
#include "display.hpp"
|
|
#include "foreach.hpp"
|
|
#include "hotkeys.hpp"
|
|
#include "game_end_exceptions.hpp"
|
|
#include "game_preferences.hpp"
|
|
#include "gettext.hpp"
|
|
#include "gui/dialogs/message.hpp"
|
|
#include "gui/dialogs/transient_message.hpp"
|
|
#include "gui/widgets/window.hpp"
|
|
#include "filesystem.hpp"
|
|
#include "log.hpp"
|
|
#include "preferences_display.hpp"
|
|
#include "wesconfig.h"
|
|
#include "wml_separators.hpp"
|
|
|
|
static lg::log_domain log_config("config");
|
|
#define ERR_G LOG_STREAM(err, lg::general)
|
|
#define LOG_G LOG_STREAM(info, lg::general)
|
|
#define DBG_G LOG_STREAM(debug, lg::general)
|
|
#define ERR_CF LOG_STREAM(err, log_config)
|
|
|
|
namespace {
|
|
|
|
const struct {
|
|
hotkey::HOTKEY_COMMAND id;
|
|
const char* command;
|
|
const char* description;
|
|
bool hidden;
|
|
hotkey::scope scope;
|
|
} hotkey_list_[] = {
|
|
|
|
{ hotkey::HOTKEY_CANCEL, "cancel", N_("Cancel"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_LEFT_MOUSE_CLICK, "leftmouseclick", N_("Left Mouse Click"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_RIGHT_MOUSE_CLICK, "rightmouseclick", N_("Right Mouse Click"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_ANIMATE_MAP, "animatemap", N_("Animate Map"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_CYCLE_UNITS, "cycle", N_("Next Unit"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_CYCLE_BACK_UNITS, "cycleback", N_("Previous Unit"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_UNIT_HOLD_POSITION, "holdposition", N_("Hold Position"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_END_UNIT_TURN, "endunitturn", N_("End Unit Turn"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_LEADER, "leader", N_("Leader"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_UNDO, "undo", N_("Undo"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_REDO, "redo", N_("Redo"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_ZOOM_IN, "zoomin", N_("Zoom In"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_ZOOM_OUT, "zoomout", N_("Zoom Out"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_ZOOM_DEFAULT, "zoomdefault", N_("Default Zoom"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_FULLSCREEN, "fullscreen", N_("Toggle Full Screen"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_SCREENSHOT, "screenshot", N_("Screenshot"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_MAP_SCREENSHOT, "mapscreenshot", N_("Map Screenshot"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_ACCELERATED, "accelerated", N_("Accelerated"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_UNIT_DESCRIPTION, "describeunit", N_("Unit Description"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_RENAME_UNIT, "renameunit", N_("Rename Unit"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_SAVE_GAME, "save", N_("Save Game"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_SAVE_REPLAY, "savereplay", N_("Save Replay"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_SAVE_MAP, "savemap", N_("Save Map"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_LOAD_GAME, "load", N_("Load Game"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_RECRUIT, "recruit", N_("Recruit"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_REPEAT_RECRUIT, "repeatrecruit", N_("Repeat Recruit"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_RECALL, "recall", N_("Recall"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_ENDTURN, "endturn", N_("End Turn"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_TOGGLE_ELLIPSES, "toggleellipses", N_("Toggle Ellipses"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_TOGGLE_GRID, "togglegrid", N_("Toggle Grid"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_MOUSE_SCROLL, "mousescroll", N_("Mouse Scrolling"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_STATUS_TABLE, "statustable", N_("Status Table"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_MUTE, "mute", N_("Mute"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_SPEAK, "speak", N_("Speak"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_CREATE_UNIT, "createunit", N_("Create Unit (Debug!)"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_CHANGE_SIDE, "changeside", N_("Change Side (Debug!)"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_PREFERENCES, "preferences", N_("Preferences"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_OBJECTIVES, "objectives", N_("Scenario Objectives"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_UNIT_LIST, "unitlist", N_("Unit List"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_STATISTICS, "statistics", N_("Statistics"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_STOP_NETWORK, "stopnetwork", N_("Pause Network Game"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_START_NETWORK, "startnetwork", N_("Continue Network Game"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_QUIT_GAME, "quit", N_("Quit Game"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_LABEL_TEAM_TERRAIN, "labelteamterrain", N_("Set Team Label"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_LABEL_TERRAIN, "labelterrain", N_("Set Label"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_CLEAR_LABELS, "clearlabels", N_("Clear Labels"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_SHOW_ENEMY_MOVES, "showenemymoves", N_("Show Enemy Moves"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_BEST_ENEMY_MOVES, "bestenemymoves", N_("Best Possible Enemy Moves"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_PLAY_REPLAY, "playreplay", N_("Play Replay"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_RESET_REPLAY, "resetreplay", N_("Reset Replay"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_STOP_REPLAY, "stopreplay", N_("Stop Replay"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_REPLAY_NEXT_TURN, "replaynextturn", N_("Next Turn"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_REPLAY_NEXT_SIDE, "replaynextside", N_("Next Side"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_REPLAY_SHOW_EVERYTHING, "replayshoweverything",
|
|
N_("Full Map"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_REPLAY_SHOW_EACH, "replayshoweach",
|
|
N_("Each Team"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_REPLAY_SHOW_TEAM1, "replayshowteam1",
|
|
N_("Team 1"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_REPLAY_SKIP_ANIMATION, "replayskipanimation", N_("Skip Animation"), false, hotkey::SCOPE_GAME },
|
|
// Whiteboard commands
|
|
{ hotkey::HOTKEY_WB_TOGGLE, "wbtoggle", N_("Toggle Planning Mode"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_WB_EXECUTE_ACTION, "wbexecuteaction", N_("Execute Planned Action"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_WB_EXECUTE_ALL_ACTIONS, "wbexecuteallactions", N_("Execute All Actions"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_WB_DELETE_ACTION, "wbdeleteaction", N_("Delete Planned Action"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_WB_BUMP_UP_ACTION, "wbbumpupaction", N_("Move Action Up Queue"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_WB_BUMP_DOWN_ACTION, "wbbumpdownaction", N_("Move Action Down Queue"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_WB_SUPPOSE_DEAD, "wbsupposedead", N_("Suppose Dead"), false, hotkey::SCOPE_GAME },
|
|
|
|
{ hotkey::HOTKEY_EDITOR_QUIT_TO_DESKTOP, "editor-quit-to-desktop", N_("Quit to Desktop"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_CLOSE_MAP, "editor-close-map", N_("Close Map"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_SWITCH_MAP, "editor-switch-map", N_("Switch Map"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_SETTINGS, "editor-settings", N_("Editor Settings"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_PARTIAL_UNDO, "editor-partial-undo", N_("Partial Undo"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_NEW, "editor-map-new", N_("New Map"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_LOAD, "editor-map-load", N_("Load Map"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_SAVE, "editor-map-save", N_("Save Map"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_SAVE_AS, "editor-map-save-as", N_("Save Map As"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_SAVE_ALL, "editor-map-save-all", N_("Save All Maps"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_REVERT, "editor-map-revert", N_("Revert All Changes"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_INFO, "editor-map-info", N_("Map Information"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_TERRAIN_PALETTE_SWAP, "editor-terrain-palette-swap",
|
|
N_("Swap Foreground/Background Terrains"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_TERRAIN_GROUPS, "editor-terrain-groups", N_("Change Terrain Group"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_TERRAIN_LEFTSCROLL, "editor-terrain-leftscroll", N_("Scroll Terrains Left"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_TERRAIN_RIGHTSCROLL, "editor-terrain-rightscroll", N_("Scroll Terrains Right"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_TOOL_NEXT, "editor-tool-next", N_("Next Tool"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_TOOL_PAINT, "editor-tool-paint", N_("Paint Tool"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_TOOL_FILL, "editor-tool-fill", N_("Fill Tool"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_TOOL_SELECT, "editor-tool-select", N_("Selection Tool"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_TOOL_STARTING_POSITION, "editor-tool-starting-position",
|
|
N_("Set Starting Positions Tool"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_TOOL_LABEL, "editor-tool-label",
|
|
N_("Place a map label Tool"), false, hotkey::SCOPE_EDITOR },
|
|
|
|
{ hotkey::HOTKEY_EDITOR_BRUSH_NEXT, "editor-brush-next", N_("Next Brush"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_BRUSH_DEFAULT, "editor-brush-default", N_("Default Brush"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_CUT, "editor-cut", N_("Cut"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_COPY, "editor-copy", N_("Copy"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_PASTE, "editor-paste", N_("Paste"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_EXPORT_SELECTION_COORDS, "editor-export-selection-coords", N_("Export Selected Coordinates to System Clipboard"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_SELECT_ALL, "editor-select-all",
|
|
N_("Select All"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_SELECT_INVERSE, "editor-select-inverse",
|
|
N_("Select Inverse"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_SELECT_NONE, "editor-select-none",
|
|
N_("Select None"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_CLIPBOARD_ROTATE_CW, "editor-clipboard-rotate-cw",
|
|
N_("Rotate Clipboard Clockwise"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_CLIPBOARD_ROTATE_CCW, "editor-clipboard-rotate-ccw",
|
|
N_("Rotate Clipboard Counter-Clockwise"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_CLIPBOARD_FLIP_HORIZONTAL, "editor-clipboard-flip-horizontal",
|
|
N_("Flip Clipboard Horizontally"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_CLIPBOARD_FLIP_VERTICAL, "editor-clipboard-flip-vertical",
|
|
N_("Flip Clipboard Vertically"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_SELECTION_ROTATE, "editor-selection-rotate",
|
|
N_("Rotate Selection"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_SELECTION_FLIP, "editor-selection-flip",
|
|
N_("Flip Selection"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_SELECTION_FILL, "editor-selection-fill",
|
|
N_("Fill Selection"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_SELECTION_GENERATE, "editor-selection-generate",
|
|
N_("Generate Tiles In Selection"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_SELECTION_RANDOMIZE, "editor-selection-randomize",
|
|
N_("Randomize Tiles In Selection"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_RESIZE, "editor-map-resize",
|
|
N_("Resize Map"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_ROTATE, "editor-map-rotate",
|
|
N_("Rotate Map"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_GENERATE, "editor-map-generate",
|
|
N_("Generate Map"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_APPLY_MASK, "editor-map-apply-mask",
|
|
N_("Apply a Mask"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_MAP_CREATE_MASK_TO, "editor-map-create-mask-to",
|
|
N_("Create Mask"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_REFRESH, "editor-refresh",
|
|
N_("Refresh Display"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_UPDATE_TRANSITIONS, "editor-update-transitions",
|
|
N_("Update Terrain Transitions"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_AUTO_UPDATE_TRANSITIONS, "editor-auto-update-transitions",
|
|
N_("Auto-update Terrain Transitions"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_REFRESH_IMAGE_CACHE, "editor-refresh-image-cache",
|
|
N_("Refresh Image Cache"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_DRAW_COORDINATES, "editor-draw-coordinates",
|
|
N_("Draw Hex Coordinates"), false, hotkey::SCOPE_EDITOR },
|
|
{ hotkey::HOTKEY_EDITOR_DRAW_TERRAIN_CODES, "editor-draw-terrain-codes",
|
|
N_("Draw Terrain Codes"), false, hotkey::SCOPE_EDITOR },
|
|
|
|
|
|
|
|
{ hotkey::HOTKEY_DELAY_SHROUD, "delayshroud", N_("Delay Shroud Updates"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_UPDATE_SHROUD, "updateshroud", N_("Update Shroud Now"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_CONTINUE_MOVE, "continue", N_("Continue Move"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_SEARCH, "search", N_("Find Label or Unit"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_SPEAK_ALLY, "speaktoally", N_("Speak to Ally"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_SPEAK_ALL, "speaktoall", N_("Speak to All"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_HELP, "help", N_("Help"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_CHAT_LOG, "chatlog", N_("View Chat Log"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_LANGUAGE, "changelanguage", N_("Change Language"), false, hotkey::SCOPE_GENERAL },
|
|
|
|
{ hotkey::HOTKEY_USER_CMD, "command", N_("Enter User Command"), false, hotkey::SCOPE_GENERAL },
|
|
{ hotkey::HOTKEY_CUSTOM_CMD, "customcommand", N_("Custom Command"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_AI_FORMULA, "aiformula", N_("Run Formula"), false, hotkey::SCOPE_GAME },
|
|
{ hotkey::HOTKEY_CLEAR_MSG, "clearmessages", N_("Clear Messages"), false, hotkey::SCOPE_GAME },
|
|
{
|
|
hotkey::TITLE_SCREEN__RELOAD_WML
|
|
, "title_screen__reload_wml"
|
|
, N_("Refresh WML")
|
|
, true
|
|
, hotkey::SCOPE_GENERAL
|
|
},
|
|
{
|
|
hotkey::TITLE_SCREEN__NEXT_TIP
|
|
, "title_screen__next_tip"
|
|
, N_("Next Tip of the Day")
|
|
, false
|
|
, hotkey::SCOPE_GENERAL
|
|
},
|
|
{
|
|
hotkey::TITLE_SCREEN__PREVIOUS_TIP
|
|
, "title_screen__previous_tip"
|
|
, N_("Previous Tip of the Day")
|
|
, false
|
|
, hotkey::SCOPE_GENERAL
|
|
},
|
|
{
|
|
hotkey::TITLE_SCREEN__TUTORIAL
|
|
, "title_screen__tutorial"
|
|
, N_("Start Tutorial")
|
|
, false
|
|
, hotkey::SCOPE_GENERAL
|
|
},
|
|
{
|
|
hotkey::TITLE_SCREEN__CAMPAIGN
|
|
, "title_screen__campaign"
|
|
, N_("Start Campaign")
|
|
, false
|
|
, hotkey::SCOPE_GENERAL
|
|
},
|
|
{
|
|
hotkey::TITLE_SCREEN__MULTIPLAYER
|
|
, "title_screen__multiplayer"
|
|
, N_("Start Multiplayer Game")
|
|
, false
|
|
, hotkey::SCOPE_GENERAL
|
|
},
|
|
{
|
|
hotkey::TITLE_SCREEN__ADDONS
|
|
, "title_screen__addons"
|
|
, N_("Manage Add-ons")
|
|
, false
|
|
, hotkey::SCOPE_GENERAL
|
|
},
|
|
{
|
|
hotkey::TITLE_SCREEN__EDITOR
|
|
, "title_screen__editor"
|
|
, N_("Start Editor")
|
|
, false
|
|
, hotkey::SCOPE_GENERAL
|
|
},
|
|
{
|
|
hotkey::TITLE_SCREEN__CREDITS
|
|
, "title_screen__credits"
|
|
, N_("Show Credits")
|
|
, false
|
|
, hotkey::SCOPE_GENERAL
|
|
},
|
|
|
|
{
|
|
hotkey::GLOBAL__HELPTIP
|
|
, "global__helptip"
|
|
, N_("Show Helptip")
|
|
, false
|
|
, hotkey::SCOPE_GENERAL
|
|
},
|
|
|
|
{ hotkey::HOTKEY_NULL, NULL, NULL, true, hotkey::SCOPE_GENERAL }
|
|
};
|
|
|
|
std::vector<hotkey::hotkey_item> hotkeys_;
|
|
hotkey::hotkey_item null_hotkey_;
|
|
|
|
config default_hotkeys_cfg_;
|
|
|
|
std::string hotkey_tag_name = "hotkey";
|
|
|
|
std::vector<bool> scope_active_(hotkey::SCOPE_COUNT, false);
|
|
}
|
|
|
|
namespace hotkey {
|
|
|
|
|
|
void deactivate_all_scopes()
|
|
{
|
|
for (int i = 0; i < hotkey::SCOPE_COUNT; ++i) {
|
|
scope_active_[i] = false;
|
|
}
|
|
}
|
|
|
|
void set_scope_active(scope s, bool set)
|
|
{
|
|
scope_active_[s] = set;
|
|
}
|
|
|
|
bool is_scope_active(scope s)
|
|
{
|
|
return scope_active_[s];
|
|
}
|
|
|
|
static void key_event_execute(display& disp, const SDL_KeyboardEvent& event, command_executor* executor);
|
|
static void button_event_execute(display& disp, const SDL_JoyButtonEvent& event, command_executor* executor);
|
|
static void hat_event_execute(display& disp, const SDL_JoyHatEvent& event, command_executor* executor);
|
|
|
|
const std::string CLEARED_TEXT = "__none__";
|
|
|
|
hotkey_item::hotkey_item(HOTKEY_COMMAND id,
|
|
const std::string& command, const t_string &description, bool hidden,
|
|
scope s) :
|
|
id_(id),
|
|
command_(command),
|
|
description_(description),
|
|
scope_(s),
|
|
type_(UNBOUND),
|
|
character_(0),
|
|
ctrl_(false),
|
|
alt_(false),
|
|
cmd_(false),
|
|
shift_(false),
|
|
keycode_(0),
|
|
button_(0),
|
|
joystick_(0),
|
|
hat_(0),
|
|
value_(0),
|
|
hidden_(hidden)
|
|
{
|
|
}
|
|
|
|
// There are two kinds of "key" values. One refers to actual keys, like
|
|
// F1 or SPACE. The other refers to characters produced, eg 'M' or ':'.
|
|
// For the latter, specifying shift+; doesn't make sense, because ; is
|
|
// already shifted on French keyboards, for example. You really want to
|
|
// say ':', however that is typed. However, when you say shift+SPACE,
|
|
// you're really referring to the space bar, as shift+SPACE usually just
|
|
// produces a SPACE character.
|
|
void hotkey_item::load_from_config(const config& cfg)
|
|
{
|
|
const std::string& button = cfg["button"];
|
|
if (!button.empty()) {
|
|
joystick_ = cfg["joystick"].to_int();
|
|
button_ = cfg["button"].to_int();
|
|
type_ = hotkey_item::BUTTON;
|
|
}
|
|
const std::string& hat = cfg["hat"];
|
|
if (!hat.empty()) {
|
|
joystick_ = cfg["joystick"].to_int();
|
|
hat_ = cfg["hat"].to_int();
|
|
value_ = cfg["value"].to_int();
|
|
type_ = hotkey_item::HAT;
|
|
}
|
|
|
|
const std::string& key = cfg["key"];
|
|
|
|
alt_ = cfg["alt"].to_bool();
|
|
cmd_ = cfg["cmd"].to_bool();
|
|
ctrl_ = cfg["ctrl"].to_bool();
|
|
shift_ = cfg["shift"].to_bool();
|
|
|
|
if (key.empty()) return;
|
|
|
|
if (key == CLEARED_TEXT)
|
|
{
|
|
type_ = hotkey_item::CLEARED;
|
|
return;
|
|
}
|
|
|
|
wide_string wkey = utils::string_to_wstring(key);
|
|
|
|
// They may really want a specific key on the keyboard: we assume
|
|
// that any single character keyname is a character.
|
|
if (wkey.size() > 1) {
|
|
type_ = BY_KEYCODE;
|
|
|
|
keycode_ = sdl_keysym_from_name(key);
|
|
if (keycode_ == SDLK_UNKNOWN) {
|
|
if (tolower(key[0]) != 'f') {
|
|
ERR_CF << "hotkey key '" << key << "' invalid\n";
|
|
} else {
|
|
int num = lexical_cast_default<int>(key.c_str() + 1);
|
|
keycode_ = num + SDLK_F1 - 1;
|
|
}
|
|
}
|
|
} else if (key == " " || shift_
|
|
#ifdef __APPLE__
|
|
|| alt_
|
|
#endif
|
|
) {
|
|
// Space must be treated as a key because shift-space
|
|
// isn't a different character from space, and control key
|
|
// makes it go weird. shift=yes should never be specified
|
|
// on single characters (eg. key=m, shift=yes would be
|
|
// key=M), but we don't want to break old preferences
|
|
// files.
|
|
type_ = BY_KEYCODE;
|
|
keycode_ = wkey[0];
|
|
} else {
|
|
type_ = BY_CHARACTER;
|
|
character_ = wkey[0];
|
|
}
|
|
}
|
|
|
|
std::string hotkey_item::get_name() const
|
|
{
|
|
std::stringstream str;
|
|
if (type_ == BY_CHARACTER) {
|
|
if (alt_)
|
|
str << "alt+";
|
|
if (cmd_)
|
|
str << "cmd+";
|
|
if (ctrl_)
|
|
str << "ctrl+";
|
|
str << static_cast<char>(character_);
|
|
} else if (type_ == BY_KEYCODE) {
|
|
if (alt_)
|
|
str << "alt+";
|
|
if (ctrl_)
|
|
str << "ctrl+";
|
|
if (shift_)
|
|
str << "shift+";
|
|
if (cmd_)
|
|
str << "cmd+";
|
|
str << SDL_GetKeyName(SDLKey(keycode_));
|
|
} else if (type_ == BUTTON) {
|
|
str << "Joy" << joystick_ << "Btn" << button_;
|
|
} else if (type_ == HAT) {
|
|
std::string direction;
|
|
switch (value_) {
|
|
case SDL_HAT_CENTERED:
|
|
direction = "Centered";
|
|
break;
|
|
case SDL_HAT_UP:
|
|
direction = "Up";
|
|
break;
|
|
case SDL_HAT_RIGHT:
|
|
direction = "Right";
|
|
break;
|
|
case SDL_HAT_DOWN:
|
|
direction = "Down";
|
|
break;
|
|
case SDL_HAT_LEFT:
|
|
direction = "Left";
|
|
break;
|
|
case SDL_HAT_RIGHTUP:
|
|
direction = "RightUp";
|
|
break;
|
|
case SDL_HAT_RIGHTDOWN:
|
|
direction = "RightDown";
|
|
break;
|
|
case SDL_HAT_LEFTUP:
|
|
direction = "LeftUp";
|
|
break;
|
|
case SDL_HAT_LEFTDOWN:
|
|
direction = "LeftDown";
|
|
break;
|
|
default:
|
|
direction = "Unknown";
|
|
}
|
|
str << "Joy" << joystick_ << "Hat" << hat_ << direction;
|
|
}
|
|
return str.str();
|
|
}
|
|
|
|
void hotkey_item::set_description(const t_string &description)
|
|
{
|
|
description_ = description;
|
|
}
|
|
void hotkey_item::clear_hotkey()
|
|
{
|
|
type_ = CLEARED;
|
|
}
|
|
|
|
void hotkey_item::set_button(int button, int joystick)
|
|
{
|
|
joystick_ = joystick;
|
|
button_ = button;
|
|
type_ = BUTTON;
|
|
}
|
|
|
|
void hotkey_item::set_hat(int joystick, int hat, int value)
|
|
{
|
|
joystick_ = joystick;
|
|
hat_ = hat;
|
|
value_ = value;
|
|
type_ = HAT;
|
|
}
|
|
|
|
void hotkey_item::set_key(int character, int keycode, bool shift, bool ctrl, bool alt, bool cmd)
|
|
{
|
|
LOG_G << "setting hotkey: char=" << lexical_cast<std::string>(character)
|
|
<< " keycode=" << lexical_cast<std::string>(keycode) << " "
|
|
<< (shift ? "shift," : "")
|
|
<< (ctrl ? "ctrl," : "")
|
|
<< (alt ? "alt," : "")
|
|
<< (cmd ? "cmd," : "")
|
|
<< "\n";
|
|
|
|
// Sometimes control modifies by -64, ie ^A == 1.
|
|
if (character < 64 && ctrl) {
|
|
if (shift)
|
|
character += 64;
|
|
else
|
|
character += 96;
|
|
LOG_G << "Mapped to character " << lexical_cast<std::string>(character) << "\n";
|
|
}
|
|
|
|
// For some reason on Mac OS, if cmd and shift are down, the character doesn't get upper-cased
|
|
if (cmd && character > 96 && character < 123 && shift)
|
|
character -= 32;
|
|
|
|
// We handle simple cases by character, others by the actual key.
|
|
if (isprint(character) && !isspace(character)) {
|
|
type_ = BY_CHARACTER;
|
|
character_ = character;
|
|
ctrl_ = ctrl;
|
|
alt_ = alt;
|
|
cmd_ = cmd;
|
|
LOG_G << "type = BY_CHARACTER\n";
|
|
} else {
|
|
type_ = BY_KEYCODE;
|
|
keycode_ = keycode;
|
|
shift_ = shift;
|
|
ctrl_ = ctrl;
|
|
alt_ = alt;
|
|
cmd_ = cmd;
|
|
LOG_G << "type = BY_KEYCODE\n";
|
|
}
|
|
}
|
|
|
|
manager::manager()
|
|
{
|
|
init();
|
|
}
|
|
|
|
void manager::init()
|
|
{
|
|
for (int i = 0; hotkey_list_[i].command; ++i) {
|
|
hotkeys_.push_back(hotkey_item(hotkey_list_[i].id, hotkey_list_[i].command,
|
|
"", hotkey_list_[i].hidden, hotkey_list_[i].scope));
|
|
}
|
|
}
|
|
|
|
void manager::wipe()
|
|
{
|
|
hotkeys_.clear();
|
|
}
|
|
|
|
manager::~manager()
|
|
{
|
|
wipe();
|
|
}
|
|
|
|
scope_changer::scope_changer(const config& cfg, const std::string& hotkey_tag)
|
|
: cfg_(cfg)
|
|
, prev_tag_name_(hotkey_tag_name)
|
|
, prev_scope_active_(scope_active_)
|
|
{
|
|
manager::wipe();
|
|
manager::init();
|
|
hotkey::load_descriptions();
|
|
load_hotkeys(cfg_);
|
|
set_hotkey_tag_name(hotkey_tag);
|
|
}
|
|
|
|
scope_changer::~scope_changer()
|
|
{
|
|
scope_active_.swap(prev_scope_active_);
|
|
manager::wipe();
|
|
manager::init();
|
|
hotkey::load_descriptions();
|
|
set_hotkey_tag_name(prev_tag_name_);
|
|
load_hotkeys(cfg_);
|
|
}
|
|
|
|
void load_descriptions()
|
|
{
|
|
for (size_t i = 0; hotkey_list_[i].command; ++i) {
|
|
if (i >= hotkeys_.size()) {
|
|
ERR_G << "Hotkey list too short: " << hotkeys_.size() << "\n";
|
|
}
|
|
hotkeys_[i].set_description(t_string(hotkey_list_[i].description, PACKAGE "-lib"));
|
|
}
|
|
}
|
|
|
|
void set_hotkey_tag_name(const std::string& name)
|
|
{
|
|
hotkey_tag_name = name;
|
|
}
|
|
|
|
void load_hotkeys(const config& cfg, bool set_as_default)
|
|
{
|
|
foreach (const config &hk, cfg.child_range(hotkey_tag_name))
|
|
{
|
|
hotkey_item& h = get_hotkey(hk["command"]);
|
|
if(h.get_id() != HOTKEY_NULL) {
|
|
h.load_from_config(hk);
|
|
}
|
|
}
|
|
|
|
if(set_as_default) {
|
|
default_hotkeys_cfg_ = cfg;
|
|
}
|
|
}
|
|
|
|
void reset_default_hotkeys()
|
|
{
|
|
foreach(hotkey_item& hi, hotkeys_) {
|
|
hi.clear_hotkey();
|
|
}
|
|
|
|
if(!default_hotkeys_cfg_.empty()) {
|
|
load_hotkeys(default_hotkeys_cfg_);
|
|
} else {
|
|
ERR_G << "no default hotkeys set yet; all hotkeys are now unassigned!\n";
|
|
}
|
|
}
|
|
|
|
void save_hotkeys(config& cfg)
|
|
{
|
|
cfg.clear_children(hotkey_tag_name);
|
|
|
|
for(std::vector<hotkey_item>::iterator i = hotkeys_.begin(); i != hotkeys_.end(); ++i) {
|
|
if (i->hidden() || i->get_type() == hotkey_item::UNBOUND || !i->is_in_active_scope())
|
|
continue;
|
|
|
|
config& item = cfg.add_child(hotkey_tag_name);
|
|
item["command"] = i->get_command();
|
|
if (i->get_type() == hotkey_item::CLEARED)
|
|
{
|
|
item["key"] = CLEARED_TEXT;
|
|
continue;
|
|
}
|
|
|
|
if (i->get_type() == hotkey_item::BUTTON)
|
|
{
|
|
item["joystick"] = i->get_joystick();
|
|
item["button"] = i->get_button();
|
|
}
|
|
|
|
if (i->get_type() == hotkey_item::HAT)
|
|
{
|
|
item["joystick"] = i->get_joystick();
|
|
item["hat"] = i->get_hat();
|
|
item["value"] = i->get_value();
|
|
}
|
|
|
|
if (i->get_type() == hotkey_item::BY_KEYCODE) {
|
|
item["key"] = SDL_GetKeyName(SDLKey(i->get_keycode()));
|
|
item["shift"] = i->get_shift();
|
|
} else if (i->get_type() == hotkey_item::BY_CHARACTER) {
|
|
item["key"] = utils::wchar_to_string(i->get_character());
|
|
}
|
|
item["alt"] = i->get_alt();
|
|
item["ctrl"] = i->get_ctrl();
|
|
item["cmd"] = i->get_cmd();
|
|
}
|
|
}
|
|
|
|
hotkey_item& get_hotkey(HOTKEY_COMMAND id)
|
|
{
|
|
std::vector<hotkey_item>::iterator itor;
|
|
|
|
for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
|
|
if (itor->get_id() == id)
|
|
break;
|
|
}
|
|
|
|
if (itor == hotkeys_.end())
|
|
return null_hotkey_;
|
|
|
|
return *itor;
|
|
}
|
|
|
|
hotkey_item& get_hotkey(const std::string& command)
|
|
{
|
|
std::vector<hotkey_item>::iterator itor;
|
|
|
|
for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
|
|
if (itor->get_command() == command)
|
|
break;
|
|
}
|
|
|
|
if (itor == hotkeys_.end())
|
|
return null_hotkey_;
|
|
|
|
return *itor;
|
|
}
|
|
|
|
HOTKEY_COMMAND get_hotkey_command(const std::string& command)
|
|
{
|
|
for (size_t i = 0; hotkey_list_[i].command; ++i) {
|
|
if (hotkey_list_[i].command == command)
|
|
return hotkey_list_[i].id;
|
|
}
|
|
|
|
return HOTKEY_NULL;
|
|
}
|
|
|
|
hotkey_item& get_hotkey(int joy_num, int button_num)
|
|
{
|
|
std::vector<hotkey_item>::iterator itor;
|
|
|
|
for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
|
|
if (joy_num == itor->get_joystick() && button_num == itor->get_button() && (itor->get_type() == hotkey_item::BUTTON) )
|
|
break;
|
|
}
|
|
if (itor == hotkeys_.end())
|
|
return null_hotkey_;
|
|
|
|
return *itor;
|
|
}
|
|
|
|
hotkey_item& get_hotkey(int joy_num, int hat_num, int hat_value)
|
|
{
|
|
std::vector<hotkey_item>::iterator itor;
|
|
|
|
for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
|
|
if (joy_num == itor->get_joystick() && hat_num == itor->get_hat()
|
|
&& hat_value == itor->get_value() && (itor->get_type() == hotkey_item::HAT) )
|
|
break;
|
|
}
|
|
if (itor == hotkeys_.end())
|
|
return null_hotkey_;
|
|
|
|
return *itor;
|
|
}
|
|
|
|
hotkey_item& get_hotkey(int character, int keycode, bool shift, bool ctrl,
|
|
bool alt, bool cmd)
|
|
{
|
|
std::vector<hotkey_item>::iterator itor;
|
|
|
|
DBG_G << "getting hotkey: char=" << lexical_cast<std::string>(character)
|
|
<< " keycode=" << lexical_cast<std::string>(keycode) << " "
|
|
<< (shift ? "shift," : "")
|
|
<< (ctrl ? "ctrl," : "")
|
|
<< (alt ? "alt," : "")
|
|
<< (cmd ? "cmd," : "")
|
|
<< "\n";
|
|
|
|
// Sometimes control modifies by -64, ie ^A == 1.
|
|
if (0 < character && character < 64 && ctrl) {
|
|
if (shift)
|
|
character += 64;
|
|
else
|
|
character += 96;
|
|
DBG_G << "Mapped to character " << lexical_cast<std::string>(character) << "\n";
|
|
}
|
|
|
|
// For some reason on Mac OS, if cmd and shift are down, the character doesn't get upper-cased
|
|
if (cmd && character > 96 && character < 123 && shift)
|
|
character -= 32;
|
|
|
|
for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
|
|
if (itor->get_type() == hotkey_item::BY_CHARACTER) {
|
|
if (character == itor->get_character()) {
|
|
if (ctrl == itor->get_ctrl()
|
|
&& alt == itor->get_alt()
|
|
&& cmd == itor->get_cmd()) {
|
|
if (itor->is_in_active_scope()) {
|
|
DBG_G << "Could match by character..." << "yes\n";
|
|
break;
|
|
} else {
|
|
DBG_G << "Could match by character..." << "yes, but scope is inactive\n";
|
|
}
|
|
}
|
|
DBG_G << "Could match by character..." << "but modifiers different\n";
|
|
}
|
|
} else if (itor->get_type() == hotkey_item::BY_KEYCODE) {
|
|
if (keycode == itor->get_keycode()) {
|
|
if (shift == itor->get_shift()
|
|
&& ctrl == itor->get_ctrl()
|
|
&& alt == itor->get_alt()
|
|
&& cmd == itor->get_cmd()) {
|
|
if (itor->is_in_active_scope()) {
|
|
DBG_G << "Could match by keycode..." << "yes\n";
|
|
break;
|
|
} else {
|
|
DBG_G << "Could match by keycode..." << "yes, but scope is inactive\n";
|
|
}
|
|
}
|
|
DBG_G << "Could match by keycode..." << "but modifiers different\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (itor == hotkeys_.end())
|
|
return null_hotkey_;
|
|
|
|
return *itor;
|
|
}
|
|
|
|
hotkey_item& get_hotkey(const SDL_JoyButtonEvent& event)
|
|
{
|
|
return get_hotkey(event.which, event.button);
|
|
}
|
|
|
|
hotkey_item& get_hotkey(const SDL_JoyHatEvent& event)
|
|
{
|
|
return get_hotkey(event.which, event.hat, event.value);
|
|
}
|
|
|
|
hotkey_item& get_hotkey(const SDL_KeyboardEvent& event)
|
|
{
|
|
return get_hotkey(event.keysym.unicode, event.keysym.sym,
|
|
(event.keysym.mod & KMOD_SHIFT) != 0,
|
|
(event.keysym.mod & KMOD_CTRL) != 0,
|
|
(event.keysym.mod & KMOD_ALT) != 0,
|
|
(event.keysym.mod & KMOD_LMETA) != 0
|
|
#ifdef __APPLE__
|
|
|| (event.keysym.mod & KMOD_RMETA) != 0
|
|
#endif
|
|
);
|
|
}
|
|
|
|
static void _get_visible_hotkey_itor(int index, std::vector<hotkey_item>::iterator& itor)
|
|
{
|
|
int counter = 0;
|
|
for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
|
|
if (itor->hidden() || !itor->is_in_active_scope())
|
|
continue;
|
|
|
|
if (index == counter)
|
|
break;
|
|
|
|
counter++;
|
|
}
|
|
}
|
|
|
|
hotkey_item& get_visible_hotkey(int index)
|
|
{
|
|
|
|
std::vector<hotkey_item>::iterator itor;
|
|
_get_visible_hotkey_itor(index, itor);
|
|
if (itor == hotkeys_.end())
|
|
return null_hotkey_;
|
|
|
|
return *itor;
|
|
}
|
|
|
|
std::vector<hotkey_item>& get_hotkeys()
|
|
{
|
|
return hotkeys_;
|
|
}
|
|
|
|
basic_handler::basic_handler(display* disp, command_executor* exec) : disp_(disp), exec_(exec) {}
|
|
|
|
void basic_handler::handle_event(const SDL_Event& event)
|
|
{
|
|
if(event.type == SDL_KEYDOWN && disp_ != NULL) {
|
|
|
|
//if we're in a dialog we only want to handle things that are explicitly handled
|
|
//by the executor. If we're not in a dialog we can call the regular key event handler
|
|
if(!gui::in_dialog()) {
|
|
key_event(*disp_,event.key,exec_);
|
|
} else if(exec_ != NULL) {
|
|
key_event_execute(*disp_,event.key,exec_);
|
|
}
|
|
}
|
|
if(event.type == SDL_JOYBUTTONDOWN && disp_ != NULL) {
|
|
button_event_execute(*disp_, event.jbutton, exec_);
|
|
}
|
|
}
|
|
|
|
void button_event(display& disp, const SDL_JoyButtonEvent& event, command_executor* executor)
|
|
{
|
|
button_event_execute(disp,event,executor);
|
|
}
|
|
|
|
void hat_event(display& disp, const SDL_JoyHatEvent& event, command_executor* executor)
|
|
{
|
|
hat_event_execute(disp,event,executor);
|
|
}
|
|
|
|
void key_event(display& disp, const SDL_KeyboardEvent& event, command_executor* executor)
|
|
{
|
|
if(event.keysym.sym == SDLK_ESCAPE && disp.in_game()) {
|
|
LOG_G << "escape pressed..showing quit\n";
|
|
const int res = gui2::show_message(disp.video(), _("Quit"), _("Do you really want to quit?"), gui2::tmessage::yes_no_buttons);
|
|
if(res != gui2::twindow::CANCEL) {
|
|
throw end_level_exception(QUIT);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
key_event_execute(disp,event,executor);
|
|
}
|
|
|
|
void button_event_execute(display& disp, const SDL_JoyButtonEvent& event, command_executor* executor)
|
|
{
|
|
const hotkey_item* hk = &get_hotkey(event);
|
|
|
|
#if 0
|
|
// This is not generally possible without knowing keyboard layout.
|
|
if(hk->null()) {
|
|
//no matching hotkey was found, but try an in-exact match.
|
|
hk = &get_hotkey(event, true);
|
|
}
|
|
#endif
|
|
|
|
if(hk->null())
|
|
return;
|
|
|
|
execute_command(disp,hk->get_id(),executor);
|
|
}
|
|
|
|
void hat_event_execute(display& disp, const SDL_JoyHatEvent& event, command_executor* executor)
|
|
{
|
|
const hotkey_item* hk = &get_hotkey(event);
|
|
|
|
#if 0
|
|
// This is not generally possible without knowing keyboard layout.
|
|
if(hk->null()) {
|
|
//no matching hotkey was found, but try an in-exact match.
|
|
hk = &get_hotkey(event, true);
|
|
}
|
|
#endif
|
|
|
|
if(hk->null())
|
|
return;
|
|
|
|
execute_command(disp,hk->get_id(),executor);
|
|
}
|
|
|
|
|
|
void key_event_execute(display& disp, const SDL_KeyboardEvent& event, command_executor* executor)
|
|
{
|
|
const hotkey_item* hk = &get_hotkey(event);
|
|
|
|
#if 0
|
|
// This is not generally possible without knowing keyboard layout.
|
|
if(hk->null()) {
|
|
//no matching hotkey was found, but try an in-exact match.
|
|
hk = &get_hotkey(event, true);
|
|
}
|
|
#endif
|
|
|
|
if(hk->null())
|
|
return;
|
|
|
|
execute_command(disp,hk->get_id(),executor);
|
|
}
|
|
|
|
bool command_executor::execute_command(HOTKEY_COMMAND command, int /*index*/)
|
|
{
|
|
switch(command) {
|
|
case HOTKEY_CYCLE_UNITS:
|
|
cycle_units();
|
|
break;
|
|
case HOTKEY_CYCLE_BACK_UNITS:
|
|
cycle_back_units();
|
|
break;
|
|
case HOTKEY_ENDTURN:
|
|
end_turn();
|
|
break;
|
|
case HOTKEY_UNIT_HOLD_POSITION:
|
|
unit_hold_position();
|
|
break;
|
|
case HOTKEY_END_UNIT_TURN:
|
|
end_unit_turn();
|
|
break;
|
|
case HOTKEY_LEADER:
|
|
goto_leader();
|
|
break;
|
|
case HOTKEY_UNDO:
|
|
undo();
|
|
break;
|
|
case HOTKEY_REDO:
|
|
redo();
|
|
break;
|
|
case HOTKEY_UNIT_DESCRIPTION:
|
|
unit_description();
|
|
break;
|
|
case HOTKEY_RENAME_UNIT:
|
|
rename_unit();
|
|
break;
|
|
case HOTKEY_SAVE_GAME:
|
|
save_game();
|
|
break;
|
|
case HOTKEY_SAVE_REPLAY:
|
|
save_replay();
|
|
break;
|
|
case HOTKEY_SAVE_MAP:
|
|
save_map();
|
|
break;
|
|
case HOTKEY_LOAD_GAME:
|
|
load_game();
|
|
break;
|
|
case HOTKEY_TOGGLE_ELLIPSES:
|
|
toggle_ellipses();
|
|
break;
|
|
case HOTKEY_TOGGLE_GRID:
|
|
toggle_grid();
|
|
break;
|
|
case HOTKEY_STATUS_TABLE:
|
|
status_table();
|
|
break;
|
|
case HOTKEY_RECALL:
|
|
recall();
|
|
break;
|
|
case HOTKEY_RECRUIT:
|
|
recruit();
|
|
break;
|
|
case hotkey::HOTKEY_REPEAT_RECRUIT:
|
|
repeat_recruit();
|
|
break;
|
|
case HOTKEY_SPEAK:
|
|
speak();
|
|
break;
|
|
case HOTKEY_SPEAK_ALLY:
|
|
whisper();
|
|
break;
|
|
case HOTKEY_SPEAK_ALL:
|
|
shout();
|
|
break;
|
|
case HOTKEY_CREATE_UNIT:
|
|
create_unit();
|
|
break;
|
|
case HOTKEY_CHANGE_SIDE:
|
|
change_side();
|
|
break;
|
|
case HOTKEY_PREFERENCES:
|
|
preferences();
|
|
break;
|
|
case HOTKEY_OBJECTIVES:
|
|
objectives();
|
|
break;
|
|
case HOTKEY_UNIT_LIST:
|
|
unit_list();
|
|
break;
|
|
case HOTKEY_STATISTICS:
|
|
show_statistics();
|
|
break;
|
|
case HOTKEY_STOP_NETWORK:
|
|
stop_network();
|
|
break;
|
|
case HOTKEY_START_NETWORK:
|
|
start_network();
|
|
break;
|
|
case HOTKEY_LABEL_TEAM_TERRAIN:
|
|
label_terrain(true);
|
|
break;
|
|
case HOTKEY_LABEL_TERRAIN:
|
|
label_terrain(false);
|
|
break;
|
|
case HOTKEY_CLEAR_LABELS:
|
|
clear_labels();
|
|
break;
|
|
case HOTKEY_SHOW_ENEMY_MOVES:
|
|
show_enemy_moves(false);
|
|
break;
|
|
case HOTKEY_BEST_ENEMY_MOVES:
|
|
show_enemy_moves(true);
|
|
break;
|
|
case HOTKEY_DELAY_SHROUD:
|
|
toggle_shroud_updates();
|
|
break;
|
|
case HOTKEY_UPDATE_SHROUD:
|
|
update_shroud_now();
|
|
break;
|
|
case HOTKEY_CONTINUE_MOVE:
|
|
continue_move();
|
|
break;
|
|
case HOTKEY_SEARCH:
|
|
search();
|
|
break;
|
|
case HOTKEY_HELP:
|
|
show_help();
|
|
break;
|
|
case HOTKEY_CHAT_LOG:
|
|
show_chat_log();
|
|
break;
|
|
case HOTKEY_USER_CMD:
|
|
user_command();
|
|
break;
|
|
case HOTKEY_CUSTOM_CMD:
|
|
custom_command();
|
|
break;
|
|
case HOTKEY_AI_FORMULA:
|
|
ai_formula();
|
|
break;
|
|
case HOTKEY_CLEAR_MSG:
|
|
clear_messages();
|
|
break;
|
|
case HOTKEY_LANGUAGE:
|
|
change_language();
|
|
break;
|
|
case HOTKEY_PLAY_REPLAY:
|
|
play_replay();
|
|
break;
|
|
case HOTKEY_RESET_REPLAY:
|
|
reset_replay();
|
|
break;
|
|
case HOTKEY_STOP_REPLAY:
|
|
stop_replay();
|
|
break;
|
|
case HOTKEY_REPLAY_NEXT_TURN:
|
|
replay_next_turn();
|
|
break;
|
|
case HOTKEY_REPLAY_NEXT_SIDE:
|
|
replay_next_side();
|
|
break;
|
|
case HOTKEY_REPLAY_SHOW_EVERYTHING:
|
|
replay_show_everything();
|
|
break;
|
|
case HOTKEY_REPLAY_SHOW_EACH:
|
|
replay_show_each();
|
|
break;
|
|
case HOTKEY_REPLAY_SHOW_TEAM1:
|
|
replay_show_team1();
|
|
break;
|
|
case HOTKEY_REPLAY_SKIP_ANIMATION:
|
|
replay_skip_animation();
|
|
break;
|
|
case HOTKEY_WB_TOGGLE:
|
|
whiteboard_toggle();
|
|
break;
|
|
case HOTKEY_WB_EXECUTE_ACTION:
|
|
whiteboard_execute_action();
|
|
break;
|
|
case HOTKEY_WB_EXECUTE_ALL_ACTIONS:
|
|
whiteboard_execute_all_actions();
|
|
break;
|
|
case HOTKEY_WB_DELETE_ACTION:
|
|
whiteboard_delete_action();
|
|
break;
|
|
case HOTKEY_WB_BUMP_UP_ACTION:
|
|
whiteboard_bump_up_action();
|
|
break;
|
|
case HOTKEY_WB_BUMP_DOWN_ACTION:
|
|
whiteboard_bump_down_action();
|
|
break;
|
|
case HOTKEY_WB_SUPPOSE_DEAD:
|
|
whiteboard_suppose_dead();
|
|
break;
|
|
case HOTKEY_LEFT_MOUSE_CLICK:
|
|
left_mouse_click();
|
|
break;
|
|
case HOTKEY_RIGHT_MOUSE_CLICK:
|
|
right_mouse_click();
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void execute_command(display& disp, HOTKEY_COMMAND command, command_executor* executor, int index)
|
|
{
|
|
const int zoom_amount = 4;
|
|
bool map_screenshot = false;
|
|
|
|
if(executor != NULL) {
|
|
if(!executor->can_execute_command(command, index) || executor->execute_command(command, index))
|
|
return;
|
|
}
|
|
switch(command) {
|
|
case HOTKEY_ZOOM_IN:
|
|
disp.set_zoom(zoom_amount);
|
|
break;
|
|
case HOTKEY_ZOOM_OUT:
|
|
disp.set_zoom(-zoom_amount);
|
|
break;
|
|
case HOTKEY_ZOOM_DEFAULT:
|
|
disp.set_default_zoom();
|
|
break;
|
|
case HOTKEY_FULLSCREEN:
|
|
preferences::set_fullscreen(!preferences::fullscreen());
|
|
break;
|
|
case HOTKEY_MAP_SCREENSHOT:
|
|
if (!disp.in_game() && !disp.in_editor())
|
|
break;
|
|
map_screenshot = true;
|
|
case HOTKEY_SCREENSHOT: {
|
|
std::string name = map_screenshot ? _("Map-Screenshot") : _("Screenshot");
|
|
std::string filename = get_screenshot_dir() + "/" + name + "_";
|
|
filename = get_next_filename(filename, ".bmp");
|
|
int size = disp.screenshot(filename, map_screenshot);
|
|
if (size > 0) {
|
|
std::stringstream res;
|
|
res << filename << " ( " << utils::si_string(size, true, _("unit_byte^B")) << " )";
|
|
gui2::show_message(disp.video(), _("Screenshot done"), res.str());
|
|
} else
|
|
gui2::show_message(disp.video(), _("Screenshot done"), "");
|
|
break;
|
|
}
|
|
case HOTKEY_ANIMATE_MAP:
|
|
preferences::set_animate_map(!preferences::animate_map());
|
|
break;
|
|
case HOTKEY_MOUSE_SCROLL:
|
|
preferences::enable_mouse_scroll(!preferences::mouse_scroll_enabled());
|
|
break;
|
|
case HOTKEY_ACCELERATED:
|
|
preferences::set_turbo(!preferences::turbo());
|
|
break;
|
|
case HOTKEY_MUTE:
|
|
{
|
|
// look if both is not playing
|
|
static struct before_muted_s
|
|
{
|
|
bool playing_sound,playing_music;
|
|
before_muted_s() : playing_sound(false),playing_music(false){}
|
|
} before_muted;
|
|
if (preferences::music_on() || preferences::sound_on())
|
|
{
|
|
//then remember settings and mute both
|
|
before_muted.playing_sound = preferences::sound_on();
|
|
before_muted.playing_music = preferences::music_on();
|
|
preferences::set_sound(false);
|
|
preferences::set_music(false);
|
|
}
|
|
else
|
|
{
|
|
//then set settings before mute
|
|
preferences::set_sound(before_muted.playing_sound);
|
|
preferences::set_music(before_muted.playing_music);
|
|
}
|
|
}
|
|
break;
|
|
case HOTKEY_QUIT_GAME: {
|
|
if(disp.in_game()) {
|
|
DBG_G << "is in game -- showing quit message\n";
|
|
const int res = gui2::show_message(disp.video(), _("Quit"), _("Do you really want to quit?"), gui2::tmessage::yes_no_buttons);
|
|
if(res != gui2::twindow::CANCEL) {
|
|
throw end_level_exception(QUIT);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
DBG_G << "command_executor: unknown command number " << command << ", ignoring.\n";
|
|
break;
|
|
}
|
|
}
|
|
|
|
void command_executor::show_menu(const std::vector<std::string>& items_arg, int xloc, int yloc, bool context_menu, display& gui)
|
|
{
|
|
std::vector<std::string> items = items_arg;
|
|
if (items.empty())
|
|
return;
|
|
if (can_execute_command(hotkey::get_hotkey(items.front()).get_id(), 0)){
|
|
//if just one item is passed in, that means we should execute that item
|
|
if(!context_menu && items.size() == 1 && items_arg.size() == 1) {
|
|
hotkey::execute_command(gui,hotkey::get_hotkey(items.front()).get_id(),this);
|
|
return;
|
|
}
|
|
|
|
std::vector<std::string> menu = get_menu_images(gui, items);
|
|
|
|
int res = 0;
|
|
{
|
|
gui::dialog mmenu = gui::dialog(gui,"","",
|
|
gui::MESSAGE, gui::dialog::hotkeys_style);
|
|
mmenu.set_menu(menu);
|
|
res = mmenu.show(xloc, yloc);
|
|
} // this will kill the dialog
|
|
if (res < 0 || size_t(res) >= items.size())
|
|
return;
|
|
|
|
const hotkey::HOTKEY_COMMAND cmd = hotkey::get_hotkey(items[res]).get_id();
|
|
hotkey::execute_command(gui,cmd,this,res);
|
|
}
|
|
}
|
|
|
|
std::string command_executor::get_menu_image(hotkey::HOTKEY_COMMAND command, int index) const {
|
|
switch(get_action_state(command, index)) {
|
|
case ACTION_ON: return game_config::images::checked_menu;
|
|
case ACTION_OFF: return game_config::images::unchecked_menu;
|
|
default: return get_action_image(command, index);
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> command_executor::get_menu_images(display &disp, const std::vector<std::string>& items){
|
|
std::vector<std::string> result;
|
|
bool has_image = false;
|
|
|
|
for(size_t i = 0; i < items.size(); ++i) {
|
|
std::string const& item = items[i];
|
|
const hotkey::hotkey_item hk = hotkey::get_hotkey(item);
|
|
|
|
std::stringstream str;
|
|
//see if this menu item has an associated image
|
|
std::string img(get_menu_image(hk.get_id(), i));
|
|
if(img.empty() == false) {
|
|
has_image = true;
|
|
str << IMAGE_PREFIX << img << COLUMN_SEPARATOR;
|
|
}
|
|
|
|
if (hk.get_id() == hotkey::HOTKEY_NULL) {
|
|
str << item.substr(0, item.find_last_not_of(' ') + 1) << COLUMN_SEPARATOR;
|
|
} else {
|
|
std::string desc = hk.get_description();
|
|
if (hk.get_id() == HOTKEY_ENDTURN) {
|
|
const theme::menu *b = disp.get_theme().get_menu_item("button-endturn");
|
|
if(b) {
|
|
desc = b->title();
|
|
}
|
|
}
|
|
str << desc << COLUMN_SEPARATOR << hk.get_name();
|
|
}
|
|
|
|
result.push_back(str.str());
|
|
}
|
|
//If any of the menu items have an image, create an image column
|
|
if(has_image)
|
|
for(std::vector<std::string>::iterator i = result.begin(); i != result.end(); ++i)
|
|
if(*(i->begin()) != IMAGE_PREFIX)
|
|
i->insert(i->begin(), COLUMN_SEPARATOR);
|
|
return result;
|
|
}
|
|
|
|
}
|