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