]> git.lizzy.rs Git - dragonfireclient.git/blob - src/guiKeyChangeMenu.cpp
Add camera smoothing and cinematic mode (F8)
[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 #include "mainmenumanager.h"  // for g_gamecallback
36
37 #define KMaxButtonPerColumns 12
38
39 extern MainGameCallback *g_gamecallback;
40
41 enum
42 {
43         GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR,
44         // buttons
45         GUI_ID_KEY_FORWARD_BUTTON,
46         GUI_ID_KEY_BACKWARD_BUTTON,
47         GUI_ID_KEY_LEFT_BUTTON,
48         GUI_ID_KEY_RIGHT_BUTTON,
49         GUI_ID_KEY_USE_BUTTON,
50         GUI_ID_KEY_FLY_BUTTON,
51         GUI_ID_KEY_FAST_BUTTON,
52         GUI_ID_KEY_JUMP_BUTTON,
53         GUI_ID_KEY_NOCLIP_BUTTON,
54         GUI_ID_KEY_CINEMATIC_BUTTON,
55         GUI_ID_KEY_CHAT_BUTTON,
56         GUI_ID_KEY_CMD_BUTTON,
57         GUI_ID_KEY_CONSOLE_BUTTON,
58         GUI_ID_KEY_SNEAK_BUTTON,
59         GUI_ID_KEY_DROP_BUTTON,
60         GUI_ID_KEY_INVENTORY_BUTTON,
61         GUI_ID_KEY_DUMP_BUTTON,
62         GUI_ID_KEY_RANGE_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, 110, 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 - 100 - 20, 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 - 100 - 20 - 100 - 20, 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                 
276                 bool prefer_character = shift_down;
277                 KeyPress kp(event.KeyInput, prefer_character);
278                 
279                 bool shift_went_down = false;
280                 if(!shift_down &&
281                                 (event.KeyInput.Key == irr::KEY_SHIFT ||
282                                 event.KeyInput.Key == irr::KEY_LSHIFT ||
283                                 event.KeyInput.Key == irr::KEY_RSHIFT))
284                         shift_went_down = true;
285
286                 // Remove Key already in use message
287                 if(this->key_used_text)
288                 {
289                         this->key_used_text->remove();
290                         this->key_used_text = NULL;
291                 }
292                 // Display Key already in use message
293                 if (std::find(this->key_used.begin(), this->key_used.end(), kp) != this->key_used.end())
294                 {
295                         core::rect < s32 > rect(0, 0, 600, 40);
296                         rect += v2s32(0, 0) + v2s32(25, 30);
297                         const wchar_t *text = wgettext("Key already in use");
298                         this->key_used_text = Environment->addStaticText(text,
299                                         rect, false, true, this, -1);
300                         delete[] text;
301                         //infostream << "Key already in use" << std::endl;
302                 }
303
304                 // But go on
305                 {
306                         key_setting *k=NULL;
307                         for(size_t i = 0; i < key_settings.size(); i++)
308                         {
309                                 if(key_settings.at(i)->id == activeKey)
310                                 {
311                                         k = key_settings.at(i);
312                                         break;
313                                 }
314                         }
315                         assert(k);
316                         k->key = kp;
317                         const wchar_t *text = wgettext(k->key.name());
318                         k->button->setText(text);
319                         delete[] text;
320
321                         this->key_used.push_back(kp);
322
323                         // Allow characters made with shift
324                         if(shift_went_down){
325                                 shift_down = true;
326                                 return false;
327                         }else{
328                                 activeKey = -1;
329                                 return true;
330                         }
331                 }
332         }
333         if (event.EventType == EET_GUI_EVENT)
334         {
335                 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
336                         && isVisible())
337                 {
338                         if (!canTakeFocus(event.GUIEvent.Element))
339                         {
340                                 dstream << "GUIMainMenu: Not allowing focus change."
341                                 << std::endl;
342                                 // Returning true disables focus change
343                                 return true;
344                         }
345                 }
346                 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
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                                         const 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                 }
381         }
382         return Parent ? Parent->OnEvent(event) : false;
383 }
384
385 void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::string &setting_name)
386 {
387         key_setting *k = new key_setting;
388         k->id = id;
389
390         k->button_name = button_name;
391         k->setting_name = setting_name;
392         k->key = getKeySetting(k->setting_name.c_str());
393         key_settings.push_back(k);
394 }
395
396 void GUIKeyChangeMenu::init_keys()
397 {
398         this->add_key(GUI_ID_KEY_FORWARD_BUTTON,   wgettext("Forward"),          "keymap_forward");
399         this->add_key(GUI_ID_KEY_BACKWARD_BUTTON,  wgettext("Backward"),         "keymap_backward");
400         this->add_key(GUI_ID_KEY_LEFT_BUTTON,      wgettext("Left"),             "keymap_left");
401         this->add_key(GUI_ID_KEY_RIGHT_BUTTON,     wgettext("Right"),            "keymap_right");
402         this->add_key(GUI_ID_KEY_USE_BUTTON,       wgettext("Use"),              "keymap_special1");
403         this->add_key(GUI_ID_KEY_JUMP_BUTTON,      wgettext("Jump"),             "keymap_jump");
404         this->add_key(GUI_ID_KEY_SNEAK_BUTTON,     wgettext("Sneak"),            "keymap_sneak");
405         this->add_key(GUI_ID_KEY_DROP_BUTTON,      wgettext("Drop"),             "keymap_drop");
406         this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"),        "keymap_inventory");
407         this->add_key(GUI_ID_KEY_CHAT_BUTTON,      wgettext("Chat"),             "keymap_chat");
408         this->add_key(GUI_ID_KEY_CMD_BUTTON,       wgettext("Command"),          "keymap_cmd");
409         this->add_key(GUI_ID_KEY_CONSOLE_BUTTON,   wgettext("Console"),          "keymap_console");
410         this->add_key(GUI_ID_KEY_FLY_BUTTON,       wgettext("Toggle fly"),       "keymap_freemove");
411         this->add_key(GUI_ID_KEY_FAST_BUTTON,      wgettext("Toggle fast"),      "keymap_fastmove");
412         this->add_key(GUI_ID_KEY_CINEMATIC_BUTTON, wgettext("Toggle Cinematic"), "keymap_cinematic");
413         this->add_key(GUI_ID_KEY_NOCLIP_BUTTON,    wgettext("Toggle noclip"),    "keymap_noclip");
414         this->add_key(GUI_ID_KEY_RANGE_BUTTON,     wgettext("Range select"),     "keymap_rangeselect");
415         this->add_key(GUI_ID_KEY_DUMP_BUTTON,      wgettext("Print stacks"),     "keymap_print_debug_stacks");
416 }
417