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()
107 key_used_text = nullptr;
109 for (key_setting *ks : key_settings) {
110 delete[] ks->button_name;
113 key_settings.clear();
116 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
119 key_used_text = nullptr;
121 const float s = m_gui_scale;
122 DesiredRect = core::rect<s32>(
123 screensize.X / 2 - 1113 * s / 2,
124 screensize.Y / 2 - 430 * s / 2,
125 screensize.X / 2 + 1113 * s / 2,
126 screensize.Y / 2 + 430 * s / 2
128 recalculateAbsolutePosition(false);
130 v2s32 size = DesiredRect.getSize();
134 core::rect<s32> rect(0, 0, 600 * s, 40 * s);
135 rect += topleft + v2s32(25 * s, 3 * s);
136 //gui::IGUIStaticText *t =
137 const wchar_t *text = wgettext("Keybindings.");
138 Environment->addStaticText(text,
139 rect, false, true, this, -1);
141 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
146 v2s32 offset(25 * s, 60 * s);
148 for(size_t i = 0; i < key_settings.size(); i++)
150 key_setting *k = key_settings.at(i);
152 core::rect<s32> rect(0, 0, 150 * s, 20 * s);
153 rect += topleft + v2s32(offset.X, offset.Y);
154 Environment->addStaticText(k->button_name, rect, false, true, this, -1);
158 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
159 rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s);
160 const wchar_t *text = wgettext(k->key.name());
161 k->button = GUIButton::addButton(Environment, rect, m_tsrc, this, k->id, text);
164 if ((i + 1) % KMaxButtonPerColumns == 0) {
168 offset += v2s32(0, 25 * s);
173 s32 option_x = offset.X;
174 s32 option_y = offset.Y + 5 * s;
175 u32 option_w = 180 * s;
177 core::rect<s32> rect(0, 0, option_w, 30 * s);
178 rect += topleft + v2s32(option_x, option_y);
179 const wchar_t *text = wgettext("\"Aux1\" = climb down");
180 Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
181 GUI_ID_CB_AUX1_DESCENDS, text);
184 offset += v2s32(0, 25 * s);
188 s32 option_x = offset.X;
189 s32 option_y = offset.Y + 5 * s;
190 u32 option_w = 280 * s;
192 core::rect<s32> rect(0, 0, option_w, 30 * s);
193 rect += topleft + v2s32(option_x, option_y);
194 const wchar_t *text = wgettext("Double tap \"jump\" to toggle fly");
195 Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this,
196 GUI_ID_CB_DOUBLETAP_JUMP, text);
199 offset += v2s32(0, 25 * s);
203 s32 option_x = offset.X;
204 s32 option_y = offset.Y + 5 * s;
207 core::rect<s32> rect(0, 0, option_w, 30 * s);
208 rect += topleft + v2s32(option_x, option_y);
209 const wchar_t *text = wgettext("Automatic jumping");
210 Environment->addCheckBox(g_settings->getBool("autojump"), rect, this,
211 GUI_ID_CB_AUTOJUMP, text);
214 offset += v2s32(0, 25);
218 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
219 rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
220 const wchar_t *text = wgettext("Save");
221 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
225 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
226 rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
227 const wchar_t *text = wgettext("Cancel");
228 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
233 void GUIKeyChangeMenu::drawMenu()
235 gui::IGUISkin* skin = Environment->getSkin();
238 video::IVideoDriver* driver = Environment->getVideoDriver();
240 video::SColor bgcolor(140, 0, 0, 0);
241 driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
243 gui::IGUIElement::draw();
246 bool GUIKeyChangeMenu::acceptInput()
248 for (key_setting *k : key_settings) {
249 std::string default_key;
250 Settings::getLayer(SL_DEFAULTS)->getNoEx(k->setting_name, default_key);
252 if (k->key.sym() != default_key)
253 g_settings->set(k->setting_name, k->key.sym());
255 g_settings->remove(k->setting_name);
259 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
260 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
261 g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
264 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
265 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
266 g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
269 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP);
270 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
271 g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
276 g_gamecallback->signalKeyConfigChange();
281 bool GUIKeyChangeMenu::resetMenu()
284 const wchar_t *text = wgettext(active_key->key.name());
285 active_key->button->setText(text);
287 active_key = nullptr;
292 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
294 if (event.EventType == EET_KEY_INPUT_EVENT && active_key
295 && event.KeyInput.PressedDown) {
297 bool prefer_character = shift_down;
298 KeyPress kp(event.KeyInput, prefer_character);
300 if (event.KeyInput.Key == irr::KEY_DELETE)
301 kp = KeyPress(""); // To erase key settings
302 else if (event.KeyInput.Key == irr::KEY_ESCAPE)
303 kp = active_key->key; // Cancel
305 bool shift_went_down = false;
307 (event.KeyInput.Key == irr::KEY_SHIFT ||
308 event.KeyInput.Key == irr::KEY_LSHIFT ||
309 event.KeyInput.Key == irr::KEY_RSHIFT))
310 shift_went_down = true;
312 // Display Key already in use message
313 bool key_in_use = false;
314 if (strcmp(kp.sym(), "") != 0) {
315 for (key_setting *ks : key_settings) {
316 if (ks != active_key && ks->key == kp) {
323 if (key_in_use && !this->key_used_text) {
324 core::rect<s32> rect(0, 0, 600, 40);
325 rect += v2s32(0, 0) + v2s32(25, 30);
326 const wchar_t *text = wgettext("Key already in use");
327 this->key_used_text = Environment->addStaticText(text,
328 rect, false, true, this, -1);
330 } else if (!key_in_use && this->key_used_text) {
331 this->key_used_text->remove();
332 this->key_used_text = nullptr;
337 active_key->key = kp;
338 const wchar_t *text = wgettext(kp.name());
339 active_key->button->setText(text);
342 // Allow characters made with shift
343 if (shift_went_down){
348 active_key = nullptr;
351 } else if (event.EventType == EET_KEY_INPUT_EVENT && !active_key
352 && event.KeyInput.PressedDown
353 && event.KeyInput.Key == irr::KEY_ESCAPE) {
356 } else if (event.EventType == EET_GUI_EVENT) {
357 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
360 if (!canTakeFocus(event.GUIEvent.Element))
362 infostream << "GUIKeyChangeMenu: Not allowing focus change."
364 // Returning true disables focus change
368 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
370 switch (event.GUIEvent.Caller->getID())
372 case GUI_ID_BACK_BUTTON: //back
376 case GUI_ID_ABORT_BUTTON: //abort
381 for (key_setting *ks : key_settings) {
382 if (ks->id == event.GUIEvent.Caller->getID()) {
387 FATAL_ERROR_IF(!active_key, "Key setting not found");
390 const wchar_t *text = wgettext("press key");
391 active_key->button->setText(text);
395 Environment->setFocus(this);
398 return Parent ? Parent->OnEvent(event) : false;
401 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
403 key_setting *k = new key_setting;
406 k->button_name = button_name;
407 k->setting_name = setting_name;
408 k->key = getKeySetting(k->setting_name.c_str());
409 key_settings.push_back(k);
412 void GUIKeyChangeMenu::init_keys()
414 this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
415 this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
416 this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
417 this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
418 this->add_key(GUI_ID_KEY_AUX1_BUTTON, wgettext("Aux1"), "keymap_aux1");
419 this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
420 this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
421 this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
422 this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
423 this->add_key(GUI_ID_KEY_ENDERCHEST_BUTTON, wgettext("Enderchest"), "keymap_enderchest");
424 this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON, wgettext("Prev. item"), "keymap_hotbar_previous");
425 this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON, wgettext("Next item"), "keymap_hotbar_next");
426 this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
427 this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
428 this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
429 this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
430 this->add_key(GUI_ID_KEY_PITCH_MOVE, wgettext("Toggle pitchmove"), "keymap_pitchmove");
431 this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
432 this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
433 this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
434 this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON, wgettext("Dec. volume"), "keymap_decrease_volume");
435 this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON, wgettext("Inc. volume"), "keymap_increase_volume");
436 this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
437 this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
438 this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON, wgettext("Screenshot"), "keymap_screenshot");
439 this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
440 this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
441 this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
442 this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
443 this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
444 this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
445 this->add_key(GUI_ID_KEY_BLOCK_BOUNDS_BUTTON, wgettext("Block bounds"), "keymap_toggle_block_bounds");
446 this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
447 this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
448 this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");
449 this->add_key(GUI_ID_KEY_CHEAT_MENU_BUTTON, wgettext("Toggle C. Menu"), "keymap_toggle_cheat_menu");
450 this->add_key(GUI_ID_KEY_KILLAURA_BUTTON, wgettext("Killaura"), "keymap_toggle_killaura");
451 this->add_key(GUI_ID_KEY_FREECAM_BUTTON, wgettext("Freecam"), "keymap_toggle_freecam");
452 this->add_key(GUI_ID_KEY_SCAFFOLD_BUTTON, wgettext("Scaffold"), "keymap_toggle_scaffold");
453 this->add_key(GUI_ID_KEY_SELECT_UP_BUTTON, wgettext("C. Menu Up"), "keymap_select_up");
454 this->add_key(GUI_ID_KEY_SELECT_DOWN_BUTTON, wgettext("C. Menu Down"), "keymap_select_down");
455 this->add_key(GUI_ID_KEY_SELECT_LEFT_BUTTON, wgettext("C. Menu Left"), "keymap_select_left");
456 this->add_key(GUI_ID_KEY_SELECT_RIGHT_BUTTON, wgettext("C. Menu Right"), "keymap_select_right");
457 this->add_key(GUI_ID_KEY_SELECT_CONFIRM_BUTTON, wgettext("C. Menu Enter"), "keymap_select_confirm");