3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2013 Ciaran Gultnieks <ciaran@ciarang.com>
5 Copyright (C) 2013 teddydestodes <derkomtur@schattengang.net>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "guiKeyChangeMenu.h"
24 #include "guiButton.h"
25 #include "serialization.h"
27 #include <IGUICheckBox.h>
28 #include <IGUIEditBox.h>
29 #include <IGUIButton.h>
30 #include <IGUIStaticText.h>
35 #include "mainmenumanager.h" // for g_gamecallback
37 #define KMaxButtonPerColumns 12
39 extern MainGameCallback *g_gamecallback;
43 GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR,
45 GUI_ID_KEY_FORWARD_BUTTON,
46 GUI_ID_KEY_BACKWARD_BUTTON,
47 GUI_ID_KEY_LEFT_BUTTON,
48 GUI_ID_KEY_RIGHT_BUTTON,
49 GUI_ID_KEY_AUX1_BUTTON,
50 GUI_ID_KEY_FLY_BUTTON,
51 GUI_ID_KEY_FAST_BUTTON,
52 GUI_ID_KEY_JUMP_BUTTON,
53 GUI_ID_KEY_NOCLIP_BUTTON,
54 GUI_ID_KEY_PITCH_MOVE,
55 GUI_ID_KEY_CHAT_BUTTON,
56 GUI_ID_KEY_CMD_BUTTON,
57 GUI_ID_KEY_CMD_LOCAL_BUTTON,
58 GUI_ID_KEY_CONSOLE_BUTTON,
59 GUI_ID_KEY_SNEAK_BUTTON,
60 GUI_ID_KEY_DROP_BUTTON,
61 GUI_ID_KEY_INVENTORY_BUTTON,
62 GUI_ID_KEY_ENDERCHEST_BUTTON,
63 GUI_ID_KEY_HOTBAR_PREV_BUTTON,
64 GUI_ID_KEY_HOTBAR_NEXT_BUTTON,
65 GUI_ID_KEY_MUTE_BUTTON,
66 GUI_ID_KEY_DEC_VOLUME_BUTTON,
67 GUI_ID_KEY_INC_VOLUME_BUTTON,
68 GUI_ID_KEY_RANGE_BUTTON,
69 GUI_ID_KEY_ZOOM_BUTTON,
70 GUI_ID_KEY_CAMERA_BUTTON,
71 GUI_ID_KEY_MINIMAP_BUTTON,
72 GUI_ID_KEY_SCREENSHOT_BUTTON,
73 GUI_ID_KEY_CHATLOG_BUTTON,
74 GUI_ID_KEY_BLOCK_BOUNDS_BUTTON,
75 GUI_ID_KEY_HUD_BUTTON,
76 GUI_ID_KEY_FOG_BUTTON,
77 GUI_ID_KEY_CHEAT_MENU_BUTTON,
78 GUI_ID_KEY_DEC_RANGE_BUTTON,
79 GUI_ID_KEY_INC_RANGE_BUTTON,
80 GUI_ID_KEY_AUTOFWD_BUTTON,
81 GUI_ID_KEY_KILLAURA_BUTTON,
82 GUI_ID_KEY_FREECAM_BUTTON,
83 GUI_ID_KEY_SCAFFOLD_BUTTON,
84 GUI_ID_KEY_SELECT_UP_BUTTON,
85 GUI_ID_KEY_SELECT_DOWN_BUTTON,
86 GUI_ID_KEY_SELECT_LEFT_BUTTON,
87 GUI_ID_KEY_SELECT_RIGHT_BUTTON,
88 GUI_ID_KEY_SELECT_CONFIRM_BUTTON,
90 GUI_ID_CB_AUX1_DESCENDS,
91 GUI_ID_CB_DOUBLETAP_JUMP,
95 GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
96 gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
97 ISimpleTextureSource *tsrc) :
98 GUIModalMenu(env, parent, id, menumgr),
104 GUIKeyChangeMenu::~GUIKeyChangeMenu()
108 for (key_setting *ks : key_settings) {
109 delete[] ks->button_name;
112 key_settings.clear();
115 void GUIKeyChangeMenu::removeChildren()
117 const core::list<gui::IGUIElement*> &children = getChildren();
118 core::list<gui::IGUIElement*> children_copy;
119 for (gui::IGUIElement*i : children) {
120 children_copy.push_back(i);
123 for (gui::IGUIElement *i : children_copy) {
126 key_used_text = nullptr;
129 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
133 const float s = m_gui_scale;
134 DesiredRect = core::rect<s32>(
135 screensize.X / 2 - 1113 * s / 2,
136 screensize.Y / 2 - 430 * s / 2,
137 screensize.X / 2 + 1113 * s / 2,
138 screensize.Y / 2 + 430 * s / 2
140 recalculateAbsolutePosition(false);
142 v2s32 size = DesiredRect.getSize();
146 core::rect<s32> rect(0, 0, 600 * s, 40 * s);
147 rect += topleft + v2s32(25 * s, 3 * s);
148 //gui::IGUIStaticText *t =
149 const wchar_t *text = wgettext("Keybindings.");
150 Environment->addStaticText(text,
151 rect, false, true, this, -1);
153 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
158 v2s32 offset(25 * s, 60 * s);
160 for(size_t i = 0; i < key_settings.size(); i++)
162 key_setting *k = key_settings.at(i);
164 core::rect<s32> rect(0, 0, 150 * s, 20 * s);
165 rect += topleft + v2s32(offset.X, offset.Y);
166 Environment->addStaticText(k->button_name, rect, false, true, this, -1);
170 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
171 rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s);
172 const wchar_t *text = wgettext(k->key.name());
173 k->button = GUIButton::addButton(Environment, rect, m_tsrc, this, k->id, text);
176 if ((i + 1) % KMaxButtonPerColumns == 0) {
180 offset += v2s32(0, 25 * s);
185 s32 option_x = offset.X;
186 s32 option_y = offset.Y + 5 * s;
187 u32 option_w = 180 * s;
189 core::rect<s32> rect(0, 0, option_w, 30 * s);
190 rect += topleft + v2s32(option_x, option_y);
191 const wchar_t *text = wgettext("\"Aux1\" = climb down");
192 Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
193 GUI_ID_CB_AUX1_DESCENDS, text);
196 offset += v2s32(0, 25 * s);
200 s32 option_x = offset.X;
201 s32 option_y = offset.Y + 5 * s;
202 u32 option_w = 280 * s;
204 core::rect<s32> rect(0, 0, option_w, 30 * s);
205 rect += topleft + v2s32(option_x, option_y);
206 const wchar_t *text = wgettext("Double tap \"jump\" to toggle fly");
207 Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this,
208 GUI_ID_CB_DOUBLETAP_JUMP, text);
211 offset += v2s32(0, 25 * s);
215 s32 option_x = offset.X;
216 s32 option_y = offset.Y + 5 * s;
219 core::rect<s32> rect(0, 0, option_w, 30 * s);
220 rect += topleft + v2s32(option_x, option_y);
221 const wchar_t *text = wgettext("Automatic jumping");
222 Environment->addCheckBox(g_settings->getBool("autojump"), rect, this,
223 GUI_ID_CB_AUTOJUMP, text);
226 offset += v2s32(0, 25);
230 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
231 rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
232 const wchar_t *text = wgettext("Save");
233 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
237 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
238 rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
239 const wchar_t *text = wgettext("Cancel");
240 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
245 void GUIKeyChangeMenu::drawMenu()
247 gui::IGUISkin* skin = Environment->getSkin();
250 video::IVideoDriver* driver = Environment->getVideoDriver();
252 video::SColor bgcolor(140, 0, 0, 0);
253 driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
255 gui::IGUIElement::draw();
258 bool GUIKeyChangeMenu::acceptInput()
260 for (key_setting *k : key_settings) {
261 std::string default_key;
262 Settings::getLayer(SL_DEFAULTS)->getNoEx(k->setting_name, default_key);
264 if (k->key.sym() != default_key)
265 g_settings->set(k->setting_name, k->key.sym());
267 g_settings->remove(k->setting_name);
271 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
272 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
273 g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
276 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
277 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
278 g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
281 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP);
282 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
283 g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
288 g_gamecallback->signalKeyConfigChange();
293 bool GUIKeyChangeMenu::resetMenu()
296 const wchar_t *text = wgettext(active_key->key.name());
297 active_key->button->setText(text);
299 active_key = nullptr;
304 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
306 if (event.EventType == EET_KEY_INPUT_EVENT && active_key
307 && event.KeyInput.PressedDown) {
309 bool prefer_character = shift_down;
310 KeyPress kp(event.KeyInput, prefer_character);
312 if (event.KeyInput.Key == irr::KEY_DELETE)
313 kp = KeyPress(""); // To erase key settings
314 else if (event.KeyInput.Key == irr::KEY_ESCAPE)
315 kp = active_key->key; // Cancel
317 bool shift_went_down = false;
319 (event.KeyInput.Key == irr::KEY_SHIFT ||
320 event.KeyInput.Key == irr::KEY_LSHIFT ||
321 event.KeyInput.Key == irr::KEY_RSHIFT))
322 shift_went_down = true;
324 // Display Key already in use message
325 bool key_in_use = false;
326 if (strcmp(kp.sym(), "") != 0) {
327 for (key_setting *ks : key_settings) {
328 if (ks != active_key && ks->key == kp) {
335 if (key_in_use && !this->key_used_text) {
336 core::rect<s32> rect(0, 0, 600, 40);
337 rect += v2s32(0, 0) + v2s32(25, 30);
338 const wchar_t *text = wgettext("Key already in use");
339 this->key_used_text = Environment->addStaticText(text,
340 rect, false, true, this, -1);
342 } else if (!key_in_use && this->key_used_text) {
343 this->key_used_text->remove();
344 this->key_used_text = nullptr;
349 active_key->key = kp;
350 const wchar_t *text = wgettext(kp.name());
351 active_key->button->setText(text);
354 // Allow characters made with shift
355 if (shift_went_down){
360 active_key = nullptr;
363 } else if (event.EventType == EET_KEY_INPUT_EVENT && !active_key
364 && event.KeyInput.PressedDown
365 && event.KeyInput.Key == irr::KEY_ESCAPE) {
368 } else if (event.EventType == EET_GUI_EVENT) {
369 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
372 if (!canTakeFocus(event.GUIEvent.Element))
374 infostream << "GUIKeyChangeMenu: Not allowing focus change."
376 // Returning true disables focus change
380 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
382 switch (event.GUIEvent.Caller->getID())
384 case GUI_ID_BACK_BUTTON: //back
388 case GUI_ID_ABORT_BUTTON: //abort
393 for (key_setting *ks : key_settings) {
394 if (ks->id == event.GUIEvent.Caller->getID()) {
399 FATAL_ERROR_IF(!active_key, "Key setting not found");
402 const wchar_t *text = wgettext("press key");
403 active_key->button->setText(text);
407 Environment->setFocus(this);
410 return Parent ? Parent->OnEvent(event) : false;
413 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
415 key_setting *k = new key_setting;
418 k->button_name = button_name;
419 k->setting_name = setting_name;
420 k->key = getKeySetting(k->setting_name.c_str());
421 key_settings.push_back(k);
424 void GUIKeyChangeMenu::init_keys()
426 this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
427 this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
428 this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
429 this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
430 this->add_key(GUI_ID_KEY_AUX1_BUTTON, wgettext("Aux1"), "keymap_aux1");
431 this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
432 this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
433 this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
434 this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
435 this->add_key(GUI_ID_KEY_ENDERCHEST_BUTTON, wgettext("Enderchest"), "keymap_enderchest");
436 this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON, wgettext("Prev. item"), "keymap_hotbar_previous");
437 this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON, wgettext("Next item"), "keymap_hotbar_next");
438 this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
439 this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
440 this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
441 this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
442 this->add_key(GUI_ID_KEY_PITCH_MOVE, wgettext("Toggle pitchmove"), "keymap_pitchmove");
443 this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
444 this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
445 this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
446 this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON, wgettext("Dec. volume"), "keymap_decrease_volume");
447 this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON, wgettext("Inc. volume"), "keymap_increase_volume");
448 this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
449 this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
450 this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON, wgettext("Screenshot"), "keymap_screenshot");
451 this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
452 this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
453 this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
454 this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
455 this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
456 this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
457 this->add_key(GUI_ID_KEY_BLOCK_BOUNDS_BUTTON, wgettext("Block bounds"), "keymap_toggle_block_bounds");
458 this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
459 this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
460 this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");
461 this->add_key(GUI_ID_KEY_CHEAT_MENU_BUTTON, wgettext("Toggle C. Menu"), "keymap_toggle_cheat_menu");
462 this->add_key(GUI_ID_KEY_KILLAURA_BUTTON, wgettext("Killaura"), "keymap_toggle_killaura");
463 this->add_key(GUI_ID_KEY_FREECAM_BUTTON, wgettext("Freecam"), "keymap_toggle_freecam");
464 this->add_key(GUI_ID_KEY_SCAFFOLD_BUTTON, wgettext("Scaffold"), "keymap_toggle_scaffold");
465 this->add_key(GUI_ID_KEY_SELECT_UP_BUTTON, wgettext("C. Menu Up"), "keymap_select_up");
466 this->add_key(GUI_ID_KEY_SELECT_DOWN_BUTTON, wgettext("C. Menu Down"), "keymap_select_down");
467 this->add_key(GUI_ID_KEY_SELECT_LEFT_BUTTON, wgettext("C. Menu Left"), "keymap_select_left");
468 this->add_key(GUI_ID_KEY_SELECT_RIGHT_BUTTON, wgettext("C. Menu Right"), "keymap_select_right");
469 this->add_key(GUI_ID_KEY_SELECT_CONFIRM_BUTTON, wgettext("C. Menu Enter"), "keymap_select_confirm");