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_SPECIAL_INVENTORY_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_SELECT_UP_BUTTON,
83 GUI_ID_KEY_SELECT_DOWN_BUTTON,
84 GUI_ID_KEY_SELECT_LEFT_BUTTON,
85 GUI_ID_KEY_SELECT_RIGHT_BUTTON,
86 GUI_ID_KEY_SELECT_CONFIRM_BUTTON,
88 GUI_ID_CB_AUX1_DESCENDS,
89 GUI_ID_CB_DOUBLETAP_JUMP,
93 GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
94 gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
95 ISimpleTextureSource *tsrc) :
96 GUIModalMenu(env, parent, id, menumgr),
102 GUIKeyChangeMenu::~GUIKeyChangeMenu()
106 for (key_setting *ks : key_settings) {
107 delete[] ks->button_name;
110 key_settings.clear();
113 void GUIKeyChangeMenu::removeChildren()
115 const core::list<gui::IGUIElement*> &children = getChildren();
116 core::list<gui::IGUIElement*> children_copy;
117 for (gui::IGUIElement*i : children) {
118 children_copy.push_back(i);
121 for (gui::IGUIElement *i : children_copy) {
124 key_used_text = nullptr;
127 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
131 const float s = m_gui_scale;
132 DesiredRect = core::rect<s32>(
133 screensize.X / 2 - 1113 * s / 2,
134 screensize.Y / 2 - 430 * s / 2,
135 screensize.X / 2 + 1113 * s / 2,
136 screensize.Y / 2 + 430 * s / 2
138 recalculateAbsolutePosition(false);
140 v2s32 size = DesiredRect.getSize();
144 core::rect<s32> rect(0, 0, 600 * s, 40 * s);
145 rect += topleft + v2s32(25 * s, 3 * s);
146 //gui::IGUIStaticText *t =
147 const wchar_t *text = wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)");
148 Environment->addStaticText(text,
149 rect, false, true, this, -1);
151 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
156 v2s32 offset(25 * s, 60 * s);
158 for(size_t i = 0; i < key_settings.size(); i++)
160 key_setting *k = key_settings.at(i);
162 core::rect<s32> rect(0, 0, 150 * s, 20 * s);
163 rect += topleft + v2s32(offset.X, offset.Y);
164 Environment->addStaticText(k->button_name, rect, false, true, this, -1);
168 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
169 rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s);
170 const wchar_t *text = wgettext(k->key.name());
171 k->button = GUIButton::addButton(Environment, rect, m_tsrc, this, k->id, text);
174 if ((i + 1) % KMaxButtonPerColumns == 0) {
178 offset += v2s32(0, 25 * s);
183 s32 option_x = offset.X;
184 s32 option_y = offset.Y + 5 * s;
185 u32 option_w = 180 * s;
187 core::rect<s32> rect(0, 0, option_w, 30 * s);
188 rect += topleft + v2s32(option_x, option_y);
189 const wchar_t *text = wgettext("\"Special\" = climb down");
190 Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
191 GUI_ID_CB_AUX1_DESCENDS, text);
194 offset += v2s32(0, 25 * s);
198 s32 option_x = offset.X;
199 s32 option_y = offset.Y + 5 * s;
200 u32 option_w = 280 * s;
202 core::rect<s32> rect(0, 0, option_w, 30 * s);
203 rect += topleft + v2s32(option_x, option_y);
204 const wchar_t *text = wgettext("Double tap \"jump\" to toggle fly");
205 Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this,
206 GUI_ID_CB_DOUBLETAP_JUMP, text);
209 offset += v2s32(0, 25 * s);
213 s32 option_x = offset.X;
214 s32 option_y = offset.Y + 5 * s;
217 core::rect<s32> rect(0, 0, option_w, 30 * s);
218 rect += topleft + v2s32(option_x, option_y);
219 const wchar_t *text = wgettext("Automatic jumping");
220 Environment->addCheckBox(g_settings->getBool("autojump"), rect, this,
221 GUI_ID_CB_AUTOJUMP, text);
224 offset += v2s32(0, 25);
228 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
229 rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
230 const wchar_t *text = wgettext("Save");
231 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
235 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
236 rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
237 const wchar_t *text = wgettext("Cancel");
238 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
243 void GUIKeyChangeMenu::drawMenu()
245 gui::IGUISkin* skin = Environment->getSkin();
248 video::IVideoDriver* driver = Environment->getVideoDriver();
250 video::SColor bgcolor(140, 0, 0, 0);
251 driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
253 gui::IGUIElement::draw();
256 bool GUIKeyChangeMenu::acceptInput()
258 for (key_setting *k : key_settings) {
259 std::string default_key;
260 g_settings->getDefaultNoEx(k->setting_name, default_key);
262 if (k->key.sym() != default_key)
263 g_settings->set(k->setting_name, k->key.sym());
265 g_settings->remove(k->setting_name);
269 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
270 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
271 g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
274 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
275 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
276 g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
279 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP);
280 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
281 g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
286 g_gamecallback->signalKeyConfigChange();
291 bool GUIKeyChangeMenu::resetMenu()
294 const wchar_t *text = wgettext(active_key->key.name());
295 active_key->button->setText(text);
297 active_key = nullptr;
302 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
304 if (event.EventType == EET_KEY_INPUT_EVENT && active_key
305 && event.KeyInput.PressedDown) {
307 bool prefer_character = shift_down;
308 KeyPress kp(event.KeyInput, prefer_character);
310 if (event.KeyInput.Key == irr::KEY_DELETE)
311 kp = KeyPress(""); // To erase key settings
312 else if (event.KeyInput.Key == irr::KEY_ESCAPE)
313 kp = active_key->key; // Cancel
315 bool shift_went_down = false;
317 (event.KeyInput.Key == irr::KEY_SHIFT ||
318 event.KeyInput.Key == irr::KEY_LSHIFT ||
319 event.KeyInput.Key == irr::KEY_RSHIFT))
320 shift_went_down = true;
322 // Display Key already in use message
323 bool key_in_use = false;
324 if (strcmp(kp.sym(), "") != 0) {
325 for (key_setting *ks : key_settings) {
326 if (ks != active_key && ks->key == kp) {
333 if (key_in_use && !this->key_used_text) {
334 core::rect<s32> rect(0, 0, 600, 40);
335 rect += v2s32(0, 0) + v2s32(25, 30);
336 const wchar_t *text = wgettext("Key already in use");
337 this->key_used_text = Environment->addStaticText(text,
338 rect, false, true, this, -1);
340 } else if (!key_in_use && this->key_used_text) {
341 this->key_used_text->remove();
342 this->key_used_text = nullptr;
347 active_key->key = kp;
348 const wchar_t *text = wgettext(kp.name());
349 active_key->button->setText(text);
352 // Allow characters made with shift
353 if (shift_went_down){
358 active_key = nullptr;
361 } else if (event.EventType == EET_KEY_INPUT_EVENT && !active_key
362 && event.KeyInput.PressedDown
363 && event.KeyInput.Key == irr::KEY_ESCAPE) {
366 } else if (event.EventType == EET_GUI_EVENT) {
367 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
370 if (!canTakeFocus(event.GUIEvent.Element))
372 infostream << "GUIKeyChangeMenu: Not allowing focus change."
374 // Returning true disables focus change
378 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
380 switch (event.GUIEvent.Caller->getID())
382 case GUI_ID_BACK_BUTTON: //back
386 case GUI_ID_ABORT_BUTTON: //abort
391 for (key_setting *ks : key_settings) {
392 if (ks->id == event.GUIEvent.Caller->getID()) {
397 FATAL_ERROR_IF(!active_key, "Key setting not found");
400 const wchar_t *text = wgettext("press key");
401 active_key->button->setText(text);
405 Environment->setFocus(this);
408 return Parent ? Parent->OnEvent(event) : false;
411 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
413 key_setting *k = new key_setting;
416 k->button_name = button_name;
417 k->setting_name = setting_name;
418 k->key = getKeySetting(k->setting_name.c_str());
419 key_settings.push_back(k);
422 void GUIKeyChangeMenu::init_keys()
424 this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
425 this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
426 this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
427 this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
428 this->add_key(GUI_ID_KEY_USE_BUTTON, wgettext("Special"), "keymap_special1");
429 this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
430 this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
431 this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
432 this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
433 this->add_key(GUI_ID_KEY_SPECIAL_INVENTORY_BUTTON,wgettext("Special Inv."),"keymap_special_inventory");
434 this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,wgettext("Prev. item"), "keymap_hotbar_previous");
435 this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,wgettext("Next item"), "keymap_hotbar_next");
436 this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
437 this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
438 this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
439 this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
440 this->add_key(GUI_ID_KEY_PITCH_MOVE, wgettext("Toggle pitchmove"), "keymap_pitchmove");
441 this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
442 this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
443 this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
444 this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON,wgettext("Dec. volume"), "keymap_decrease_volume");
445 this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON,wgettext("Inc. volume"), "keymap_increase_volume");
446 this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
447 this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
448 this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON,wgettext("Screenshot"), "keymap_screenshot");
449 this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
450 this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
451 this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
452 this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
453 this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
454 this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
455 this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
456 this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
457 this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");
458 this->add_key(GUI_ID_KEY_CHEAT_MENU_BUTTON,wgettext("Toggle C. Menu"),"keymap_toggle_cheat_menu");
459 this->add_key(GUI_ID_KEY_KILLAURA_BUTTON, wgettext("Toggle Killaura"), "keymap_toggle_killaura");
460 this->add_key(GUI_ID_KEY_FREECAM_BUTTON, wgettext("Toggle Freec."), "keymap_toggle_freecam");
461 this->add_key(GUI_ID_KEY_SELECT_UP_BUTTON, wgettext("C. Menu Up"), "keymap_select_up");
462 this->add_key(GUI_ID_KEY_SELECT_DOWN_BUTTON,wgettext("C. Menu Down"), "keymap_select_down");
463 this->add_key(GUI_ID_KEY_SELECT_LEFT_BUTTON,wgettext("C. Menu Left"), "keymap_select_left");
464 this->add_key(GUI_ID_KEY_SELECT_RIGHT_BUTTON,wgettext("C. Menu Right"),"keymap_select_right");
465 this->add_key(GUI_ID_KEY_SELECT_CONFIRM_BUTTON,wgettext("C. Menu Enter"),"keymap_select_confirm");