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_HOTBAR_PREV_BUTTON,
63 GUI_ID_KEY_HOTBAR_NEXT_BUTTON,
64 GUI_ID_KEY_MUTE_BUTTON,
65 GUI_ID_KEY_DEC_VOLUME_BUTTON,
66 GUI_ID_KEY_INC_VOLUME_BUTTON,
67 GUI_ID_KEY_RANGE_BUTTON,
68 GUI_ID_KEY_ZOOM_BUTTON,
69 GUI_ID_KEY_CAMERA_BUTTON,
70 GUI_ID_KEY_MINIMAP_BUTTON,
71 GUI_ID_KEY_SCREENSHOT_BUTTON,
72 GUI_ID_KEY_CHATLOG_BUTTON,
73 GUI_ID_KEY_HUD_BUTTON,
74 GUI_ID_KEY_FOG_BUTTON,
75 GUI_ID_KEY_DEC_RANGE_BUTTON,
76 GUI_ID_KEY_INC_RANGE_BUTTON,
77 GUI_ID_KEY_AUTOFWD_BUTTON,
79 GUI_ID_CB_AUX1_DESCENDS,
80 GUI_ID_CB_DOUBLETAP_JUMP,
84 GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
85 gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
86 ISimpleTextureSource *tsrc) :
87 GUIModalMenu(env, parent, id, menumgr),
93 GUIKeyChangeMenu::~GUIKeyChangeMenu()
97 for (key_setting *ks : key_settings) {
98 delete[] ks->button_name;
101 key_settings.clear();
104 void GUIKeyChangeMenu::removeChildren()
106 const core::list<gui::IGUIElement*> &children = getChildren();
107 core::list<gui::IGUIElement*> children_copy;
108 for (gui::IGUIElement*i : children) {
109 children_copy.push_back(i);
112 for (gui::IGUIElement *i : children_copy) {
115 key_used_text = nullptr;
118 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
122 const float s = m_gui_scale;
123 DesiredRect = core::rect<s32>(
124 screensize.X / 2 - 835 * s / 2,
125 screensize.Y / 2 - 430 * s / 2,
126 screensize.X / 2 + 835 * s / 2,
127 screensize.Y / 2 + 430 * s / 2
129 recalculateAbsolutePosition(false);
131 v2s32 size = DesiredRect.getSize();
135 core::rect<s32> rect(0, 0, 600 * s, 40 * s);
136 rect += topleft + v2s32(25 * s, 3 * s);
137 //gui::IGUIStaticText *t =
138 const wchar_t *text = wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)");
139 Environment->addStaticText(text,
140 rect, false, true, this, -1);
142 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
147 v2s32 offset(25 * s, 60 * s);
149 for(size_t i = 0; i < key_settings.size(); i++)
151 key_setting *k = key_settings.at(i);
153 core::rect<s32> rect(0, 0, 150 * s, 20 * s);
154 rect += topleft + v2s32(offset.X, offset.Y);
155 Environment->addStaticText(k->button_name, rect, false, true, this, -1);
159 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
160 rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s);
161 const wchar_t *text = wgettext(k->key.name());
162 k->button = GUIButton::addButton(Environment, rect, m_tsrc, this, k->id, text);
165 if ((i + 1) % KMaxButtonPerColumns == 0) {
169 offset += v2s32(0, 25 * s);
174 s32 option_x = offset.X;
175 s32 option_y = offset.Y + 5 * s;
176 u32 option_w = 180 * s;
178 core::rect<s32> rect(0, 0, option_w, 30 * s);
179 rect += topleft + v2s32(option_x, option_y);
180 const wchar_t *text = wgettext("\"Special\" = climb down");
181 Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
182 GUI_ID_CB_AUX1_DESCENDS, text);
185 offset += v2s32(0, 25 * s);
189 s32 option_x = offset.X;
190 s32 option_y = offset.Y + 5 * s;
191 u32 option_w = 280 * s;
193 core::rect<s32> rect(0, 0, option_w, 30 * s);
194 rect += topleft + v2s32(option_x, option_y);
195 const wchar_t *text = wgettext("Double tap \"jump\" to toggle fly");
196 Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this,
197 GUI_ID_CB_DOUBLETAP_JUMP, text);
200 offset += v2s32(0, 25 * s);
204 s32 option_x = offset.X;
205 s32 option_y = offset.Y + 5 * s;
208 core::rect<s32> rect(0, 0, option_w, 30 * s);
209 rect += topleft + v2s32(option_x, option_y);
210 const wchar_t *text = wgettext("Automatic jumping");
211 Environment->addCheckBox(g_settings->getBool("autojump"), rect, this,
212 GUI_ID_CB_AUTOJUMP, text);
215 offset += v2s32(0, 25);
219 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
220 rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
221 const wchar_t *text = wgettext("Save");
222 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
226 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
227 rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
228 const wchar_t *text = wgettext("Cancel");
229 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
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 std::string default_key;
251 g_settings->getDefaultNoEx(k->setting_name, default_key);
253 if (k->key.sym() != default_key)
254 g_settings->set(k->setting_name, k->key.sym());
256 g_settings->remove(k->setting_name);
260 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
261 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
262 g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
265 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
266 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
267 g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
270 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP);
271 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
272 g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
277 g_gamecallback->signalKeyConfigChange();
282 bool GUIKeyChangeMenu::resetMenu()
285 const wchar_t *text = wgettext(active_key->key.name());
286 active_key->button->setText(text);
288 active_key = nullptr;
293 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
295 if (event.EventType == EET_KEY_INPUT_EVENT && active_key
296 && event.KeyInput.PressedDown) {
298 bool prefer_character = shift_down;
299 KeyPress kp(event.KeyInput, prefer_character);
301 if (event.KeyInput.Key == irr::KEY_DELETE)
302 kp = KeyPress(""); // To erase key settings
303 else if (event.KeyInput.Key == irr::KEY_ESCAPE)
304 kp = active_key->key; // Cancel
306 bool shift_went_down = false;
308 (event.KeyInput.Key == irr::KEY_SHIFT ||
309 event.KeyInput.Key == irr::KEY_LSHIFT ||
310 event.KeyInput.Key == irr::KEY_RSHIFT))
311 shift_went_down = true;
313 // Display Key already in use message
314 bool key_in_use = false;
315 if (strcmp(kp.sym(), "") != 0) {
316 for (key_setting *ks : key_settings) {
317 if (ks != active_key && ks->key == kp) {
324 if (key_in_use && !this->key_used_text) {
325 core::rect<s32> rect(0, 0, 600, 40);
326 rect += v2s32(0, 0) + v2s32(25, 30);
327 const wchar_t *text = wgettext("Key already in use");
328 this->key_used_text = Environment->addStaticText(text,
329 rect, false, true, this, -1);
331 } else if (!key_in_use && this->key_used_text) {
332 this->key_used_text->remove();
333 this->key_used_text = nullptr;
338 active_key->key = kp;
339 const wchar_t *text = wgettext(kp.name());
340 active_key->button->setText(text);
343 // Allow characters made with shift
344 if (shift_went_down){
349 active_key = nullptr;
352 } else if (event.EventType == EET_KEY_INPUT_EVENT && !active_key
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 infostream << "GUIKeyChangeMenu: 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
382 for (key_setting *ks : key_settings) {
383 if (ks->id == event.GUIEvent.Caller->getID()) {
388 FATAL_ERROR_IF(!active_key, "Key setting not found");
391 const wchar_t *text = wgettext("press key");
392 active_key->button->setText(text);
396 Environment->setFocus(this);
399 return Parent ? Parent->OnEvent(event) : false;
402 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
404 key_setting *k = new key_setting;
407 k->button_name = button_name;
408 k->setting_name = setting_name;
409 k->key = getKeySetting(k->setting_name.c_str());
410 key_settings.push_back(k);
413 void GUIKeyChangeMenu::init_keys()
415 this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
416 this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
417 this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
418 this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
419 this->add_key(GUI_ID_KEY_USE_BUTTON, wgettext("Special"), "keymap_special1");
420 this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
421 this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
422 this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
423 this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
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_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
446 this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
447 this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");