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)
89 for (key_setting *ks : key_settings)
90 key_used.push_back(ks->key);
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) {
117 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
121 const float s = m_gui_scale;
122 DesiredRect = core::rect<s32>(
123 screensize.X / 2 - 835 * s / 2,
124 screensize.Y / 2 - 430 * s / 2,
125 screensize.X / 2 + 835 * s / 2,
126 screensize.Y / 2 + 430 * s / 2
128 recalculateAbsolutePosition(false);
130 v2s32 size = DesiredRect.getSize();
134 core::rect<s32> rect(0, 0, 600 * s, 40 * s);
135 rect += topleft + v2s32(25 * s, 3 * s);
136 //gui::IGUIStaticText *t =
137 const wchar_t *text = wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)");
138 Environment->addStaticText(text,
139 rect, false, true, this, -1);
141 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
146 v2s32 offset(25 * s, 60 * s);
148 for(size_t i = 0; i < key_settings.size(); i++)
150 key_setting *k = key_settings.at(i);
152 core::rect<s32> rect(0, 0, 150 * s, 20 * s);
153 rect += topleft + v2s32(offset.X, offset.Y);
154 Environment->addStaticText(k->button_name, rect, false, true, this, -1);
158 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
159 rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s);
160 const wchar_t *text = wgettext(k->key.name());
161 k->button = GUIButton::addButton(Environment, rect, this, k->id, text);
164 if ((i + 1) % KMaxButtonPerColumns == 0) {
168 offset += v2s32(0, 25 * s);
173 s32 option_x = offset.X;
174 s32 option_y = offset.Y + 5 * s;
175 u32 option_w = 180 * s;
177 core::rect<s32> rect(0, 0, option_w, 30 * s);
178 rect += topleft + v2s32(option_x, option_y);
179 const wchar_t *text = wgettext("\"Special\" = climb down");
180 Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
181 GUI_ID_CB_AUX1_DESCENDS, text);
184 offset += v2s32(0, 25 * s);
188 s32 option_x = offset.X;
189 s32 option_y = offset.Y + 5 * s;
190 u32 option_w = 280 * s;
192 core::rect<s32> rect(0, 0, option_w, 30 * s);
193 rect += topleft + v2s32(option_x, option_y);
194 const wchar_t *text = wgettext("Double tap \"jump\" to toggle fly");
195 Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this,
196 GUI_ID_CB_DOUBLETAP_JUMP, text);
199 offset += v2s32(0, 25 * s);
203 s32 option_x = offset.X;
204 s32 option_y = offset.Y + 5 * s;
207 core::rect<s32> rect(0, 0, option_w, 30 * s);
208 rect += topleft + v2s32(option_x, option_y);
209 const wchar_t *text = wgettext("Automatic jumping");
210 Environment->addCheckBox(g_settings->getBool("autojump"), rect, this,
211 GUI_ID_CB_AUTOJUMP, text);
214 offset += v2s32(0, 25);
218 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
219 rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
220 const wchar_t *text = wgettext("Save");
221 GUIButton::addButton(Environment, rect, this, GUI_ID_BACK_BUTTON, text);
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 GUIButton::addButton(Environment, rect, this, GUI_ID_ABORT_BUTTON, text);
233 void GUIKeyChangeMenu::drawMenu()
235 gui::IGUISkin* skin = Environment->getSkin();
238 video::IVideoDriver* driver = Environment->getVideoDriver();
240 video::SColor bgcolor(140, 0, 0, 0);
241 driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
243 gui::IGUIElement::draw();
246 bool GUIKeyChangeMenu::acceptInput()
248 for (key_setting *k : key_settings) {
249 g_settings->set(k->setting_name, k->key.sym());
253 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
254 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
255 g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
258 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
259 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
260 g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
263 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP);
264 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
265 g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
270 g_gamecallback->signalKeyConfigChange();
275 bool GUIKeyChangeMenu::resetMenu()
279 for (key_setting *k : key_settings) {
280 if (k->id == activeKey) {
281 const wchar_t *text = wgettext(k->key.name());
282 k->button->setText(text);
292 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
294 if (event.EventType == EET_KEY_INPUT_EVENT && activeKey >= 0
295 && event.KeyInput.PressedDown) {
297 bool prefer_character = shift_down;
298 KeyPress kp(event.KeyInput, prefer_character);
300 bool shift_went_down = false;
302 (event.KeyInput.Key == irr::KEY_SHIFT ||
303 event.KeyInput.Key == irr::KEY_LSHIFT ||
304 event.KeyInput.Key == irr::KEY_RSHIFT))
305 shift_went_down = true;
307 // Remove Key already in use message
308 if(this->key_used_text)
310 this->key_used_text->remove();
311 this->key_used_text = NULL;
313 // Display Key already in use message
314 if (std::find(this->key_used.begin(), this->key_used.end(), kp) != this->key_used.end())
316 core::rect < s32 > rect(0, 0, 600, 40);
317 rect += v2s32(0, 0) + v2s32(25, 30);
318 const wchar_t *text = wgettext("Key already in use");
319 this->key_used_text = Environment->addStaticText(text,
320 rect, false, true, this, -1);
322 //infostream << "Key already in use" << std::endl;
327 key_setting *k = NULL;
328 for (key_setting *ks : key_settings) {
329 if (ks->id == activeKey) {
334 FATAL_ERROR_IF(k == NULL, "Key setting not found");
336 const wchar_t *text = wgettext(k->key.name());
337 k->button->setText(text);
340 this->key_used.push_back(kp);
342 // Allow characters made with shift
351 } else if (event.EventType == EET_KEY_INPUT_EVENT && activeKey < 0
352 && event.KeyInput.PressedDown
353 && event.KeyInput.Key == irr::KEY_ESCAPE) {
356 } else if (event.EventType == EET_GUI_EVENT) {
357 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
360 if (!canTakeFocus(event.GUIEvent.Element))
362 dstream << "GUIMainMenu: Not allowing focus change."
364 // Returning true disables focus change
368 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
370 switch (event.GUIEvent.Caller->getID())
372 case GUI_ID_BACK_BUTTON: //back
376 case GUI_ID_ABORT_BUTTON: //abort
380 key_setting *k = NULL;
382 for (key_setting *ks : key_settings) {
383 if (ks->id == event.GUIEvent.Caller->getID()) {
388 FATAL_ERROR_IF(k == NULL, "Key setting not found");
392 activeKey = event.GUIEvent.Caller->getID();
393 const wchar_t *text = wgettext("press key");
394 k->button->setText(text);
396 this->key_used.erase(std::remove(this->key_used.begin(),
397 this->key_used.end(), k->key), this->key_used.end());
400 Environment->setFocus(this);
403 return Parent ? Parent->OnEvent(event) : false;
406 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
408 key_setting *k = new key_setting;
411 k->button_name = button_name;
412 k->setting_name = setting_name;
413 k->key = getKeySetting(k->setting_name.c_str());
414 key_settings.push_back(k);
417 void GUIKeyChangeMenu::init_keys()
419 this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
420 this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
421 this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
422 this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
423 this->add_key(GUI_ID_KEY_USE_BUTTON, wgettext("Special"), "keymap_special1");
424 this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
425 this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
426 this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
427 this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
428 this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,wgettext("Prev. item"), "keymap_hotbar_previous");
429 this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,wgettext("Next item"), "keymap_hotbar_next");
430 this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
431 this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
432 this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
433 this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
434 this->add_key(GUI_ID_KEY_PITCH_MOVE, wgettext("Toggle pitchmove"), "keymap_pitchmove");
435 this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
436 this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
437 this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
438 this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON,wgettext("Dec. volume"), "keymap_decrease_volume");
439 this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON,wgettext("Inc. volume"), "keymap_increase_volume");
440 this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
441 this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
442 this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON,wgettext("Screenshot"), "keymap_screenshot");
443 this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
444 this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
445 this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
446 this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
447 this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
448 this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
449 this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
450 this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
451 this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");