]> git.lizzy.rs Git - dragonfireclient.git/blob - src/gui/guiKeyChangeMenu.cpp
Merge branch 'master' of https://github.com/minetest/minetest
[dragonfireclient.git] / src / gui / guiKeyChangeMenu.cpp
1 /*
2  Minetest
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>
6
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.
11
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.
16
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.
20  */
21
22 #include "guiKeyChangeMenu.h"
23 #include "debug.h"
24 #include "guiButton.h"
25 #include "serialization.h"
26 #include <string>
27 #include <IGUICheckBox.h>
28 #include <IGUIEditBox.h>
29 #include <IGUIButton.h>
30 #include <IGUIStaticText.h>
31 #include <IGUIFont.h>
32 #include "settings.h"
33 #include <algorithm>
34
35 #include "mainmenumanager.h"  // for g_gamecallback
36
37 #define KMaxButtonPerColumns 12
38
39 extern MainGameCallback *g_gamecallback;
40
41 enum
42 {
43         GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR,
44         // buttons
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_ENDERCHEST_BUTTON,
63         GUI_ID_KEY_HOTBAR_PREV_BUTTON,
64         GUI_ID_KEY_HOTBAR_NEXT_BUTTON,
65         GUI_ID_KEY_MUTE_BUTTON,
66         GUI_ID_KEY_DEC_VOLUME_BUTTON,
67         GUI_ID_KEY_INC_VOLUME_BUTTON,
68         GUI_ID_KEY_RANGE_BUTTON,
69         GUI_ID_KEY_ZOOM_BUTTON,
70         GUI_ID_KEY_CAMERA_BUTTON,
71         GUI_ID_KEY_MINIMAP_BUTTON,
72         GUI_ID_KEY_SCREENSHOT_BUTTON,
73         GUI_ID_KEY_CHATLOG_BUTTON,
74         GUI_ID_KEY_HUD_BUTTON,
75         GUI_ID_KEY_FOG_BUTTON,
76         GUI_ID_KEY_CHEAT_MENU_BUTTON,
77         GUI_ID_KEY_DEC_RANGE_BUTTON,
78         GUI_ID_KEY_INC_RANGE_BUTTON,
79         GUI_ID_KEY_AUTOFWD_BUTTON,
80         GUI_ID_KEY_KILLAURA_BUTTON,
81         GUI_ID_KEY_FREECAM_BUTTON,
82         GUI_ID_KEY_SCAFFOLD_BUTTON,
83         GUI_ID_KEY_SELECT_UP_BUTTON,
84         GUI_ID_KEY_SELECT_DOWN_BUTTON,
85         GUI_ID_KEY_SELECT_LEFT_BUTTON,
86         GUI_ID_KEY_SELECT_RIGHT_BUTTON,
87         GUI_ID_KEY_SELECT_CONFIRM_BUTTON,
88         // other
89         GUI_ID_CB_AUX1_DESCENDS,
90         GUI_ID_CB_DOUBLETAP_JUMP,
91         GUI_ID_CB_AUTOJUMP,
92 };
93
94 GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
95                 gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
96                 ISimpleTextureSource *tsrc) :
97                 GUIModalMenu(env, parent, id, menumgr),
98                 m_tsrc(tsrc)
99 {
100         init_keys();
101 }
102
103 GUIKeyChangeMenu::~GUIKeyChangeMenu()
104 {
105         removeChildren();
106
107         for (key_setting *ks : key_settings) {
108                 delete[] ks->button_name;
109                 delete ks;
110         }
111         key_settings.clear();
112 }
113
114 void GUIKeyChangeMenu::removeChildren()
115 {
116         const core::list<gui::IGUIElement*> &children = getChildren();
117         core::list<gui::IGUIElement*> children_copy;
118         for (gui::IGUIElement*i : children) {
119                 children_copy.push_back(i);
120         }
121
122         for (gui::IGUIElement *i : children_copy) {
123                 i->remove();
124         }
125         key_used_text = nullptr;
126 }
127
128 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
129 {
130         removeChildren();
131
132         const float s = m_gui_scale;
133         DesiredRect = core::rect<s32>(
134                 screensize.X / 2 - 1113 * s / 2,
135                 screensize.Y / 2 - 430 * s / 2,
136                 screensize.X / 2 + 1113 * s / 2,
137                 screensize.Y / 2 + 430 * s / 2
138         );
139         recalculateAbsolutePosition(false);
140
141         v2s32 size = DesiredRect.getSize();
142         v2s32 topleft(0, 0);
143
144         {
145                 core::rect<s32> rect(0, 0, 600 * s, 40 * s);
146                 rect += topleft + v2s32(25 * s, 3 * s);
147                 //gui::IGUIStaticText *t =
148                 const wchar_t *text = wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)");
149                 Environment->addStaticText(text,
150                                                                    rect, false, true, this, -1);
151                 delete[] text;
152                 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
153         }
154
155         // Build buttons
156
157         v2s32 offset(25 * s, 60 * s);
158
159         for(size_t i = 0; i < key_settings.size(); i++)
160         {
161                 key_setting *k = key_settings.at(i);
162                 {
163                         core::rect<s32> rect(0, 0, 150 * s, 20 * s);
164                         rect += topleft + v2s32(offset.X, offset.Y);
165                         Environment->addStaticText(k->button_name, rect, false, true, this, -1);
166                 }
167
168                 {
169                         core::rect<s32> rect(0, 0, 100 * s, 30 * s);
170                         rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s);
171                         const wchar_t *text = wgettext(k->key.name());
172                         k->button = GUIButton::addButton(Environment, rect, m_tsrc, this, k->id, text);
173                         delete[] text;
174                 }
175                 if ((i + 1) % KMaxButtonPerColumns == 0) {
176                         offset.X += 260 * s;
177                         offset.Y = 60 * s;
178                 } else {
179                         offset += v2s32(0, 25 * s);
180                 }
181         }
182
183         {
184                 s32 option_x = offset.X;
185                 s32 option_y = offset.Y + 5 * s;
186                 u32 option_w = 180 * s;
187                 {
188                         core::rect<s32> rect(0, 0, option_w, 30 * s);
189                         rect += topleft + v2s32(option_x, option_y);
190                         const wchar_t *text = wgettext("\"Special\" = climb down");
191                         Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
192                                         GUI_ID_CB_AUX1_DESCENDS, text);
193                         delete[] text;
194                 }
195                 offset += v2s32(0, 25 * s);
196         }
197
198         {
199                 s32 option_x = offset.X;
200                 s32 option_y = offset.Y + 5 * s;
201                 u32 option_w = 280 * s;
202                 {
203                         core::rect<s32> rect(0, 0, option_w, 30 * s);
204                         rect += topleft + v2s32(option_x, option_y);
205                         const wchar_t *text = wgettext("Double tap \"jump\" to toggle fly");
206                         Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this,
207                                         GUI_ID_CB_DOUBLETAP_JUMP, text);
208                         delete[] text;
209                 }
210                 offset += v2s32(0, 25 * s);
211         }
212
213         {
214                 s32 option_x = offset.X;
215                 s32 option_y = offset.Y + 5 * s;
216                 u32 option_w = 280;
217                 {
218                         core::rect<s32> rect(0, 0, option_w, 30 * s);
219                         rect += topleft + v2s32(option_x, option_y);
220                         const wchar_t *text = wgettext("Automatic jumping");
221                         Environment->addCheckBox(g_settings->getBool("autojump"), rect, this,
222                                         GUI_ID_CB_AUTOJUMP, text);
223                         delete[] text;
224                 }
225                 offset += v2s32(0, 25);
226         }
227
228         {
229                 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
230                 rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
231                 const wchar_t *text =  wgettext("Save");
232                 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
233                 delete[] text;
234         }
235         {
236                 core::rect<s32> rect(0, 0, 100 * s, 30 * s);
237                 rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
238                 const wchar_t *text = wgettext("Cancel");
239                 GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
240                 delete[] text;
241         }
242 }
243
244 void GUIKeyChangeMenu::drawMenu()
245 {
246         gui::IGUISkin* skin = Environment->getSkin();
247         if (!skin)
248                 return;
249         video::IVideoDriver* driver = Environment->getVideoDriver();
250
251         video::SColor bgcolor(140, 0, 0, 0);
252         driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
253
254         gui::IGUIElement::draw();
255 }
256
257 bool GUIKeyChangeMenu::acceptInput()
258 {
259         for (key_setting *k : key_settings) {
260                 std::string default_key;
261                 g_settings->getDefaultNoEx(k->setting_name, default_key);
262
263                 if (k->key.sym() != default_key)
264                         g_settings->set(k->setting_name, k->key.sym());
265                 else
266                         g_settings->remove(k->setting_name);
267         }
268
269         {
270                 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
271                 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
272                         g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
273         }
274         {
275                 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
276                 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
277                         g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
278         }
279         {
280                 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP);
281                 if(e && e->getType() == gui::EGUIET_CHECK_BOX)
282                         g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
283         }
284
285         clearKeyCache();
286
287         g_gamecallback->signalKeyConfigChange();
288
289         return true;
290 }
291
292 bool GUIKeyChangeMenu::resetMenu()
293 {
294         if (active_key) {
295                 const wchar_t *text = wgettext(active_key->key.name());
296                 active_key->button->setText(text);
297                 delete[] text;
298                 active_key = nullptr;
299                 return false;
300         }
301         return true;
302 }
303 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
304 {
305         if (event.EventType == EET_KEY_INPUT_EVENT && active_key
306                         && event.KeyInput.PressedDown) {
307
308                 bool prefer_character = shift_down;
309                 KeyPress kp(event.KeyInput, prefer_character);
310
311                 if (event.KeyInput.Key == irr::KEY_DELETE)
312                         kp = KeyPress(""); // To erase key settings
313                 else if (event.KeyInput.Key == irr::KEY_ESCAPE)
314                         kp = active_key->key; // Cancel
315
316                 bool shift_went_down = false;
317                 if(!shift_down &&
318                                 (event.KeyInput.Key == irr::KEY_SHIFT ||
319                                 event.KeyInput.Key == irr::KEY_LSHIFT ||
320                                 event.KeyInput.Key == irr::KEY_RSHIFT))
321                         shift_went_down = true;
322
323                 // Display Key already in use message
324                 bool key_in_use = false;
325                 if (strcmp(kp.sym(), "") != 0) {
326                         for (key_setting *ks : key_settings) {
327                                 if (ks != active_key && ks->key == kp) {
328                                         key_in_use = true;
329                                         break;
330                                 }
331                         }
332                 }
333
334                 if (key_in_use && !this->key_used_text) {
335                         core::rect<s32> rect(0, 0, 600, 40);
336                         rect += v2s32(0, 0) + v2s32(25, 30);
337                         const wchar_t *text = wgettext("Key already in use");
338                         this->key_used_text = Environment->addStaticText(text,
339                                         rect, false, true, this, -1);
340                         delete[] text;
341                 } else if (!key_in_use && this->key_used_text) {
342                         this->key_used_text->remove();
343                         this->key_used_text = nullptr;
344                 }
345
346                 // But go on
347                 {
348                         active_key->key = kp;
349                         const wchar_t *text = wgettext(kp.name());
350                         active_key->button->setText(text);
351                         delete[] text;
352
353                         // Allow characters made with shift
354                         if (shift_went_down){
355                                 shift_down = true;
356                                 return false;
357                         }
358
359                         active_key = nullptr;
360                         return true;
361                 }
362         } else if (event.EventType == EET_KEY_INPUT_EVENT && !active_key
363                         && event.KeyInput.PressedDown
364                         && event.KeyInput.Key == irr::KEY_ESCAPE) {
365                 quitMenu();
366                 return true;
367         } else if (event.EventType == EET_GUI_EVENT) {
368                 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
369                         && isVisible())
370                 {
371                         if (!canTakeFocus(event.GUIEvent.Element))
372                         {
373                                 infostream << "GUIKeyChangeMenu: Not allowing focus change."
374                                 << std::endl;
375                                 // Returning true disables focus change
376                                 return true;
377                         }
378                 }
379                 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
380                 {
381                         switch (event.GUIEvent.Caller->getID())
382                         {
383                                 case GUI_ID_BACK_BUTTON: //back
384                                         acceptInput();
385                                         quitMenu();
386                                         return true;
387                                 case GUI_ID_ABORT_BUTTON: //abort
388                                         quitMenu();
389                                         return true;
390                                 default:
391                                         resetMenu();
392                                         for (key_setting *ks : key_settings) {
393                                                 if (ks->id == event.GUIEvent.Caller->getID()) {
394                                                         active_key = ks;
395                                                         break;
396                                                 }
397                                         }
398                                         FATAL_ERROR_IF(!active_key, "Key setting not found");
399
400                                         shift_down = false;
401                                         const wchar_t *text = wgettext("press key");
402                                         active_key->button->setText(text);
403                                         delete[] text;
404                                         break;
405                         }
406                         Environment->setFocus(this);
407                 }
408         }
409         return Parent ? Parent->OnEvent(event) : false;
410 }
411
412 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
413 {
414         key_setting *k = new key_setting;
415         k->id = id;
416
417         k->button_name = button_name;
418         k->setting_name = setting_name;
419         k->key = getKeySetting(k->setting_name.c_str());
420         key_settings.push_back(k);
421 }
422
423 void GUIKeyChangeMenu::init_keys()
424 {
425         this->add_key(GUI_ID_KEY_FORWARD_BUTTON,   wgettext("Forward"),          "keymap_forward");
426         this->add_key(GUI_ID_KEY_BACKWARD_BUTTON,  wgettext("Backward"),         "keymap_backward");
427         this->add_key(GUI_ID_KEY_LEFT_BUTTON,      wgettext("Left"),             "keymap_left");
428         this->add_key(GUI_ID_KEY_RIGHT_BUTTON,     wgettext("Right"),            "keymap_right");
429         this->add_key(GUI_ID_KEY_USE_BUTTON,       wgettext("Special"),          "keymap_special1");
430         this->add_key(GUI_ID_KEY_JUMP_BUTTON,      wgettext("Jump"),             "keymap_jump");
431         this->add_key(GUI_ID_KEY_SNEAK_BUTTON,     wgettext("Sneak"),            "keymap_sneak");
432         this->add_key(GUI_ID_KEY_DROP_BUTTON,      wgettext("Drop"),             "keymap_drop");
433         this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"),        "keymap_inventory");
434         this->add_key(GUI_ID_KEY_ENDERCHEST_BUTTON,wgettext("Enderchest"),               "keymap_enderchest");
435         this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,wgettext("Prev. item"),      "keymap_hotbar_previous");
436         this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,wgettext("Next item"),       "keymap_hotbar_next");
437         this->add_key(GUI_ID_KEY_ZOOM_BUTTON,      wgettext("Zoom"),             "keymap_zoom");
438         this->add_key(GUI_ID_KEY_CAMERA_BUTTON,    wgettext("Change camera"),    "keymap_camera_mode");
439         this->add_key(GUI_ID_KEY_MINIMAP_BUTTON,   wgettext("Toggle minimap"),   "keymap_minimap");
440         this->add_key(GUI_ID_KEY_FLY_BUTTON,       wgettext("Toggle fly"),       "keymap_freemove");
441         this->add_key(GUI_ID_KEY_PITCH_MOVE,       wgettext("Toggle pitchmove"), "keymap_pitchmove");
442         this->add_key(GUI_ID_KEY_FAST_BUTTON,      wgettext("Toggle fast"),      "keymap_fastmove");
443         this->add_key(GUI_ID_KEY_NOCLIP_BUTTON,    wgettext("Toggle noclip"),    "keymap_noclip");
444         this->add_key(GUI_ID_KEY_MUTE_BUTTON,      wgettext("Mute"),             "keymap_mute");
445         this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON,wgettext("Dec. volume"),      "keymap_decrease_volume");
446         this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON,wgettext("Inc. volume"),      "keymap_increase_volume");
447         this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON,   wgettext("Autoforward"),      "keymap_autoforward");
448         this->add_key(GUI_ID_KEY_CHAT_BUTTON,      wgettext("Chat"),             "keymap_chat");
449         this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON,wgettext("Screenshot"),       "keymap_screenshot");
450         this->add_key(GUI_ID_KEY_RANGE_BUTTON,     wgettext("Range select"),     "keymap_rangeselect");
451         this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"),       "keymap_decrease_viewing_range_min");
452         this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"),       "keymap_increase_viewing_range_min");
453         this->add_key(GUI_ID_KEY_CONSOLE_BUTTON,   wgettext("Console"),          "keymap_console");
454         this->add_key(GUI_ID_KEY_CMD_BUTTON,       wgettext("Command"),          "keymap_cmd");
455         this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"),    "keymap_cmd_local");
456         this->add_key(GUI_ID_KEY_HUD_BUTTON,       wgettext("Toggle HUD"),       "keymap_toggle_hud");
457         this->add_key(GUI_ID_KEY_CHATLOG_BUTTON,   wgettext("Toggle chat log"),  "keymap_toggle_chat");
458         this->add_key(GUI_ID_KEY_FOG_BUTTON,       wgettext("Toggle fog"),       "keymap_toggle_fog");
459         this->add_key(GUI_ID_KEY_CHEAT_MENU_BUTTON,wgettext("Toggle C. Menu"),"keymap_toggle_cheat_menu");
460         this->add_key(GUI_ID_KEY_KILLAURA_BUTTON,  wgettext("Killaura"),  "keymap_toggle_killaura");
461         this->add_key(GUI_ID_KEY_FREECAM_BUTTON,   wgettext("Freecam"),    "keymap_toggle_freecam");
462         this->add_key(GUI_ID_KEY_SCAFFOLD_BUTTON,  wgettext("Scaffold"),    "keymap_toggle_scaffold");
463         this->add_key(GUI_ID_KEY_SELECT_UP_BUTTON, wgettext("C. Menu Up"),    "keymap_select_up");
464         this->add_key(GUI_ID_KEY_SELECT_DOWN_BUTTON,wgettext("C. Menu Down"), "keymap_select_down");
465         this->add_key(GUI_ID_KEY_SELECT_LEFT_BUTTON,wgettext("C. Menu Left"), "keymap_select_left");
466         this->add_key(GUI_ID_KEY_SELECT_RIGHT_BUTTON,wgettext("C. Menu Right"),"keymap_select_right");
467         this->add_key(GUI_ID_KEY_SELECT_CONFIRM_BUTTON,wgettext("C. Menu Enter"),"keymap_select_confirm");
468 }