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 GUIModalMenu(env, parent, id, menumgr)
91 GUIKeyChangeMenu::~GUIKeyChangeMenu()
95 for (key_setting *ks : key_settings) {
96 delete[] ks->button_name;
102 void GUIKeyChangeMenu::removeChildren()
104 const core::list<gui::IGUIElement*> &children = getChildren();
105 core::list<gui::IGUIElement*> children_copy;
106 for (gui::IGUIElement*i : children) {
107 children_copy.push_back(i);
110 for (gui::IGUIElement *i : children_copy) {
113 key_used_text = nullptr;
116 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
120 const float s = m_gui_scale;
121 DesiredRect = core::rect<s32>(
122 screensize.X / 2 - 835 * s / 2,
123 screensize.Y / 2 - 430 * s / 2,
124 screensize.X / 2 + 835 * 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 + 150 * s, offset.Y - 5 * s);
159 const wchar_t *text = wgettext(k->key.name());
160 k->button = GUIButton::addButton(Environment, 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 GUIButton::addButton(Environment, rect, this, GUI_ID_BACK_BUTTON, text);
224 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
225 rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
226 const wchar_t *text = wgettext("Cancel");
227 GUIButton::addButton(Environment, rect, this, GUI_ID_ABORT_BUTTON, text);
232 void GUIKeyChangeMenu::drawMenu()
234 gui::IGUISkin* skin = Environment->getSkin();
237 video::IVideoDriver* driver = Environment->getVideoDriver();
239 video::SColor bgcolor(140, 0, 0, 0);
240 driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
242 gui::IGUIElement::draw();
245 bool GUIKeyChangeMenu::acceptInput()
247 for (key_setting *k : key_settings) {
248 std::string default_key;
249 g_settings->getDefaultNoEx(k->setting_name, default_key);
251 if (k->key.sym() != default_key)
252 g_settings->set(k->setting_name, k->key.sym());
254 g_settings->remove(k->setting_name);
258 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
259 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
260 g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
263 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
264 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
265 g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
268 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP);
269 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
270 g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
275 g_gamecallback->signalKeyConfigChange();
280 bool GUIKeyChangeMenu::resetMenu()
283 const wchar_t *text = wgettext(active_key->key.name());
284 active_key->button->setText(text);
286 active_key = nullptr;
291 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
293 if (event.EventType == EET_KEY_INPUT_EVENT && active_key
294 && event.KeyInput.PressedDown) {
296 bool prefer_character = shift_down;
297 KeyPress kp(event.KeyInput, prefer_character);
299 if (event.KeyInput.Key == irr::KEY_DELETE)
300 kp = KeyPress(""); // To erase key settings
301 else if (event.KeyInput.Key == irr::KEY_ESCAPE)
302 kp = active_key->key; // Cancel
304 bool shift_went_down = false;
306 (event.KeyInput.Key == irr::KEY_SHIFT ||
307 event.KeyInput.Key == irr::KEY_LSHIFT ||
308 event.KeyInput.Key == irr::KEY_RSHIFT))
309 shift_went_down = true;
311 // Display Key already in use message
312 bool key_in_use = false;
313 if (strcmp(kp.sym(), "") != 0) {
314 for (key_setting *ks : key_settings) {
315 if (ks != active_key && ks->key == kp) {
322 if (key_in_use && !this->key_used_text) {
323 core::rect<s32> rect(0, 0, 600, 40);
324 rect += v2s32(0, 0) + v2s32(25, 30);
325 const wchar_t *text = wgettext("Key already in use");
326 this->key_used_text = Environment->addStaticText(text,
327 rect, false, true, this, -1);
329 } else if (!key_in_use && this->key_used_text) {
330 this->key_used_text->remove();
331 this->key_used_text = nullptr;
336 active_key->key = kp;
337 const wchar_t *text = wgettext(kp.name());
338 active_key->button->setText(text);
341 // Allow characters made with shift
342 if (shift_went_down){
347 active_key = nullptr;
350 } else if (event.EventType == EET_KEY_INPUT_EVENT && !active_key
351 && event.KeyInput.PressedDown
352 && event.KeyInput.Key == irr::KEY_ESCAPE) {
355 } else if (event.EventType == EET_GUI_EVENT) {
356 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
359 if (!canTakeFocus(event.GUIEvent.Element))
361 dstream << "GUIMainMenu: Not allowing focus change."
363 // Returning true disables focus change
367 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
369 switch (event.GUIEvent.Caller->getID())
371 case GUI_ID_BACK_BUTTON: //back
375 case GUI_ID_ABORT_BUTTON: //abort
380 for (key_setting *ks : key_settings) {
381 if (ks->id == event.GUIEvent.Caller->getID()) {
386 FATAL_ERROR_IF(!active_key, "Key setting not found");
389 const wchar_t *text = wgettext("press key");
390 active_key->button->setText(text);
394 Environment->setFocus(this);
397 return Parent ? Parent->OnEvent(event) : false;
400 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
402 key_setting *k = new key_setting;
405 k->button_name = button_name;
406 k->setting_name = setting_name;
407 k->key = getKeySetting(k->setting_name.c_str());
408 key_settings.push_back(k);
411 void GUIKeyChangeMenu::init_keys()
413 this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
414 this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
415 this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
416 this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
417 this->add_key(GUI_ID_KEY_USE_BUTTON, wgettext("Special"), "keymap_special1");
418 this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
419 this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
420 this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
421 this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
422 this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,wgettext("Prev. item"), "keymap_hotbar_previous");
423 this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,wgettext("Next item"), "keymap_hotbar_next");
424 this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
425 this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
426 this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
427 this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
428 this->add_key(GUI_ID_KEY_PITCH_MOVE, wgettext("Toggle pitchmove"), "keymap_pitchmove");
429 this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
430 this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
431 this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
432 this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON,wgettext("Dec. volume"), "keymap_decrease_volume");
433 this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON,wgettext("Inc. volume"), "keymap_increase_volume");
434 this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
435 this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
436 this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON,wgettext("Screenshot"), "keymap_screenshot");
437 this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
438 this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
439 this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
440 this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
441 this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
442 this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
443 this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
444 this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
445 this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");