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_AUX1_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_BLOCK_BOUNDS_BUTTON,
74 GUI_ID_KEY_HUD_BUTTON,
75 GUI_ID_KEY_FOG_BUTTON,
76 GUI_ID_KEY_DEC_RANGE_BUTTON,
77 GUI_ID_KEY_INC_RANGE_BUTTON,
78 GUI_ID_KEY_AUTOFWD_BUTTON,
80 GUI_ID_CB_AUX1_DESCENDS,
81 GUI_ID_CB_DOUBLETAP_JUMP,
85 GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
86 gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
87 ISimpleTextureSource *tsrc) :
88 GUIModalMenu(env, parent, id, menumgr),
94 GUIKeyChangeMenu::~GUIKeyChangeMenu()
97 key_used_text = nullptr;
99 for (key_setting *ks : key_settings) {
100 delete[] ks->button_name;
103 key_settings.clear();
106 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
109 key_used_text = nullptr;
111 const float s = m_gui_scale;
112 DesiredRect = core::rect<s32>(
113 screensize.X / 2 - 835 * s / 2,
114 screensize.Y / 2 - 430 * s / 2,
115 screensize.X / 2 + 835 * s / 2,
116 screensize.Y / 2 + 430 * s / 2
118 recalculateAbsolutePosition(false);
120 v2s32 size = DesiredRect.getSize();
124 core::rect<s32> rect(0, 0, 600 * s, 40 * s);
125 rect += topleft + v2s32(25 * s, 3 * s);
126 //gui::IGUIStaticText *t =
127 const wchar_t *text = wgettext("Keybindings.");
128 Environment->addStaticText(text,
129 rect, false, true, this, -1);
131 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
136 v2s32 offset(25 * s, 60 * s);
138 for(size_t i = 0; i < key_settings.size(); i++)
140 key_setting *k = key_settings.at(i);
142 core::rect<s32> rect(0, 0, 150 * s, 20 * s);
143 rect += topleft + v2s32(offset.X, offset.Y);
144 Environment->addStaticText(k->button_name, rect, false, true, this, -1);
148 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
149 rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s);
150 const wchar_t *text = wgettext(k->key.name());
151 k->button = GUIButton::addButton(Environment, rect, m_tsrc, this, k->id, text);
154 if ((i + 1) % KMaxButtonPerColumns == 0) {
158 offset += v2s32(0, 25 * s);
163 s32 option_x = offset.X;
164 s32 option_y = offset.Y + 5 * s;
165 u32 option_w = 180 * s;
167 core::rect<s32> rect(0, 0, option_w, 30 * s);
168 rect += topleft + v2s32(option_x, option_y);
169 const wchar_t *text = wgettext("\"Aux1\" = climb down");
170 Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
171 GUI_ID_CB_AUX1_DESCENDS, text);
174 offset += v2s32(0, 25 * s);
178 s32 option_x = offset.X;
179 s32 option_y = offset.Y + 5 * s;
180 u32 option_w = 280 * s;
182 core::rect<s32> rect(0, 0, option_w, 30 * s);
183 rect += topleft + v2s32(option_x, option_y);
184 const wchar_t *text = wgettext("Double tap \"jump\" to toggle fly");
185 Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this,
186 GUI_ID_CB_DOUBLETAP_JUMP, text);
189 offset += v2s32(0, 25 * s);
193 s32 option_x = offset.X;
194 s32 option_y = offset.Y + 5 * s;
197 core::rect<s32> rect(0, 0, option_w, 30 * s);
198 rect += topleft + v2s32(option_x, option_y);
199 const wchar_t *text = wgettext("Automatic jumping");
200 Environment->addCheckBox(g_settings->getBool("autojump"), rect, this,
201 GUI_ID_CB_AUTOJUMP, text);
204 offset += v2s32(0, 25);
208 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
209 rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
210 const wchar_t *text = wgettext("Save");
211 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
215 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
216 rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
217 const wchar_t *text = wgettext("Cancel");
218 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
223 void GUIKeyChangeMenu::drawMenu()
225 gui::IGUISkin* skin = Environment->getSkin();
228 video::IVideoDriver* driver = Environment->getVideoDriver();
230 video::SColor bgcolor(140, 0, 0, 0);
231 driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
233 gui::IGUIElement::draw();
236 bool GUIKeyChangeMenu::acceptInput()
238 for (key_setting *k : key_settings) {
239 std::string default_key;
240 Settings::getLayer(SL_DEFAULTS)->getNoEx(k->setting_name, default_key);
242 if (k->key.sym() != default_key)
243 g_settings->set(k->setting_name, k->key.sym());
245 g_settings->remove(k->setting_name);
249 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
250 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
251 g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
254 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
255 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
256 g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
259 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP);
260 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
261 g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
266 g_gamecallback->signalKeyConfigChange();
271 bool GUIKeyChangeMenu::resetMenu()
274 const wchar_t *text = wgettext(active_key->key.name());
275 active_key->button->setText(text);
277 active_key = nullptr;
282 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
284 if (event.EventType == EET_KEY_INPUT_EVENT && active_key
285 && event.KeyInput.PressedDown) {
287 bool prefer_character = shift_down;
288 KeyPress kp(event.KeyInput, prefer_character);
290 if (event.KeyInput.Key == irr::KEY_DELETE)
291 kp = KeyPress(""); // To erase key settings
292 else if (event.KeyInput.Key == irr::KEY_ESCAPE)
293 kp = active_key->key; // Cancel
295 bool shift_went_down = false;
297 (event.KeyInput.Key == irr::KEY_SHIFT ||
298 event.KeyInput.Key == irr::KEY_LSHIFT ||
299 event.KeyInput.Key == irr::KEY_RSHIFT))
300 shift_went_down = true;
302 // Display Key already in use message
303 bool key_in_use = false;
304 if (strcmp(kp.sym(), "") != 0) {
305 for (key_setting *ks : key_settings) {
306 if (ks != active_key && ks->key == kp) {
313 if (key_in_use && !this->key_used_text) {
314 core::rect<s32> rect(0, 0, 600, 40);
315 rect += v2s32(0, 0) + v2s32(25, 30);
316 const wchar_t *text = wgettext("Key already in use");
317 this->key_used_text = Environment->addStaticText(text,
318 rect, false, true, this, -1);
320 } else if (!key_in_use && this->key_used_text) {
321 this->key_used_text->remove();
322 this->key_used_text = nullptr;
327 active_key->key = kp;
328 const wchar_t *text = wgettext(kp.name());
329 active_key->button->setText(text);
332 // Allow characters made with shift
333 if (shift_went_down){
338 active_key = nullptr;
341 } else if (event.EventType == EET_KEY_INPUT_EVENT && !active_key
342 && event.KeyInput.PressedDown
343 && event.KeyInput.Key == irr::KEY_ESCAPE) {
346 } else if (event.EventType == EET_GUI_EVENT) {
347 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
350 if (!canTakeFocus(event.GUIEvent.Element))
352 infostream << "GUIKeyChangeMenu: Not allowing focus change."
354 // Returning true disables focus change
358 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
360 switch (event.GUIEvent.Caller->getID())
362 case GUI_ID_BACK_BUTTON: //back
366 case GUI_ID_ABORT_BUTTON: //abort
371 for (key_setting *ks : key_settings) {
372 if (ks->id == event.GUIEvent.Caller->getID()) {
377 FATAL_ERROR_IF(!active_key, "Key setting not found");
380 const wchar_t *text = wgettext("press key");
381 active_key->button->setText(text);
385 Environment->setFocus(this);
388 return Parent ? Parent->OnEvent(event) : false;
391 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
393 key_setting *k = new key_setting;
396 k->button_name = button_name;
397 k->setting_name = setting_name;
398 k->key = getKeySetting(k->setting_name.c_str());
399 key_settings.push_back(k);
402 void GUIKeyChangeMenu::init_keys()
404 this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
405 this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
406 this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
407 this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
408 this->add_key(GUI_ID_KEY_AUX1_BUTTON, wgettext("Aux1"), "keymap_aux1");
409 this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
410 this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
411 this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
412 this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
413 this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON, wgettext("Prev. item"), "keymap_hotbar_previous");
414 this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON, wgettext("Next item"), "keymap_hotbar_next");
415 this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
416 this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
417 this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
418 this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
419 this->add_key(GUI_ID_KEY_PITCH_MOVE, wgettext("Toggle pitchmove"), "keymap_pitchmove");
420 this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
421 this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
422 this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
423 this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON, wgettext("Dec. volume"), "keymap_decrease_volume");
424 this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON, wgettext("Inc. volume"), "keymap_increase_volume");
425 this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
426 this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
427 this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON, wgettext("Screenshot"), "keymap_screenshot");
428 this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
429 this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
430 this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
431 this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
432 this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
433 this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
434 this->add_key(GUI_ID_KEY_BLOCK_BOUNDS_BUTTON, wgettext("Block bounds"), "keymap_toggle_block_bounds");
435 this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
436 this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
437 this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");