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