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 "serialization.h"
26 #include <IGUICheckBox.h>
27 #include <IGUIEditBox.h>
28 #include <IGUIButton.h>
29 #include <IGUIStaticText.h>
34 #include "mainmenumanager.h" // for g_gamecallback
36 #define KMaxButtonPerColumns 12
38 extern MainGameCallback *g_gamecallback;
42 GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR,
44 GUI_ID_KEY_FORWARD_BUTTON,
45 GUI_ID_KEY_BACKWARD_BUTTON,
46 GUI_ID_KEY_LEFT_BUTTON,
47 GUI_ID_KEY_RIGHT_BUTTON,
48 GUI_ID_KEY_USE_BUTTON,
49 GUI_ID_KEY_FLY_BUTTON,
50 GUI_ID_KEY_FAST_BUTTON,
51 GUI_ID_KEY_JUMP_BUTTON,
52 GUI_ID_KEY_NOCLIP_BUTTON,
53 GUI_ID_KEY_CINEMATIC_BUTTON,
54 GUI_ID_KEY_CHAT_BUTTON,
55 GUI_ID_KEY_CMD_BUTTON,
56 GUI_ID_KEY_CMD_LOCAL_BUTTON,
57 GUI_ID_KEY_CONSOLE_BUTTON,
58 GUI_ID_KEY_SNEAK_BUTTON,
59 GUI_ID_KEY_DROP_BUTTON,
60 GUI_ID_KEY_INVENTORY_BUTTON,
61 GUI_ID_KEY_HOTBAR_PREV_BUTTON,
62 GUI_ID_KEY_HOTBAR_NEXT_BUTTON,
63 GUI_ID_KEY_MUTE_BUTTON,
64 GUI_ID_KEY_DEC_VOLUME_BUTTON,
65 GUI_ID_KEY_INC_VOLUME_BUTTON,
66 GUI_ID_KEY_RANGE_BUTTON,
67 GUI_ID_KEY_ZOOM_BUTTON,
68 GUI_ID_KEY_CAMERA_BUTTON,
69 GUI_ID_KEY_MINIMAP_BUTTON,
70 GUI_ID_KEY_SCREENSHOT_BUTTON,
71 GUI_ID_KEY_CHATLOG_BUTTON,
72 GUI_ID_KEY_HUD_BUTTON,
73 GUI_ID_KEY_FOG_BUTTON,
74 GUI_ID_KEY_DEC_RANGE_BUTTON,
75 GUI_ID_KEY_INC_RANGE_BUTTON,
76 GUI_ID_KEY_AUTOFWD_BUTTON,
78 GUI_ID_CB_AUX1_DESCENDS,
79 GUI_ID_CB_DOUBLETAP_JUMP,
83 GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
84 gui::IGUIElement* parent, s32 id, IMenuManager *menumgr) :
85 GUIModalMenu(env, parent, id, menumgr)
88 for (key_setting *ks : key_settings)
89 key_used.push_back(ks->key);
92 GUIKeyChangeMenu::~GUIKeyChangeMenu()
96 for (key_setting *ks : key_settings) {
97 delete[] ks->button_name;
100 key_settings.clear();
103 void GUIKeyChangeMenu::removeChildren()
105 const core::list<gui::IGUIElement*> &children = getChildren();
106 core::list<gui::IGUIElement*> children_copy;
107 for (gui::IGUIElement*i : children) {
108 children_copy.push_back(i);
111 for (gui::IGUIElement *i : children_copy) {
116 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
120 const float s = m_gui_scale;
121 DesiredRect = core::rect<s32>(
122 screensize.X / 2 - 745 * s / 2,
123 screensize.Y / 2 - 430 * s / 2,
124 screensize.X / 2 + 745 * s / 2,
125 screensize.Y / 2 + 430 * s / 2
127 recalculateAbsolutePosition(false);
129 v2s32 size = DesiredRect.getSize();
133 core::rect<s32> rect(0, 0, 600 * s, 40 * s);
134 rect += topleft + v2s32(25 * s, 3 * s);
135 //gui::IGUIStaticText *t =
136 const wchar_t *text = wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)");
137 Environment->addStaticText(text,
138 rect, false, true, this, -1);
140 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
145 v2s32 offset(25 * s, 60 * s);
147 for(size_t i = 0; i < key_settings.size(); i++)
149 key_setting *k = key_settings.at(i);
151 core::rect<s32> rect(0, 0, 150 * s, 20 * s);
152 rect += topleft + v2s32(offset.X, offset.Y);
153 Environment->addStaticText(k->button_name, rect, false, true, this, -1);
157 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
158 rect += topleft + v2s32(offset.X + 120 * s, offset.Y - 5 * s);
159 const wchar_t *text = wgettext(k->key.name());
160 k->button = Environment->addButton(rect, this, k->id, text);
163 if ((i + 1) % KMaxButtonPerColumns == 0) {
167 offset += v2s32(0, 25 * s);
172 s32 option_x = offset.X;
173 s32 option_y = offset.Y + 5 * s;
174 u32 option_w = 180 * s;
176 core::rect<s32> rect(0, 0, option_w, 30 * s);
177 rect += topleft + v2s32(option_x, option_y);
178 const wchar_t *text = wgettext("\"Special\" = climb down");
179 Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
180 GUI_ID_CB_AUX1_DESCENDS, text);
183 offset += v2s32(0, 25 * s);
187 s32 option_x = offset.X;
188 s32 option_y = offset.Y + 5 * s;
189 u32 option_w = 280 * s;
191 core::rect<s32> rect(0, 0, option_w, 30 * s);
192 rect += topleft + v2s32(option_x, option_y);
193 const wchar_t *text = wgettext("Double tap \"jump\" to toggle fly");
194 Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this,
195 GUI_ID_CB_DOUBLETAP_JUMP, text);
198 offset += v2s32(0, 25 * s);
202 s32 option_x = offset.X;
203 s32 option_y = offset.Y + 5 * s;
206 core::rect<s32> rect(0, 0, option_w, 30 * s);
207 rect += topleft + v2s32(option_x, option_y);
208 const wchar_t *text = wgettext("Automatic jumping");
209 Environment->addCheckBox(g_settings->getBool("autojump"), rect, this,
210 GUI_ID_CB_AUTOJUMP, text);
213 offset += v2s32(0, 25);
217 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
218 rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
219 const wchar_t *text = wgettext("Save");
220 Environment->addButton(rect, this, GUI_ID_BACK_BUTTON,
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 Environment->addButton(rect, this, GUI_ID_ABORT_BUTTON,
234 void GUIKeyChangeMenu::drawMenu()
236 gui::IGUISkin* skin = Environment->getSkin();
239 video::IVideoDriver* driver = Environment->getVideoDriver();
241 video::SColor bgcolor(140, 0, 0, 0);
242 driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
244 gui::IGUIElement::draw();
247 bool GUIKeyChangeMenu::acceptInput()
249 for (key_setting *k : key_settings) {
250 g_settings->set(k->setting_name, k->key.sym());
254 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
255 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
256 g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
259 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
260 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
261 g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
264 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP);
265 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
266 g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
271 g_gamecallback->signalKeyConfigChange();
276 bool GUIKeyChangeMenu::resetMenu()
280 for (key_setting *k : key_settings) {
281 if (k->id == activeKey) {
282 const wchar_t *text = wgettext(k->key.name());
283 k->button->setText(text);
293 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
295 if (event.EventType == EET_KEY_INPUT_EVENT && activeKey >= 0
296 && event.KeyInput.PressedDown) {
298 bool prefer_character = shift_down;
299 KeyPress kp(event.KeyInput, prefer_character);
301 bool shift_went_down = false;
303 (event.KeyInput.Key == irr::KEY_SHIFT ||
304 event.KeyInput.Key == irr::KEY_LSHIFT ||
305 event.KeyInput.Key == irr::KEY_RSHIFT))
306 shift_went_down = true;
308 // Remove Key already in use message
309 if(this->key_used_text)
311 this->key_used_text->remove();
312 this->key_used_text = NULL;
314 // Display Key already in use message
315 if (std::find(this->key_used.begin(), this->key_used.end(), kp) != this->key_used.end())
317 core::rect < s32 > rect(0, 0, 600, 40);
318 rect += v2s32(0, 0) + v2s32(25, 30);
319 const wchar_t *text = wgettext("Key already in use");
320 this->key_used_text = Environment->addStaticText(text,
321 rect, false, true, this, -1);
323 //infostream << "Key already in use" << std::endl;
328 key_setting *k = NULL;
329 for (key_setting *ks : key_settings) {
330 if (ks->id == activeKey) {
335 FATAL_ERROR_IF(k == NULL, "Key setting not found");
337 const wchar_t *text = wgettext(k->key.name());
338 k->button->setText(text);
341 this->key_used.push_back(kp);
343 // Allow characters made with shift
352 } else if (event.EventType == EET_KEY_INPUT_EVENT && activeKey < 0
353 && event.KeyInput.PressedDown
354 && event.KeyInput.Key == irr::KEY_ESCAPE) {
357 } else if (event.EventType == EET_GUI_EVENT) {
358 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
361 if (!canTakeFocus(event.GUIEvent.Element))
363 dstream << "GUIMainMenu: Not allowing focus change."
365 // Returning true disables focus change
369 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
371 switch (event.GUIEvent.Caller->getID())
373 case GUI_ID_BACK_BUTTON: //back
377 case GUI_ID_ABORT_BUTTON: //abort
381 key_setting *k = NULL;
383 for (key_setting *ks : key_settings) {
384 if (ks->id == event.GUIEvent.Caller->getID()) {
389 FATAL_ERROR_IF(k == NULL, "Key setting not found");
393 activeKey = event.GUIEvent.Caller->getID();
394 const wchar_t *text = wgettext("press key");
395 k->button->setText(text);
397 this->key_used.erase(std::remove(this->key_used.begin(),
398 this->key_used.end(), k->key), this->key_used.end());
401 Environment->setFocus(this);
404 return Parent ? Parent->OnEvent(event) : false;
407 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
409 key_setting *k = new key_setting;
412 k->button_name = button_name;
413 k->setting_name = setting_name;
414 k->key = getKeySetting(k->setting_name.c_str());
415 key_settings.push_back(k);
418 void GUIKeyChangeMenu::init_keys()
420 this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
421 this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
422 this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
423 this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
424 this->add_key(GUI_ID_KEY_USE_BUTTON, wgettext("Special"), "keymap_special1");
425 this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
426 this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
427 this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
428 this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
429 this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,wgettext("Prev. item"), "keymap_hotbar_previous");
430 this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,wgettext("Next item"), "keymap_hotbar_next");
431 this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
432 this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
433 this->add_key(GUI_ID_KEY_CINEMATIC_BUTTON, wgettext("Toggle Cinematic"), "keymap_cinematic");
434 this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
435 this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
436 this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
437 this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
438 this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
439 this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON,wgettext("Dec. volume"), "keymap_decrease_volume");
440 this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON,wgettext("Inc. volume"), "keymap_increase_volume");
441 this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
442 this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
443 this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON,wgettext("Screenshot"), "keymap_screenshot");
444 this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
445 this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
446 this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
447 this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
448 this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
449 this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
450 this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
451 this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
452 this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");