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_USE_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_HUD_BUTTON,
75 GUI_ID_KEY_FOG_BUTTON,
76 GUI_ID_KEY_CHEAT_MENU_BUTTON,
77 GUI_ID_KEY_DEC_RANGE_BUTTON,
78 GUI_ID_KEY_INC_RANGE_BUTTON,
79 GUI_ID_KEY_AUTOFWD_BUTTON,
80 GUI_ID_KEY_KILLAURA_BUTTON,
81 GUI_ID_KEY_FREECAM_BUTTON,
82 GUI_ID_KEY_SCAFFOLD_BUTTON,
83 GUI_ID_KEY_SELECT_UP_BUTTON,
84 GUI_ID_KEY_SELECT_DOWN_BUTTON,
85 GUI_ID_KEY_SELECT_LEFT_BUTTON,
86 GUI_ID_KEY_SELECT_RIGHT_BUTTON,
87 GUI_ID_KEY_SELECT_CONFIRM_BUTTON,
89 GUI_ID_CB_AUX1_DESCENDS,
90 GUI_ID_CB_DOUBLETAP_JUMP,
94 GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
95 gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
96 ISimpleTextureSource *tsrc) :
97 GUIModalMenu(env, parent, id, menumgr),
103 GUIKeyChangeMenu::~GUIKeyChangeMenu()
107 for (key_setting *ks : key_settings) {
108 delete[] ks->button_name;
111 key_settings.clear();
114 void GUIKeyChangeMenu::removeChildren()
116 const core::list<gui::IGUIElement*> &children = getChildren();
117 core::list<gui::IGUIElement*> children_copy;
118 for (gui::IGUIElement*i : children) {
119 children_copy.push_back(i);
122 for (gui::IGUIElement *i : children_copy) {
125 key_used_text = nullptr;
128 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
132 const float s = m_gui_scale;
133 DesiredRect = core::rect<s32>(
134 screensize.X / 2 - 1113 * s / 2,
135 screensize.Y / 2 - 430 * s / 2,
136 screensize.X / 2 + 1113 * s / 2,
137 screensize.Y / 2 + 430 * s / 2
139 recalculateAbsolutePosition(false);
141 v2s32 size = DesiredRect.getSize();
145 core::rect<s32> rect(0, 0, 600 * s, 40 * s);
146 rect += topleft + v2s32(25 * s, 3 * s);
147 //gui::IGUIStaticText *t =
148 const wchar_t *text = wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)");
149 Environment->addStaticText(text,
150 rect, false, true, this, -1);
152 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
157 v2s32 offset(25 * s, 60 * s);
159 for(size_t i = 0; i < key_settings.size(); i++)
161 key_setting *k = key_settings.at(i);
163 core::rect<s32> rect(0, 0, 150 * s, 20 * s);
164 rect += topleft + v2s32(offset.X, offset.Y);
165 Environment->addStaticText(k->button_name, rect, false, true, this, -1);
169 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
170 rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s);
171 const wchar_t *text = wgettext(k->key.name());
172 k->button = GUIButton::addButton(Environment, rect, m_tsrc, this, k->id, text);
175 if ((i + 1) % KMaxButtonPerColumns == 0) {
179 offset += v2s32(0, 25 * s);
184 s32 option_x = offset.X;
185 s32 option_y = offset.Y + 5 * s;
186 u32 option_w = 180 * s;
188 core::rect<s32> rect(0, 0, option_w, 30 * s);
189 rect += topleft + v2s32(option_x, option_y);
190 const wchar_t *text = wgettext("\"Special\" = climb down");
191 Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
192 GUI_ID_CB_AUX1_DESCENDS, text);
195 offset += v2s32(0, 25 * s);
199 s32 option_x = offset.X;
200 s32 option_y = offset.Y + 5 * s;
201 u32 option_w = 280 * s;
203 core::rect<s32> rect(0, 0, option_w, 30 * s);
204 rect += topleft + v2s32(option_x, option_y);
205 const wchar_t *text = wgettext("Double tap \"jump\" to toggle fly");
206 Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this,
207 GUI_ID_CB_DOUBLETAP_JUMP, text);
210 offset += v2s32(0, 25 * s);
214 s32 option_x = offset.X;
215 s32 option_y = offset.Y + 5 * s;
218 core::rect<s32> rect(0, 0, option_w, 30 * s);
219 rect += topleft + v2s32(option_x, option_y);
220 const wchar_t *text = wgettext("Automatic jumping");
221 Environment->addCheckBox(g_settings->getBool("autojump"), rect, this,
222 GUI_ID_CB_AUTOJUMP, text);
225 offset += v2s32(0, 25);
229 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
230 rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
231 const wchar_t *text = wgettext("Save");
232 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
236 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
237 rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
238 const wchar_t *text = wgettext("Cancel");
239 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
244 void GUIKeyChangeMenu::drawMenu()
246 gui::IGUISkin* skin = Environment->getSkin();
249 video::IVideoDriver* driver = Environment->getVideoDriver();
251 video::SColor bgcolor(140, 0, 0, 0);
252 driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
254 gui::IGUIElement::draw();
257 bool GUIKeyChangeMenu::acceptInput()
259 for (key_setting *k : key_settings) {
260 std::string default_key;
261 g_settings->getDefaultNoEx(k->setting_name, default_key);
263 if (k->key.sym() != default_key)
264 g_settings->set(k->setting_name, k->key.sym());
266 g_settings->remove(k->setting_name);
270 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
271 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
272 g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
275 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
276 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
277 g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
280 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP);
281 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
282 g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
287 g_gamecallback->signalKeyConfigChange();
292 bool GUIKeyChangeMenu::resetMenu()
295 const wchar_t *text = wgettext(active_key->key.name());
296 active_key->button->setText(text);
298 active_key = nullptr;
303 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
305 if (event.EventType == EET_KEY_INPUT_EVENT && active_key
306 && event.KeyInput.PressedDown) {
308 bool prefer_character = shift_down;
309 KeyPress kp(event.KeyInput, prefer_character);
311 if (event.KeyInput.Key == irr::KEY_DELETE)
312 kp = KeyPress(""); // To erase key settings
313 else if (event.KeyInput.Key == irr::KEY_ESCAPE)
314 kp = active_key->key; // Cancel
316 bool shift_went_down = false;
318 (event.KeyInput.Key == irr::KEY_SHIFT ||
319 event.KeyInput.Key == irr::KEY_LSHIFT ||
320 event.KeyInput.Key == irr::KEY_RSHIFT))
321 shift_went_down = true;
323 // Display Key already in use message
324 bool key_in_use = false;
325 if (strcmp(kp.sym(), "") != 0) {
326 for (key_setting *ks : key_settings) {
327 if (ks != active_key && ks->key == kp) {
334 if (key_in_use && !this->key_used_text) {
335 core::rect<s32> rect(0, 0, 600, 40);
336 rect += v2s32(0, 0) + v2s32(25, 30);
337 const wchar_t *text = wgettext("Key already in use");
338 this->key_used_text = Environment->addStaticText(text,
339 rect, false, true, this, -1);
341 } else if (!key_in_use && this->key_used_text) {
342 this->key_used_text->remove();
343 this->key_used_text = nullptr;
348 active_key->key = kp;
349 const wchar_t *text = wgettext(kp.name());
350 active_key->button->setText(text);
353 // Allow characters made with shift
354 if (shift_went_down){
359 active_key = nullptr;
362 } else if (event.EventType == EET_KEY_INPUT_EVENT && !active_key
363 && event.KeyInput.PressedDown
364 && event.KeyInput.Key == irr::KEY_ESCAPE) {
367 } else if (event.EventType == EET_GUI_EVENT) {
368 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
371 if (!canTakeFocus(event.GUIEvent.Element))
373 infostream << "GUIKeyChangeMenu: Not allowing focus change."
375 // Returning true disables focus change
379 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
381 switch (event.GUIEvent.Caller->getID())
383 case GUI_ID_BACK_BUTTON: //back
387 case GUI_ID_ABORT_BUTTON: //abort
392 for (key_setting *ks : key_settings) {
393 if (ks->id == event.GUIEvent.Caller->getID()) {
398 FATAL_ERROR_IF(!active_key, "Key setting not found");
401 const wchar_t *text = wgettext("press key");
402 active_key->button->setText(text);
406 Environment->setFocus(this);
409 return Parent ? Parent->OnEvent(event) : false;
412 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
414 key_setting *k = new key_setting;
417 k->button_name = button_name;
418 k->setting_name = setting_name;
419 k->key = getKeySetting(k->setting_name.c_str());
420 key_settings.push_back(k);
423 void GUIKeyChangeMenu::init_keys()
425 this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
426 this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
427 this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
428 this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
429 this->add_key(GUI_ID_KEY_USE_BUTTON, wgettext("Special"), "keymap_special1");
430 this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
431 this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
432 this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
433 this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
434 this->add_key(GUI_ID_KEY_ENDERCHEST_BUTTON,wgettext("Enderchest"), "keymap_enderchest");
435 this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,wgettext("Prev. item"), "keymap_hotbar_previous");
436 this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,wgettext("Next item"), "keymap_hotbar_next");
437 this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
438 this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
439 this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
440 this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
441 this->add_key(GUI_ID_KEY_PITCH_MOVE, wgettext("Toggle pitchmove"), "keymap_pitchmove");
442 this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
443 this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
444 this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
445 this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON,wgettext("Dec. volume"), "keymap_decrease_volume");
446 this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON,wgettext("Inc. volume"), "keymap_increase_volume");
447 this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
448 this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
449 this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON,wgettext("Screenshot"), "keymap_screenshot");
450 this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
451 this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
452 this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
453 this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
454 this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
455 this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
456 this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
457 this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
458 this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");
459 this->add_key(GUI_ID_KEY_CHEAT_MENU_BUTTON,wgettext("Toggle C. Menu"),"keymap_toggle_cheat_menu");
460 this->add_key(GUI_ID_KEY_KILLAURA_BUTTON, wgettext("Killaura"), "keymap_toggle_killaura");
461 this->add_key(GUI_ID_KEY_FREECAM_BUTTON, wgettext("Freecam"), "keymap_toggle_freecam");
462 this->add_key(GUI_ID_KEY_SCAFFOLD_BUTTON, wgettext("Scaffold"), "keymap_toggle_scaffold");
463 this->add_key(GUI_ID_KEY_SELECT_UP_BUTTON, wgettext("C. Menu Up"), "keymap_select_up");
464 this->add_key(GUI_ID_KEY_SELECT_DOWN_BUTTON,wgettext("C. Menu Down"), "keymap_select_down");
465 this->add_key(GUI_ID_KEY_SELECT_LEFT_BUTTON,wgettext("C. Menu Left"), "keymap_select_left");
466 this->add_key(GUI_ID_KEY_SELECT_RIGHT_BUTTON,wgettext("C. Menu Right"),"keymap_select_right");
467 this->add_key(GUI_ID_KEY_SELECT_CONFIRM_BUTTON,wgettext("C. Menu Enter"),"keymap_select_confirm");