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,
82 GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
83 gui::IGUIElement* parent, s32 id, IMenuManager *menumgr) :
84 GUIModalMenu(env, parent, id, menumgr)
87 for (key_setting *ks : key_settings)
88 key_used.push_back(ks->key);
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) {
115 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
118 v2s32 size(745, 430);
120 core::rect < s32 > rect(screensize.X / 2 - size.X / 2,
121 screensize.Y / 2 - size.Y / 2, screensize.X / 2 + size.X / 2,
122 screensize.Y / 2 + size.Y / 2);
125 recalculateAbsolutePosition(false);
130 core::rect < s32 > rect(0, 0, 600, 40);
131 rect += topleft + v2s32(25, 3);
132 //gui::IGUIStaticText *t =
133 const wchar_t *text = wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)");
134 Environment->addStaticText(text,
135 rect, false, true, this, -1);
137 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
142 v2s32 offset(25, 60);
144 for(size_t i = 0; i < key_settings.size(); i++)
146 key_setting *k = key_settings.at(i);
148 core::rect < s32 > rect(0, 0, 150, 20);
149 rect += topleft + v2s32(offset.X, offset.Y);
150 Environment->addStaticText(k->button_name, rect, false, true, this, -1);
154 core::rect < s32 > rect(0, 0, 100, 30);
155 rect += topleft + v2s32(offset.X + 120, offset.Y - 5);
156 const wchar_t *text = wgettext(k->key.name());
157 k->button = Environment->addButton(rect, this, k->id, text);
160 if ((i + 1) % KMaxButtonPerColumns == 0) {
164 offset += v2s32(0, 25);
169 s32 option_x = offset.X;
170 s32 option_y = offset.Y + 5;
173 core::rect<s32> rect(0, 0, option_w, 30);
174 rect += topleft + v2s32(option_x, option_y);
175 const wchar_t *text = wgettext("\"Special\" = climb down");
176 Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
177 GUI_ID_CB_AUX1_DESCENDS, text);
180 offset += v2s32(0, 25);
184 s32 option_x = offset.X;
185 s32 option_y = offset.Y + 5;
188 core::rect<s32> rect(0, 0, option_w, 30);
189 rect += topleft + v2s32(option_x, option_y);
190 const wchar_t *text = wgettext("Double tap \"jump\" to toggle fly");
191 Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this,
192 GUI_ID_CB_DOUBLETAP_JUMP, text);
195 offset += v2s32(0, 25);
199 core::rect < s32 > rect(0, 0, 100, 30);
200 rect += topleft + v2s32(size.X / 2 - 105, size.Y - 40);
201 const wchar_t *text = wgettext("Save");
202 Environment->addButton(rect, this, GUI_ID_BACK_BUTTON,
207 core::rect < s32 > rect(0, 0, 100, 30);
208 rect += topleft + v2s32(size.X / 2 + 5, size.Y - 40);
209 const wchar_t *text = wgettext("Cancel");
210 Environment->addButton(rect, this, GUI_ID_ABORT_BUTTON,
216 void GUIKeyChangeMenu::drawMenu()
218 gui::IGUISkin* skin = Environment->getSkin();
221 video::IVideoDriver* driver = Environment->getVideoDriver();
223 video::SColor bgcolor(140, 0, 0, 0);
226 core::rect < s32 > rect(0, 0, 745, 620);
227 rect += AbsoluteRect.UpperLeftCorner;
228 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
231 gui::IGUIElement::draw();
234 bool GUIKeyChangeMenu::acceptInput()
236 for (key_setting *k : key_settings) {
237 g_settings->set(k->setting_name, k->key.sym());
241 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
242 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
243 g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
246 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
247 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
248 g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
253 g_gamecallback->signalKeyConfigChange();
258 bool GUIKeyChangeMenu::resetMenu()
262 for (key_setting *k : key_settings) {
263 if (k->id == activeKey) {
264 const wchar_t *text = wgettext(k->key.name());
265 k->button->setText(text);
275 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
277 if (event.EventType == EET_KEY_INPUT_EVENT && activeKey >= 0
278 && event.KeyInput.PressedDown) {
280 bool prefer_character = shift_down;
281 KeyPress kp(event.KeyInput, prefer_character);
283 bool shift_went_down = false;
285 (event.KeyInput.Key == irr::KEY_SHIFT ||
286 event.KeyInput.Key == irr::KEY_LSHIFT ||
287 event.KeyInput.Key == irr::KEY_RSHIFT))
288 shift_went_down = true;
290 // Remove Key already in use message
291 if(this->key_used_text)
293 this->key_used_text->remove();
294 this->key_used_text = NULL;
296 // Display Key already in use message
297 if (std::find(this->key_used.begin(), this->key_used.end(), kp) != this->key_used.end())
299 core::rect < s32 > rect(0, 0, 600, 40);
300 rect += v2s32(0, 0) + v2s32(25, 30);
301 const wchar_t *text = wgettext("Key already in use");
302 this->key_used_text = Environment->addStaticText(text,
303 rect, false, true, this, -1);
305 //infostream << "Key already in use" << std::endl;
310 key_setting *k = NULL;
311 for (key_setting *ks : key_settings) {
312 if (ks->id == activeKey) {
317 FATAL_ERROR_IF(k == NULL, "Key setting not found");
319 const wchar_t *text = wgettext(k->key.name());
320 k->button->setText(text);
323 this->key_used.push_back(kp);
325 // Allow characters made with shift
334 } else if (event.EventType == EET_KEY_INPUT_EVENT && activeKey < 0
335 && event.KeyInput.PressedDown
336 && event.KeyInput.Key == irr::KEY_ESCAPE) {
339 } else if (event.EventType == EET_GUI_EVENT) {
340 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
343 if (!canTakeFocus(event.GUIEvent.Element))
345 dstream << "GUIMainMenu: Not allowing focus change."
347 // Returning true disables focus change
351 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
353 switch (event.GUIEvent.Caller->getID())
355 case GUI_ID_BACK_BUTTON: //back
359 case GUI_ID_ABORT_BUTTON: //abort
363 key_setting *k = NULL;
365 for (key_setting *ks : key_settings) {
366 if (ks->id == event.GUIEvent.Caller->getID()) {
371 FATAL_ERROR_IF(k == NULL, "Key setting not found");
375 activeKey = event.GUIEvent.Caller->getID();
376 const wchar_t *text = wgettext("press key");
377 k->button->setText(text);
379 this->key_used.erase(std::remove(this->key_used.begin(),
380 this->key_used.end(), k->key), this->key_used.end());
383 Environment->setFocus(this);
386 return Parent ? Parent->OnEvent(event) : false;
389 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
391 key_setting *k = new key_setting;
394 k->button_name = button_name;
395 k->setting_name = setting_name;
396 k->key = getKeySetting(k->setting_name.c_str());
397 key_settings.push_back(k);
400 void GUIKeyChangeMenu::init_keys()
402 this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
403 this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
404 this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
405 this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
406 this->add_key(GUI_ID_KEY_USE_BUTTON, wgettext("Special"), "keymap_special1");
407 this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
408 this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
409 this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
410 this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
411 this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,wgettext("Prev. item"), "keymap_hotbar_previous");
412 this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,wgettext("Next item"), "keymap_hotbar_next");
413 this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
414 this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
415 this->add_key(GUI_ID_KEY_CINEMATIC_BUTTON, wgettext("Toggle Cinematic"), "keymap_cinematic");
416 this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
417 this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
418 this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
419 this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
420 this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
421 this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON,wgettext("Dec. volume"), "keymap_decrease_volume");
422 this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON,wgettext("Inc. volume"), "keymap_increase_volume");
423 this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
424 this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
425 this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON,wgettext("Screenshot"), "keymap_screenshot");
426 this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
427 this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
428 this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
429 this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
430 this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
431 this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
432 this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
433 this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
434 this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");