]> git.lizzy.rs Git - minetest.git/blob - src/guiKeyChangeMenu.cpp
Fix msvc2012 build
[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 "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         
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 }
201
202 void GUIKeyChangeMenu::drawMenu()
203 {
204         gui::IGUISkin* skin = Environment->getSkin();
205         if (!skin)
206                 return;
207         video::IVideoDriver* driver = Environment->getVideoDriver();
208
209         video::SColor bgcolor(140, 0, 0, 0);
210
211         {
212                 core::rect < s32 > rect(0, 0, 620, 620);
213                 rect += AbsoluteRect.UpperLeftCorner;
214                 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
215         }
216
217         gui::IGUIElement::draw();
218 }
219
220 bool GUIKeyChangeMenu::acceptInput()
221 {
222         for(size_t i = 0; i < key_settings.size(); i++)
223         {
224                 key_setting *k = key_settings.at(i);
225                 g_settings->set(k->setting_name, k->key.sym());
226         }
227         {
228                 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
229                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
230                         g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
231         }
232         {
233                 gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
234                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
235                         g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
236         }
237         clearKeyCache();
238         return true;
239 }
240
241 bool GUIKeyChangeMenu::resetMenu()
242 {
243         if (activeKey >= 0)
244         {
245                 for(size_t i = 0; i < key_settings.size(); i++)
246                 {
247                         key_setting *k = key_settings.at(i);
248                         if(k->id == activeKey)
249                         {
250                                 wchar_t* text = wgettext(k->key.name());
251                                 k->button->setText(text);
252                                 delete[] text;
253                                 break;
254                         }
255                 }
256                 activeKey = -1;
257                 return false;
258         }
259         return true;
260 }
261 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
262 {
263         if (event.EventType == EET_KEY_INPUT_EVENT && activeKey >= 0
264                 && event.KeyInput.PressedDown)
265         {
266                 
267                 bool prefer_character = shift_down;
268                 KeyPress kp(event.KeyInput, prefer_character);
269                 
270                 bool shift_went_down = false;
271                 if(!shift_down &&
272                                 (event.KeyInput.Key == irr::KEY_SHIFT ||
273                                 event.KeyInput.Key == irr::KEY_LSHIFT ||
274                                 event.KeyInput.Key == irr::KEY_RSHIFT))
275                         shift_went_down = true;
276
277                 // Remove Key already in use message
278                 if(this->key_used_text)
279                 {
280                         this->key_used_text->remove();
281                         this->key_used_text = NULL;
282                 }
283                 // Display Key already in use message
284                 if (std::find(this->key_used.begin(), this->key_used.end(), kp) != this->key_used.end())
285                 {
286                         core::rect < s32 > rect(0, 0, 600, 40);
287                         rect += v2s32(0, 0) + v2s32(25, 30);
288                         wchar_t* text = wgettext("Key already in use");
289                         this->key_used_text = Environment->addStaticText(text,
290                                                                         rect, false, true, this, -1);
291                         delete[] text;
292                         //infostream << "Key already in use" << std::endl;
293                 }
294
295                 // But go on
296                 {
297                         key_setting *k=NULL;
298                         for(size_t i = 0; i < key_settings.size(); i++)
299                         {
300                                 if(key_settings.at(i)->id == activeKey)
301                                 {
302                                         k = key_settings.at(i);
303                                         break;
304                                 }
305                         }
306                         assert(k);
307                         k->key = kp;
308                         wchar_t* text = wgettext(k->key.name());
309                         k->button->setText(text);
310                         delete[] text;
311
312                         this->key_used.push_back(kp);
313
314                         // Allow characters made with shift
315                         if(shift_went_down){
316                                 shift_down = true;
317                                 return false;
318                         }else{
319                                 activeKey = -1;
320                                 return true;
321                         }
322                 }
323         }
324         if (event.EventType == EET_GUI_EVENT)
325         {
326                 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
327                         && isVisible())
328                 {
329                         if (!canTakeFocus(event.GUIEvent.Element))
330                         {
331                                 dstream << "GUIMainMenu: Not allowing focus change."
332                                 << std::endl;
333                                 // Returning true disables focus change
334                                 return true;
335                         }
336                 }
337                 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
338                 {
339                         switch (event.GUIEvent.Caller->getID())
340                         {
341                                 case GUI_ID_BACK_BUTTON: //back
342                                         acceptInput();
343                                         quitMenu();
344                                         return true;
345                                 case GUI_ID_ABORT_BUTTON: //abort
346                                         quitMenu();
347                                         return true;
348                                 default:
349                                         key_setting *k = NULL;
350                                         for(size_t i = 0; i < key_settings.size(); i++)
351                                         {
352                                                 if(key_settings.at(i)->id == event.GUIEvent.Caller->getID())
353                                                 {
354                                                         k = key_settings.at(i);
355                                                         break;
356                                                 }
357                                         }
358                                         assert(k);
359
360                                         resetMenu();
361                                         shift_down = false;
362                                         activeKey = event.GUIEvent.Caller->getID();
363                                         wchar_t* text = wgettext("press key");
364                                         k->button->setText(text);
365                                         delete[] text;
366                                         this->key_used.erase(std::remove(this->key_used.begin(),
367                                                         this->key_used.end(), k->key), this->key_used.end());
368                                         break;
369                         }
370                         Environment->setFocus(this);
371                 }
372         }
373         return Parent ? Parent->OnEvent(event) : false;
374 }
375
376 void GUIKeyChangeMenu::add_key(int id, wchar_t* button_name, std::string setting_name)
377 {
378         key_setting *k = new key_setting;
379         k->id = id;
380
381         k->button_name = button_name;
382         k->setting_name = setting_name;
383         k->key = getKeySetting(k->setting_name.c_str());
384         key_settings.push_back(k);
385 }
386
387 void GUIKeyChangeMenu::init_keys()
388 {
389         this->add_key(GUI_ID_KEY_FORWARD_BUTTON,   wgettext("Forward"),       "keymap_forward");
390         this->add_key(GUI_ID_KEY_BACKWARD_BUTTON,  wgettext("Backward"),      "keymap_backward");
391         this->add_key(GUI_ID_KEY_LEFT_BUTTON,      wgettext("Left"),          "keymap_left");
392         this->add_key(GUI_ID_KEY_RIGHT_BUTTON,     wgettext("Right"),         "keymap_right");
393         this->add_key(GUI_ID_KEY_USE_BUTTON,       wgettext("Use"),           "keymap_special1");
394         this->add_key(GUI_ID_KEY_JUMP_BUTTON,      wgettext("Jump"),          "keymap_jump");
395         this->add_key(GUI_ID_KEY_SNEAK_BUTTON,     wgettext("Sneak"),         "keymap_sneak");
396         this->add_key(GUI_ID_KEY_DROP_BUTTON,      wgettext("Drop"),          "keymap_drop");
397         this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"),     "keymap_inventory");
398         this->add_key(GUI_ID_KEY_CHAT_BUTTON,      wgettext("Chat"),          "keymap_chat");
399         this->add_key(GUI_ID_KEY_CMD_BUTTON,       wgettext("Command"),       "keymap_cmd");
400         this->add_key(GUI_ID_KEY_CONSOLE_BUTTON,   wgettext("Console"),       "keymap_console");
401         this->add_key(GUI_ID_KEY_FLY_BUTTON,       wgettext("Toggle fly"),    "keymap_freemove");
402         this->add_key(GUI_ID_KEY_FAST_BUTTON,      wgettext("Toggle fast"),   "keymap_fastmove");
403         this->add_key(GUI_ID_KEY_NOCLIP_BUTTON,    wgettext("Toggle noclip"), "keymap_noclip");
404         this->add_key(GUI_ID_KEY_RANGE_BUTTON,     wgettext("Range select"),  "keymap_rangeselect");
405         this->add_key(GUI_ID_KEY_DUMP_BUTTON,      wgettext("Print stacks"),  "keymap_print_debug_stacks");
406 }