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