]> git.lizzy.rs Git - dragonfireclient.git/blob - src/guiKeyChangeMenu.cpp
Fix for cropped text "Toggle Cinematic"
[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, 150, 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 / 2 - 105, 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 / 2 + 5, 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                 bool prefer_character = shift_down;
275                 KeyPress kp(event.KeyInput, prefer_character);
276                 
277                 bool shift_went_down = false;
278                 if(!shift_down &&
279                                 (event.KeyInput.Key == irr::KEY_SHIFT ||
280                                 event.KeyInput.Key == irr::KEY_LSHIFT ||
281                                 event.KeyInput.Key == irr::KEY_RSHIFT))
282                         shift_went_down = true;
283
284                 // Remove Key already in use message
285                 if(this->key_used_text)
286                 {
287                         this->key_used_text->remove();
288                         this->key_used_text = NULL;
289                 }
290                 // Display Key already in use message
291                 if (std::find(this->key_used.begin(), this->key_used.end(), kp) != this->key_used.end())
292                 {
293                         core::rect < s32 > rect(0, 0, 600, 40);
294                         rect += v2s32(0, 0) + v2s32(25, 30);
295                         const wchar_t *text = wgettext("Key already in use");
296                         this->key_used_text = Environment->addStaticText(text,
297                                         rect, false, true, this, -1);
298                         delete[] text;
299                         //infostream << "Key already in use" << std::endl;
300                 }
301
302                 // But go on
303                 {
304                         key_setting *k = NULL;
305                         for(size_t i = 0; i < key_settings.size(); i++)
306                         {
307                                 if(key_settings.at(i)->id == activeKey)
308                                 {
309                                         k = key_settings.at(i);
310                                         break;
311                                 }
312                         }
313                         FATAL_ERROR_IF(k == NULL, "Key setting not found");
314                         k->key = kp;
315                         const wchar_t *text = wgettext(k->key.name());
316                         k->button->setText(text);
317                         delete[] text;
318
319                         this->key_used.push_back(kp);
320
321                         // Allow characters made with shift
322                         if(shift_went_down){
323                                 shift_down = true;
324                                 return false;
325                         }else{
326                                 activeKey = -1;
327                                 return true;
328                         }
329                 }
330         } else if (event.EventType == EET_KEY_INPUT_EVENT && activeKey < 0
331                         && event.KeyInput.PressedDown
332                         && event.KeyInput.Key == irr::KEY_ESCAPE) {
333                 quitMenu();
334                 return true;
335         } else if (event.EventType == EET_GUI_EVENT) {
336                 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
337                         && isVisible())
338                 {
339                         if (!canTakeFocus(event.GUIEvent.Element))
340                         {
341                                 dstream << "GUIMainMenu: Not allowing focus change."
342                                 << std::endl;
343                                 // Returning true disables focus change
344                                 return true;
345                         }
346                 }
347                 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
348                 {
349                         switch (event.GUIEvent.Caller->getID())
350                         {
351                                 case GUI_ID_BACK_BUTTON: //back
352                                         acceptInput();
353                                         quitMenu();
354                                         return true;
355                                 case GUI_ID_ABORT_BUTTON: //abort
356                                         quitMenu();
357                                         return true;
358                                 default:
359                                         key_setting *k = NULL;
360                                         for(size_t i = 0; i < key_settings.size(); i++)
361                                         {
362                                                 if(key_settings.at(i)->id == event.GUIEvent.Caller->getID())
363                                                 {
364                                                         k = key_settings.at(i);
365                                                         break;
366                                                 }
367                                         }
368                                         FATAL_ERROR_IF(k == NULL, "Key setting not found");
369
370                                         resetMenu();
371                                         shift_down = false;
372                                         activeKey = event.GUIEvent.Caller->getID();
373                                         const wchar_t *text = wgettext("press key");
374                                         k->button->setText(text);
375                                         delete[] text;
376                                         this->key_used.erase(std::remove(this->key_used.begin(),
377                                                         this->key_used.end(), k->key), this->key_used.end());
378                                         break;
379                         }
380                         Environment->setFocus(this);
381                 }
382         }
383         return Parent ? Parent->OnEvent(event) : false;
384 }
385
386 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
387 {
388         key_setting *k = new key_setting;
389         k->id = id;
390
391         k->button_name = button_name;
392         k->setting_name = setting_name;
393         k->key = getKeySetting(k->setting_name.c_str());
394         key_settings.push_back(k);
395 }
396
397 void GUIKeyChangeMenu::init_keys()
398 {
399         this->add_key(GUI_ID_KEY_FORWARD_BUTTON,   wgettext("Forward"),          "keymap_forward");
400         this->add_key(GUI_ID_KEY_BACKWARD_BUTTON,  wgettext("Backward"),         "keymap_backward");
401         this->add_key(GUI_ID_KEY_LEFT_BUTTON,      wgettext("Left"),             "keymap_left");
402         this->add_key(GUI_ID_KEY_RIGHT_BUTTON,     wgettext("Right"),            "keymap_right");
403         this->add_key(GUI_ID_KEY_USE_BUTTON,       wgettext("Use"),              "keymap_special1");
404         this->add_key(GUI_ID_KEY_JUMP_BUTTON,      wgettext("Jump"),             "keymap_jump");
405         this->add_key(GUI_ID_KEY_SNEAK_BUTTON,     wgettext("Sneak"),            "keymap_sneak");
406         this->add_key(GUI_ID_KEY_DROP_BUTTON,      wgettext("Drop"),             "keymap_drop");
407         this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"),        "keymap_inventory");
408         this->add_key(GUI_ID_KEY_CHAT_BUTTON,      wgettext("Chat"),             "keymap_chat");
409         this->add_key(GUI_ID_KEY_CMD_BUTTON,       wgettext("Command"),          "keymap_cmd");
410         this->add_key(GUI_ID_KEY_CONSOLE_BUTTON,   wgettext("Console"),          "keymap_console");
411         this->add_key(GUI_ID_KEY_FLY_BUTTON,       wgettext("Toggle fly"),       "keymap_freemove");
412         this->add_key(GUI_ID_KEY_FAST_BUTTON,      wgettext("Toggle fast"),      "keymap_fastmove");
413         this->add_key(GUI_ID_KEY_CINEMATIC_BUTTON, wgettext("Toggle Cinematic"), "keymap_cinematic");
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 }
418