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