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