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