New hotkey preferences dialog.
Have a look in the players_changelog for details.
This commit is contained in:
parent
b56df83d08
commit
36fc26b8fd
8 changed files with 633 additions and 236 deletions
|
@ -36,6 +36,7 @@ Version 1.11.0+svn:
|
|||
* Miscellaneous and bug fixes:
|
||||
* Fix invalid memory access crash resulting from deleting all saved games
|
||||
in the Load Game dialog
|
||||
* Redesigned the hotkey preferences dialog
|
||||
* Removed two Khalifate leftovers (Hakim portrait and KHALIFATE_NAMES macro)
|
||||
* Hex field size and default terrain are wml configurable
|
||||
* Fix OOS when dismissing a recall in a multiplayer campaign (bug #19924).
|
||||
|
|
|
@ -18,6 +18,15 @@ Version 1.11.0+svn:
|
|||
|
||||
* User interface:
|
||||
* Healing animations are now played when poison is cured.
|
||||
* Preferences
|
||||
* "Hotkey Settings" dialog redisigned.
|
||||
* Features a tab for each hotkey scope.
|
||||
* Truncates hotkey descriptions to keep the dialog functional,
|
||||
but shows their full description as help tooltips.
|
||||
* Allows reasigning hotkeys
|
||||
* Cancel button to discard any changes
|
||||
* Assigning of more than one hotkey per action possible
|
||||
* Support for assigning mouse buttons to actions
|
||||
* The recruit and recall commands are restored when right-clicking on a
|
||||
leader, but with new semantics -- only that leader's recruits/recalls will
|
||||
be presented as options.
|
||||
|
|
|
@ -735,6 +735,7 @@ set(wesnoth-main_SRC
|
|||
gui/dialogs/wml_message.cpp
|
||||
halo.cpp
|
||||
help.cpp
|
||||
hotkey_preferences_display.cpp
|
||||
intro.cpp
|
||||
leader_list.cpp
|
||||
map.cpp
|
||||
|
|
|
@ -491,6 +491,7 @@ wesnoth_sources = Split("""
|
|||
""")
|
||||
|
||||
wesnoth_sources.extend(client_env.Object("game_preferences_display.cpp", EXTRA_DEFINE = env["PLATFORM"] != "win32" and "WESNOTH_PREFIX='\"$prefix\"'" or None))
|
||||
wesnoth_sources.extend(client_env.Object("hotkey_preferences_display.cpp", EXTRA_DEFINE = env["PLATFORM"] != "win32" and "WESNOTH_PREFIX='\"$prefix\"'" or None))
|
||||
|
||||
libwesnoth_extras = client_env.Library("wesnoth_extras", wesnoth_sources)
|
||||
|
||||
|
|
|
@ -243,8 +243,7 @@ preferences_dialog::preferences_dialog(display& disp, const config& game_cfg)
|
|||
{
|
||||
sort_advanced_preferences();
|
||||
|
||||
// FIXME: this box should be vertically centered on the screen, but is not
|
||||
set_measurements(465, 400);
|
||||
set_measurements(preferences::width, preferences::height);
|
||||
|
||||
|
||||
sound_button_.set_check(sound_on());
|
||||
|
@ -748,7 +747,7 @@ void preferences_dialog::process_event()
|
|||
if (hide_whiteboard_button_.pressed())
|
||||
set_hide_whiteboard(hide_whiteboard_button_.checked());
|
||||
if (hotkeys_button_.pressed()) {
|
||||
show_hotkeys_dialog(disp_);
|
||||
show_hotkeys_preferences_dialog(disp_);
|
||||
parent->clear_buttons();
|
||||
}
|
||||
|
||||
|
|
614
src/hotkey_preferences_display.cpp
Normal file
614
src/hotkey_preferences_display.cpp
Normal file
|
@ -0,0 +1,614 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2012 by Fabian Mueler <fabianmueller5@gmx.de>
|
||||
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.
|
||||
*/
|
||||
|
||||
#define GETTEXT_DOMAIN "wesnoth-lib"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Manages the hotkey bindings.
|
||||
*/
|
||||
|
||||
#include "preferences_display.hpp"
|
||||
|
||||
#include "construct_dialog.hpp"
|
||||
#include "display.hpp"
|
||||
#include "formatter.hpp"
|
||||
#include "formula_string_utils.hpp"
|
||||
#include "game_preferences.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "gui/dialogs/message.hpp"
|
||||
#include "gui/dialogs/simple_item_selector.hpp"
|
||||
#include "gui/dialogs/transient_message.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "hotkeys.hpp"
|
||||
#include "log.hpp"
|
||||
#include "marked-up_text.hpp"
|
||||
#include "wml_separators.hpp"
|
||||
|
||||
#include <boost/assign/list_of.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
namespace preferences {
|
||||
|
||||
|
||||
class hotkey_preferences_parent_dialog: public gui::dialog {
|
||||
public:
|
||||
hotkey_preferences_parent_dialog(display &disp) :
|
||||
dialog(disp, _("Hotkey Settings"), "", gui::OK_CANCEL),
|
||||
clear_buttons_(false),
|
||||
hotkey_cfg_()
|
||||
{
|
||||
// keep the old config in case the user cancels the dialog
|
||||
hotkey::save_hotkeys(hotkey_cfg_);
|
||||
}
|
||||
|
||||
~hotkey_preferences_parent_dialog() {
|
||||
ERR_GUI_D << "resulte ist" << result() << "\n";
|
||||
// save or restore depending on the exit result
|
||||
if (result() >= 0)
|
||||
save_hotkeys();
|
||||
else hotkey::load_hotkeys(hotkey_cfg_, false);
|
||||
}
|
||||
|
||||
void action(gui::dialog_process_info &info) {
|
||||
if (clear_buttons_) {
|
||||
info.clear_buttons();
|
||||
clear_buttons_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_buttons() {
|
||||
clear_buttons_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool clear_buttons_;
|
||||
config hotkey_cfg_;
|
||||
|
||||
};
|
||||
|
||||
class hotkey_preferences_dialog: public gui::preview_pane {
|
||||
|
||||
private :
|
||||
/* nice little magic number, the size of the truncated hotkey command */
|
||||
static const int truncate_at = 25;
|
||||
|
||||
public:
|
||||
hotkey_preferences_dialog(display& disp);
|
||||
|
||||
private:
|
||||
|
||||
// overrides events::handler::process_event
|
||||
void process_event();
|
||||
|
||||
// overrides gui::widget::update_location
|
||||
void update_location(SDL_Rect const &rect);
|
||||
|
||||
// overrides gui::preview_pane::handler_members
|
||||
virtual handler_vector handler_members();
|
||||
|
||||
// implements gui::preview_pane::set_selection
|
||||
void set_selection(int index);
|
||||
|
||||
// implements gui::preview_pane::left_side
|
||||
bool left_side() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populates, sorts and redraws the hotkey menu
|
||||
* specified by tab_.
|
||||
* @keep_viewport feeds the keep_viewport param of menu::set_menu_items()
|
||||
*/
|
||||
void set_hotkey_menu(bool keep_viewport);
|
||||
|
||||
/* Subdialog, recognizing the hotkey sequence
|
||||
* @command add the result of the dialog to this item
|
||||
*/
|
||||
void show_binding_dialog(const std::string& command);
|
||||
|
||||
/*
|
||||
* Buttons to trigger the tools involved in hotkey assignment.
|
||||
* The buttons are shared by all scope tabs.
|
||||
*/
|
||||
gui::button add_button_, clear_button_, reset_button_;
|
||||
|
||||
/* The dialog features a tab for each hotkey scope (except the SCOPE_COUNTER)*/
|
||||
hotkey::scope tab_;
|
||||
|
||||
/* These are to map the menu selection to the corresponding command
|
||||
* example: std::string selected_general_command = general_commands_[general_hotkey_.get_selected()];
|
||||
*/
|
||||
std::vector<std::string> general_commands_;
|
||||
std::vector<std::string> game_commands_;
|
||||
std::vector<std::string> editor_commands_;
|
||||
|
||||
/* The header of all the scope menus */
|
||||
const std::string heading_;
|
||||
|
||||
/* Every scope gets its own menu and sorter to allow keeping the viewport
|
||||
* while switching through the tabs.
|
||||
*/
|
||||
int selected_command_;
|
||||
gui::menu::basic_sorter general_sorter_, game_sorter_, editor_sorter_;
|
||||
gui::menu general_hotkeys_, game_hotkeys_, editor_hotkeys_;
|
||||
|
||||
/* The display, for usage by child dialogs */
|
||||
display &disp_;
|
||||
|
||||
public:
|
||||
/*
|
||||
* TODO Okay, we have here a public member in a class.
|
||||
* Like in game_preferences_dialog.
|
||||
*/
|
||||
util::scoped_ptr<hotkey_preferences_parent_dialog> parent;
|
||||
};
|
||||
|
||||
void show_hotkeys_preferences_dialog(display& disp) {
|
||||
|
||||
std::vector<std::string> items;
|
||||
const std::string pre = IMAGE_PREFIX + std::string("icons/icon-");
|
||||
char const sep = COLUMN_SEPARATOR;
|
||||
|
||||
// tab names and icons
|
||||
items.push_back(pre + "general.png" + sep + sgettext("Prefs section^General"));
|
||||
items.push_back(pre + "game.png" + sep + sgettext("Prefs section^Game"));
|
||||
items.push_back(pre + "editor.png" + sep + sgettext("Prefs section^Editor"));
|
||||
|
||||
// determine the current scope, but not general
|
||||
int scope;
|
||||
for (scope = 1; scope != hotkey::SCOPE_COUNT; scope++)
|
||||
if (hotkey::is_scope_active((hotkey::scope)scope))
|
||||
break;
|
||||
|
||||
// The restorer will change the scope back to where we came from
|
||||
// when it runs out of the function's scope
|
||||
hotkey::scope_changer scope_restorer;
|
||||
hotkey_preferences_dialog dialog(disp);
|
||||
dialog.parent.assign(new hotkey_preferences_parent_dialog(disp));
|
||||
dialog.parent->set_menu(items);
|
||||
dialog.parent->add_pane(&dialog);
|
||||
// select the tab corresponding to the current scope.
|
||||
dialog.parent->get_menu().move_selection(scope);
|
||||
dialog.parent->show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/************ hotkey_preferences_dialog members ************************/
|
||||
hotkey_preferences_dialog::hotkey_preferences_dialog(display& disp) :
|
||||
gui::preview_pane(disp.video()),
|
||||
add_button_(disp.video(), _("Add Hotkey")),
|
||||
clear_button_(disp.video(), _("Clear Hotkey")),
|
||||
reset_button_(disp.video(), _("Reset All")),
|
||||
tab_(hotkey::SCOPE_GENERAL),
|
||||
general_commands_(),
|
||||
game_commands_(),
|
||||
editor_commands_(),
|
||||
heading_( (formatter() << HEADING_PREFIX << _("Action")
|
||||
<< COLUMN_SEPARATOR << _("Binding")).str()),
|
||||
selected_command_(0),
|
||||
general_sorter_(),
|
||||
game_sorter_(),
|
||||
editor_sorter_(),
|
||||
// Note: If you don't instantiate the menus with heading_,
|
||||
// the header can't be enabled later, seems to be a bug in gui::menu
|
||||
general_hotkeys_(disp.video(), boost::assign::list_of(heading_), false, -1, -1,
|
||||
&general_sorter_, &gui::menu::bluebg_style),
|
||||
game_hotkeys_(disp.video(), boost::assign::list_of(heading_), false, -1, -1,
|
||||
&game_sorter_, &gui::menu::bluebg_style),
|
||||
editor_hotkeys_(disp.video(), boost::assign::list_of(heading_), false, -1, -1,
|
||||
&editor_sorter_, &gui::menu::bluebg_style),
|
||||
disp_(disp),
|
||||
parent(NULL)
|
||||
{
|
||||
|
||||
set_measurements(preferences::width, preferences::height);
|
||||
|
||||
// Populate the command vectors, this needs to happen only once.
|
||||
const hotkey::hotkey_command* list = hotkey::get_hotkey_commands();
|
||||
for (size_t i = 0; list[i].id != hotkey::HOTKEY_NULL; ++i) {
|
||||
|
||||
if (list[i].hidden)
|
||||
continue;
|
||||
|
||||
switch (list[i].scope) {
|
||||
|
||||
case hotkey::SCOPE_GAME:
|
||||
game_commands_.push_back(list[i].command);
|
||||
break;
|
||||
case hotkey::SCOPE_EDITOR:
|
||||
editor_commands_.push_back(list[i].command);
|
||||
break;
|
||||
case hotkey::SCOPE_GENERAL:
|
||||
general_commands_.push_back(list[i].command);
|
||||
break;
|
||||
case hotkey::SCOPE_COUNT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO move to the caller?
|
||||
disp_.video().clear_all_help_strings();
|
||||
|
||||
// Add help tooltips to the buttons
|
||||
//TODO adjust them corresponding to the selected item
|
||||
clear_button_.set_help_string(_("Clears the selected actions's bindings"));
|
||||
add_button_.set_help_string(_("Add additional binding to the selected action"));
|
||||
reset_button_.set_help_string(_("Reset all bindings to the default values"));
|
||||
|
||||
// Initialize sorters.
|
||||
general_sorter_.set_alpha_sort(0).set_alpha_sort(1);
|
||||
game_sorter_.set_alpha_sort(0).set_alpha_sort(1);
|
||||
editor_sorter_.set_alpha_sort(0).set_alpha_sort(1);
|
||||
|
||||
// Populate every menu_
|
||||
for (int scope = 0; scope != hotkey::SCOPE_COUNT; scope++) {
|
||||
tab_ = hotkey::scope(scope);
|
||||
set_hotkey_menu(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void hotkey_preferences_dialog::set_hotkey_menu(bool keep_viewport) {
|
||||
|
||||
/*
|
||||
* First hide all elements of all tabs,
|
||||
* we might have redrawing glitches otherwise.
|
||||
*/
|
||||
add_button_.hide(true);
|
||||
reset_button_.hide(true);
|
||||
clear_button_.hide(true);
|
||||
game_hotkeys_.hide(true);
|
||||
editor_hotkeys_.hide(true);
|
||||
general_hotkeys_.hide(true);
|
||||
|
||||
// Helpers to keep the switch statement small.
|
||||
gui::menu* active_hotkeys = NULL;
|
||||
std::vector<std::string>* commands = NULL;
|
||||
|
||||
// Determine the menu corresponding to the selected tab.
|
||||
switch (tab_) {
|
||||
case hotkey::SCOPE_GAME:
|
||||
active_hotkeys = &game_hotkeys_;
|
||||
commands = &game_commands_;
|
||||
break;
|
||||
case hotkey::SCOPE_EDITOR:
|
||||
active_hotkeys = &editor_hotkeys_;
|
||||
commands = &editor_commands_;
|
||||
break;
|
||||
case hotkey::SCOPE_GENERAL:
|
||||
active_hotkeys = &general_hotkeys_;
|
||||
commands = &general_commands_;
|
||||
break;
|
||||
case hotkey::SCOPE_COUNT:
|
||||
assert(false); // should not happen.
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill the menu rows
|
||||
std::vector<std::string> menu_items;
|
||||
BOOST_FOREACH(const std::string& command, *commands) {
|
||||
|
||||
const std::string& description = hotkey::get_description(command);
|
||||
std::string truncated_description = description;
|
||||
if (truncated_description.size() >= (truncate_at + 2) )
|
||||
utils::ellipsis_truncate(truncated_description, truncate_at);
|
||||
const std::string& name = hotkey::get_names(hotkey::get_id(command));
|
||||
|
||||
menu_items.push_back(
|
||||
(formatter() << truncated_description << HELP_STRING_SEPARATOR << description << COLUMN_SEPARATOR
|
||||
<< font::NULL_MARKUP << name << HELP_STRING_SEPARATOR << name).str() );
|
||||
}
|
||||
// No effect if the vector is used in set_items instead of the menu's constructor.
|
||||
// menu_items.push_back(heading_);
|
||||
|
||||
// Re-populate the items.
|
||||
// workaround for set_items not keeping the selected item.
|
||||
selected_command_ = active_hotkeys->selection();
|
||||
active_hotkeys->set_items(menu_items, true, keep_viewport);
|
||||
// This shall happen only once at the start of the dialog.
|
||||
if (!keep_viewport) {
|
||||
active_hotkeys->sort_by(0);
|
||||
active_hotkeys->reset_selection();
|
||||
} else {
|
||||
active_hotkeys->move_selection_keeping_viewport(selected_command_);
|
||||
// !hide and thus redraw only the current tab_'s items
|
||||
active_hotkeys->hide(false);
|
||||
add_button_.hide(false);
|
||||
reset_button_.hide(false);
|
||||
clear_button_.hide(false);
|
||||
}
|
||||
}
|
||||
|
||||
handler_vector hotkey_preferences_dialog::handler_members() {
|
||||
handler_vector h;
|
||||
h.push_back(&add_button_);
|
||||
h.push_back(&clear_button_);
|
||||
h.push_back(&reset_button_);
|
||||
h.push_back(&general_hotkeys_);
|
||||
h.push_back(&game_hotkeys_);
|
||||
h.push_back(&editor_hotkeys_);
|
||||
return h;
|
||||
}
|
||||
|
||||
void hotkey_preferences_dialog::set_selection(int index) {
|
||||
|
||||
tab_ = hotkey::scope(index);
|
||||
|
||||
set_dirty();
|
||||
bg_restore();
|
||||
|
||||
hotkey::deactivate_all_scopes();
|
||||
switch (tab_) {
|
||||
case hotkey::SCOPE_GENERAL:
|
||||
hotkey::set_scope_active(hotkey::SCOPE_GENERAL);
|
||||
hotkey::set_scope_active(hotkey::SCOPE_GAME);
|
||||
hotkey::set_scope_active(hotkey::SCOPE_EDITOR);
|
||||
break;
|
||||
case hotkey::SCOPE_GAME:
|
||||
hotkey::set_scope_active(hotkey::SCOPE_GENERAL);
|
||||
hotkey::set_scope_active(hotkey::SCOPE_GAME);
|
||||
break;
|
||||
case hotkey::SCOPE_EDITOR:
|
||||
hotkey::set_scope_active(hotkey::SCOPE_GENERAL);
|
||||
hotkey::set_scope_active(hotkey::SCOPE_EDITOR);
|
||||
break;
|
||||
case hotkey::SCOPE_COUNT:
|
||||
break;
|
||||
}
|
||||
set_hotkey_menu(true);
|
||||
}
|
||||
|
||||
void hotkey_preferences_dialog::process_event() {
|
||||
|
||||
std::string id;
|
||||
gui::menu* active_menu_ = NULL;
|
||||
switch (tab_) {
|
||||
case hotkey::SCOPE_GAME:
|
||||
id = game_commands_[game_hotkeys_.selection()];
|
||||
active_menu_ = &game_hotkeys_;
|
||||
break;
|
||||
case hotkey::SCOPE_EDITOR:
|
||||
id = editor_commands_[editor_hotkeys_.selection()];
|
||||
active_menu_ = &editor_hotkeys_;
|
||||
break;
|
||||
case hotkey::SCOPE_GENERAL:
|
||||
id = general_commands_[general_hotkeys_.selection()];
|
||||
active_menu_ = &general_hotkeys_;
|
||||
break;
|
||||
case hotkey::SCOPE_COUNT:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( selected_command_ != active_menu_->selection()) {
|
||||
selected_command_ = active_menu_->selection();
|
||||
}
|
||||
|
||||
if (add_button_.pressed() || active_menu_->double_clicked()) {
|
||||
show_binding_dialog(id);
|
||||
}
|
||||
|
||||
if (clear_button_.pressed()) {
|
||||
// clear hotkey
|
||||
hotkey::clear_hotkeys(id);
|
||||
set_hotkey_menu(true);
|
||||
}
|
||||
|
||||
if (reset_button_.pressed()) {
|
||||
// reset all bindings to default
|
||||
const int res =
|
||||
gui2::show_message(disp_.video(), _("Reset Hotkeys"),
|
||||
_("This will reset all hotkeys to their default values. Do you wish to continue?"),
|
||||
gui2::tmessage::yes_no_buttons);
|
||||
|
||||
if (res != gui2::twindow::CANCEL) {
|
||||
clear_hotkeys();
|
||||
gui2::show_transient_message(disp_.video(), _("Hotkeys Reset"),
|
||||
_("All hotkeys have been reset to their default values."));
|
||||
set_hotkey_menu(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hotkey_preferences_dialog::update_location(SDL_Rect const &rect) {
|
||||
|
||||
bg_register(rect);
|
||||
|
||||
// some magic numbers :-P
|
||||
// TODO they match the ones in game_preferences_dialog.
|
||||
const int top_border = 10;
|
||||
const int right_border = font::relative_size(10);
|
||||
const int h = height() - 75; // well, this one not.
|
||||
const int w = rect.w - right_border;
|
||||
|
||||
int xpos = rect.x;
|
||||
int ypos = rect.y + top_border;
|
||||
|
||||
general_hotkeys_.set_location(xpos, ypos);
|
||||
general_hotkeys_.set_max_height(h);
|
||||
general_hotkeys_.set_height(h);
|
||||
general_hotkeys_.set_max_width(w);
|
||||
general_hotkeys_.set_width(w);
|
||||
|
||||
game_hotkeys_.set_location(xpos, ypos);
|
||||
game_hotkeys_.set_max_height(h);
|
||||
game_hotkeys_.set_height(h);
|
||||
game_hotkeys_.set_max_width(w);
|
||||
game_hotkeys_.set_width(w);
|
||||
|
||||
editor_hotkeys_.set_location(xpos, ypos);
|
||||
editor_hotkeys_.set_max_height(h);
|
||||
editor_hotkeys_.set_height(h);
|
||||
editor_hotkeys_.set_max_width(w);
|
||||
editor_hotkeys_.set_width(w);
|
||||
|
||||
ypos += h + font::relative_size(14);
|
||||
|
||||
add_button_.set_location(xpos, ypos);
|
||||
xpos += add_button_.width() + font::relative_size(14);
|
||||
reset_button_.set_location(xpos, ypos);
|
||||
xpos += reset_button_.width() + font::relative_size(14);
|
||||
clear_button_.set_location(xpos, ypos);
|
||||
}
|
||||
|
||||
void hotkey_preferences_dialog::show_binding_dialog(const std::string& id) {
|
||||
|
||||
// Lets change this hotkey......
|
||||
|
||||
SDL_Rect clip_rect = create_rect(0, 0, disp_.w(), disp_.h());
|
||||
SDL_Rect text_size = font::draw_text(NULL, clip_rect, font::SIZE_LARGE,
|
||||
font::NORMAL_COLOR, _("Press desired hotkey (Esc cancels)"), 0,
|
||||
0);
|
||||
|
||||
const int centerx = disp_.w() / 2;
|
||||
const int centery = disp_.h() / 2;
|
||||
|
||||
SDL_Rect dlgr = create_rect(centerx - text_size.w / 2 - 30,
|
||||
centery - text_size.h / 2 - 16, text_size.w + 60,
|
||||
text_size.h + 32);
|
||||
|
||||
surface_restorer restorer(&disp_.video(), dlgr);
|
||||
gui::dialog_frame mini_frame(disp_.video());
|
||||
mini_frame.layout(centerx - text_size.w / 2 - 20,
|
||||
centery - text_size.h / 2 - 6, text_size.w + 40,
|
||||
text_size.h + 12);
|
||||
mini_frame.draw_background();
|
||||
mini_frame.draw_border();
|
||||
font::draw_text(&disp_.video(), clip_rect, font::SIZE_LARGE,
|
||||
font::NORMAL_COLOR, _("Press desired hotkey (Esc cancels)"),
|
||||
centerx - text_size.w / 2, centery - text_size.h / 2);
|
||||
disp_.update_display();
|
||||
SDL_Event event;
|
||||
event.type = 0;
|
||||
int character = 0, keycode = 0, mod = 0; // Just to avoid warning
|
||||
int device = 0, button = 0, hat = 0, value = 0;
|
||||
const int any_mod = KMOD_CTRL | KMOD_ALT | KMOD_LMETA;
|
||||
|
||||
while (event.type != SDL_KEYDOWN && event.type != SDL_JOYBUTTONDOWN
|
||||
&& event.type != SDL_JOYHATMOTION
|
||||
&& (event.type != SDL_MOUSEBUTTONDOWN || event.button.button < 8))
|
||||
SDL_PollEvent(&event);
|
||||
|
||||
do {
|
||||
switch (event.type) {
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
keycode = event.key.keysym.sym;
|
||||
character = event.key.keysym.unicode;
|
||||
mod = event.key.keysym.mod;
|
||||
break;
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
device = event.jbutton.which;
|
||||
button = event.jbutton.button;
|
||||
break;
|
||||
case SDL_JOYHATMOTION:
|
||||
device = event.jhat.which;
|
||||
hat = event.jhat.hat;
|
||||
value = event.jhat.value;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
device = event.button.which;
|
||||
button = event.button.button;
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_PollEvent(&event);
|
||||
disp_.flip();
|
||||
disp_.delay(10);
|
||||
} while (event.type != SDL_KEYUP && event.type != SDL_JOYBUTTONUP
|
||||
&& event.type != SDL_JOYHATMOTION
|
||||
&& event.type != SDL_MOUSEBUTTONUP);
|
||||
|
||||
restorer.restore();
|
||||
disp_.update_display();
|
||||
|
||||
// only if not canceled.
|
||||
if (!(keycode == SDLK_ESCAPE && (mod & any_mod) == 0)) {
|
||||
|
||||
hotkey::hotkey_item newhk(id);
|
||||
hotkey::hotkey_item* oldhk = NULL;
|
||||
|
||||
Uint8 *keystate = SDL_GetKeyState(NULL);
|
||||
bool alt = keystate[SDLK_RALT] || keystate[SDLK_LALT];
|
||||
bool ctrl = keystate[SDLK_RCTRL] || keystate[SDLK_LCTRL];
|
||||
bool shift = keystate[SDLK_RSHIFT] || keystate[SDLK_LSHIFT];
|
||||
bool cmd = keystate[SDLK_RMETA] || keystate[SDLK_LMETA];
|
||||
|
||||
switch (event.type) {
|
||||
|
||||
case SDL_JOYHATMOTION:
|
||||
oldhk = &hotkey::get_hotkey(hotkey::hotkey_item::JHAT, device,
|
||||
hat, value, shift, ctrl, alt, cmd);
|
||||
newhk.set_jhat(device, hat, value, shift, ctrl, alt, cmd);
|
||||
break;
|
||||
case SDL_JOYBUTTONUP:
|
||||
oldhk = &hotkey::get_hotkey(hotkey::hotkey_item::JBUTTON,
|
||||
device, button, 0, shift, ctrl, alt, cmd);
|
||||
newhk.set_jbutton(device, button, shift, ctrl, alt, cmd);
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
oldhk = &hotkey::get_hotkey(hotkey::hotkey_item::MBUTTON,
|
||||
device, button, 0, shift, ctrl, alt, cmd);
|
||||
newhk.set_mbutton(device, button, shift, ctrl, alt, cmd);
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
oldhk =
|
||||
&hotkey::get_hotkey(character, keycode,
|
||||
(mod & KMOD_SHIFT)!= 0,
|
||||
(mod & KMOD_CTRL) != 0, (mod & KMOD_ALT) != 0, (mod & KMOD_LMETA) != 0);newhk.set_key(character, keycode, (mod & KMOD_SHIFT) != 0,
|
||||
(mod & KMOD_CTRL) != 0, (mod & KMOD_ALT) != 0, (mod & KMOD_LMETA) != 0);
|
||||
|
||||
if ( (newhk.get_id() == hotkey::HOTKEY_SCREENSHOT
|
||||
|| newhk.get_id() == hotkey::HOTKEY_MAP_SCREENSHOT)
|
||||
&& (mod & any_mod) == 0 ) {
|
||||
gui2::show_transient_message(disp_.video(), _("Warning"),
|
||||
_("Screenshot hotkeys should be combined with the Control, Alt or Meta modifiers to avoid problems."));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((oldhk && (!(oldhk->null())))) {
|
||||
if (oldhk->get_command() != id) {
|
||||
|
||||
utils::string_map symbols;
|
||||
symbols["hotkey_sequence"] = oldhk->get_name();
|
||||
symbols["old_hotkey_action"] = oldhk->get_description();
|
||||
symbols["new_hotkey_action"] = newhk.get_description();
|
||||
|
||||
std::string text =
|
||||
vgettext("\"$hotkey_sequence|\" is in use by \"$old_hotkey_action|\".\nDo you wish to reassign it to \"$new_hotkey_action|\"?",
|
||||
symbols);
|
||||
text += "\n\n";
|
||||
|
||||
const int res = gui2::show_message(disp_.video(),
|
||||
_("Hotkey is already in use."), text,
|
||||
gui2::tmessage::yes_no_buttons);
|
||||
if (res == gui2::twindow::OK) {
|
||||
oldhk->set_command(id);
|
||||
set_hotkey_menu(true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hotkey::add_hotkey(newhk);
|
||||
set_hotkey_menu(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // end namespace preferences
|
||||
|
|
@ -281,238 +281,6 @@ void repopulate_hotkeys_menu(std::vector<std::string>& menu_items,
|
|||
|
||||
} // end anonymous namespace
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable:4701)
|
||||
#endif
|
||||
void show_hotkeys_dialog(display & disp)
|
||||
{
|
||||
log_scope ("show_hotkeys_dialog");
|
||||
|
||||
const events::event_context dialog_events_context;
|
||||
|
||||
const int centerx = disp.w()/2;
|
||||
const int centery = disp.h()/2;
|
||||
const int width = 750;
|
||||
const int height = disp.video().gety() < 600 ? 380 : 500;
|
||||
const int xpos = centerx - width/2;
|
||||
const int ypos = centery - height/2;
|
||||
|
||||
gui::button close_button (disp.video(), _("Close"));
|
||||
std::vector<gui::button*> buttons;
|
||||
buttons.push_back(&close_button);
|
||||
|
||||
gui::dialog_frame f(disp.video(),_("Hotkey Settings"),gui::dialog_frame::default_style,true,&buttons);
|
||||
f.layout(xpos,ypos,width,height);
|
||||
f.draw();
|
||||
|
||||
SDL_Rect clip_rect = create_rect(0, 0, disp.w (), disp.h ());
|
||||
SDL_Rect text_size = font::draw_text(NULL, clip_rect, font::SIZE_LARGE,
|
||||
font::NORMAL_COLOR,_("Press desired hotkey (Esc cancels)"),
|
||||
0, 0);
|
||||
|
||||
gui::menu::basic_sorter sorter;
|
||||
sorter.set_alpha_sort(0).set_alpha_sort(1);
|
||||
|
||||
std::vector<std::string> menu_items;
|
||||
std::vector<std::string> item_commands;
|
||||
repopulate_hotkeys_menu(menu_items, item_commands);
|
||||
|
||||
gui::menu menu_(disp.video(), menu_items, false, height - font::relative_size(10), -1, &sorter, &gui::menu::bluebg_style);
|
||||
menu_.sort_by(0);
|
||||
menu_.reset_selection();
|
||||
menu_.set_width(font::relative_size(550));
|
||||
menu_.set_location(xpos + font::relative_size(10), ypos + font::relative_size(10));
|
||||
|
||||
gui::button change_button(disp.video(), _("Add Hotkey"));
|
||||
change_button.set_location(xpos + width - change_button.width () - font::relative_size(30), ypos + font::relative_size(30));
|
||||
|
||||
gui::button clear_button(disp.video(), _("Clear Hotkey"));
|
||||
clear_button.set_location(xpos + width - clear_button.width () - font::relative_size(30), ypos + font::relative_size(60));
|
||||
|
||||
gui::button reset_button(disp.video(), _("Reset All"));
|
||||
reset_button.set_location(xpos + width - reset_button.width() - font::relative_size(30), ypos + font::relative_size(90));
|
||||
|
||||
escape_handler esc_hand;
|
||||
|
||||
for(;;) {
|
||||
|
||||
if (close_button.pressed() || esc_hand.escape_pressed())
|
||||
{
|
||||
save_hotkeys();
|
||||
break;
|
||||
}
|
||||
|
||||
bool repopulate = false;
|
||||
const int selected = menu_.selection();
|
||||
const std::string id = item_commands[selected];
|
||||
if (change_button.pressed () || menu_.double_clicked()) {
|
||||
// Lets change this hotkey......
|
||||
SDL_Rect dlgr = create_rect(centerx - text_size.w / 2 - 30
|
||||
, centery - text_size.h / 2 - 16
|
||||
, text_size.w + 60
|
||||
, text_size.h + 32);
|
||||
|
||||
surface_restorer restorer(&disp.video(),dlgr);
|
||||
gui::dialog_frame mini_frame(disp.video());
|
||||
mini_frame.layout(centerx-text_size.w/2 - 20,
|
||||
centery-text_size.h/2 - 6,
|
||||
text_size.w+40,
|
||||
text_size.h+12);
|
||||
mini_frame.draw_background();
|
||||
mini_frame.draw_border();
|
||||
font::draw_text (&disp.video(), clip_rect, font::SIZE_LARGE,font::NORMAL_COLOR,
|
||||
_("Press desired hotkey (Esc cancels)"),centerx-text_size.w/2,
|
||||
centery-text_size.h/2);
|
||||
disp.update_display();
|
||||
SDL_Event event;
|
||||
event.type = 0;
|
||||
int character = 0, keycode = 0, mod = 0; // Just to avoid warning
|
||||
int device = 0, button = 0, hat = 0, value = 0;
|
||||
const int any_mod = KMOD_CTRL | KMOD_ALT | KMOD_LMETA;
|
||||
|
||||
while (event.type!=SDL_KEYDOWN
|
||||
&& event.type!=SDL_JOYBUTTONDOWN && event.type!= SDL_JOYHATMOTION
|
||||
&& (event.type!=SDL_MOUSEBUTTONDOWN || event.button.button < 8) )
|
||||
SDL_PollEvent(&event);
|
||||
|
||||
do {
|
||||
switch (event.type) {
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
keycode=event.key.keysym.sym;
|
||||
character=event.key.keysym.unicode;
|
||||
mod=event.key.keysym.mod;
|
||||
break;
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
device = event.jbutton.which;
|
||||
button = event.jbutton.button;
|
||||
break;
|
||||
case SDL_JOYHATMOTION:
|
||||
device = event.jhat.which;
|
||||
hat = event.jhat.hat;
|
||||
value = event.jhat.value;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
device = event.button.which;
|
||||
button = event.button.button;
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_PollEvent(&event);
|
||||
disp.flip();
|
||||
disp.delay(10);
|
||||
} while (event.type!=SDL_KEYUP
|
||||
&& event.type!=SDL_JOYBUTTONUP && event.type!=SDL_JOYHATMOTION
|
||||
&& event.type!=SDL_MOUSEBUTTONUP);
|
||||
|
||||
restorer.restore();
|
||||
disp.update_display();
|
||||
|
||||
// only if not canceled.
|
||||
if (!(keycode == SDLK_ESCAPE && (mod & any_mod) == 0)) {
|
||||
|
||||
hotkey::hotkey_item newhk(id);
|
||||
hotkey::hotkey_item* oldhk = NULL;
|
||||
|
||||
Uint8 *keystate = SDL_GetKeyState(NULL);
|
||||
bool alt = keystate[SDLK_RALT] || keystate[SDLK_LALT];
|
||||
bool ctrl = keystate[SDLK_RCTRL] || keystate[SDLK_LCTRL];
|
||||
bool shift = keystate[SDLK_RSHIFT] || keystate[SDLK_LSHIFT];
|
||||
bool cmd = keystate[SDLK_RMETA] || keystate[SDLK_LMETA];
|
||||
|
||||
switch (event.type) {
|
||||
|
||||
case SDL_JOYHATMOTION:
|
||||
oldhk = &hotkey::get_hotkey(hotkey::hotkey_item::JHAT, device, hat, value, shift, ctrl, alt, cmd);
|
||||
newhk.set_jhat(device, hat, value, shift, ctrl, alt, cmd);
|
||||
break;
|
||||
case SDL_JOYBUTTONUP:
|
||||
oldhk = &hotkey::get_hotkey(hotkey::hotkey_item::JBUTTON, device, button, 0, shift, ctrl, alt, cmd);
|
||||
newhk.set_jbutton(device, button, shift, ctrl, alt, cmd);
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
oldhk = &hotkey::get_hotkey(hotkey::hotkey_item::MBUTTON, device, button, 0, shift, ctrl, alt, cmd);
|
||||
newhk.set_mbutton(device, button, shift, ctrl, alt, cmd);
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
oldhk = &hotkey::get_hotkey(character, keycode, (mod & KMOD_SHIFT) != 0,
|
||||
(mod & KMOD_CTRL) != 0, (mod & KMOD_ALT) != 0, (mod & KMOD_LMETA) != 0);
|
||||
newhk.set_key(character, keycode, (mod & KMOD_SHIFT) != 0,
|
||||
(mod & KMOD_CTRL) != 0, (mod & KMOD_ALT) != 0, (mod & KMOD_LMETA) != 0);
|
||||
|
||||
if ( (newhk.get_id() == hotkey::HOTKEY_SCREENSHOT
|
||||
|| newhk.get_id() == hotkey::HOTKEY_MAP_SCREENSHOT)
|
||||
&& (mod & any_mod) == 0 ) {
|
||||
gui2::show_transient_message(disp.video(), _("Warning"),
|
||||
_("Screenshot hotkeys should be combined with the Control, Alt or Meta modifiers to avoid problems."));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((oldhk && (!(oldhk->null())) )) {
|
||||
if (oldhk->get_command() != id) {
|
||||
|
||||
utils::string_map symbols;
|
||||
symbols["hotkey_sequence"] = oldhk->get_name();
|
||||
symbols["old_hotkey_action"] = oldhk->get_description();
|
||||
symbols["new_hotkey_action"] = newhk.get_description();
|
||||
|
||||
std::string text = vgettext("\"$hotkey_sequence|\" is in use by \"$old_hotkey_action|\".\nDo you wish to reassign it to \"$new_hotkey_action|\"?"
|
||||
, symbols);
|
||||
text += "\n\n";
|
||||
|
||||
const int res = gui2::show_message(disp.video(), _("Hotkey is already in use.")
|
||||
, text, gui2::tmessage::yes_no_buttons);
|
||||
if(res == gui2::twindow::OK) {
|
||||
oldhk->set_command(id);
|
||||
repopulate = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hotkey::add_hotkey(newhk);
|
||||
repopulate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clear_button.pressed()) {
|
||||
// clear hotkey
|
||||
hotkey::clear_hotkeys(id);
|
||||
repopulate = true;
|
||||
}
|
||||
|
||||
if (reset_button.pressed()) {
|
||||
const int res = gui2::show_message(
|
||||
disp.video(), _("Reset Hotkeys"),
|
||||
_("This will reset all hotkeys to their default values. Do you wish to continue?"), gui2::tmessage::yes_no_buttons);
|
||||
|
||||
if(res != gui2::twindow::CANCEL) {
|
||||
clear_hotkeys();
|
||||
repopulate = true;
|
||||
gui2::show_transient_message(disp.video(), _("Hotkeys Reset"), _("All hotkeys have been reset to their default values."));
|
||||
}
|
||||
}
|
||||
|
||||
if (repopulate) {
|
||||
repopulate_hotkeys_menu(menu_items, item_commands);
|
||||
menu_.set_items(menu_items,true,true);
|
||||
menu_.move_selection_keeping_viewport(selected);
|
||||
}
|
||||
|
||||
menu_.process();
|
||||
|
||||
events::pump();
|
||||
events::raise_process_event();
|
||||
events::raise_draw_event();
|
||||
|
||||
disp.update_display();
|
||||
disp.delay(10);
|
||||
}
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
bool compare_resolutions(const std::pair<int,int>& lhs, const std::pair<int,int>& rhs)
|
||||
{
|
||||
|
|
|
@ -24,6 +24,10 @@ class display;
|
|||
|
||||
namespace preferences {
|
||||
|
||||
// FIXME: this box should be vertically centered on the screen, but is not
|
||||
static const int height = 400;
|
||||
static const int width = 465;
|
||||
|
||||
struct display_manager
|
||||
{
|
||||
display_manager(display* disp);
|
||||
|
@ -77,7 +81,7 @@ namespace preferences {
|
|||
|
||||
// If prefs is non-null, save the hotkeys in that config
|
||||
// instead of the default.
|
||||
void show_hotkeys_dialog(display & disp);
|
||||
void show_hotkeys_preferences_dialog(display & disp);
|
||||
} // end namespace preferences
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue