]> git.lizzy.rs Git - dragonfireclient.git/blob - src/guiKeyChangeMenu.cpp
A bunch of GUIKeyChangeMenu fixes
[dragonfireclient.git] / src / guiKeyChangeMenu.cpp
1 /*
2  Minetest-c55
3  Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
4  Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
5  Copyright (C) 2011 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_CHAT_BUTTON,
50         GUI_ID_KEY_CMD_BUTTON,
51         GUI_ID_KEY_CONSOLE_BUTTON,
52         GUI_ID_KEY_SNEAK_BUTTON,
53         GUI_ID_KEY_DROP_BUTTON,
54         GUI_ID_KEY_INVENTORY_BUTTON,
55         GUI_ID_KEY_DUMP_BUTTON,
56         GUI_ID_KEY_RANGE_BUTTON
57 };
58
59 GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
60                                 gui::IGUIElement* parent, s32 id, IMenuManager *menumgr) :
61 GUIModalMenu(env, parent, id, menumgr)
62 {
63         activeKey = -1;
64         this->key_used_text = NULL;
65         init_keys();
66         for(size_t i=0; i<key_settings.size(); i++)
67                 this->key_used.push_back(key_settings.at(i)->key);
68 }
69
70 GUIKeyChangeMenu::~GUIKeyChangeMenu()
71 {
72         removeChildren();
73 }
74
75 void GUIKeyChangeMenu::removeChildren()
76 {
77         const core::list<gui::IGUIElement*> &children = getChildren();
78         core::list<gui::IGUIElement*> children_copy;
79         for (core::list<gui::IGUIElement*>::ConstIterator i = children.begin(); i
80                  != children.end(); i++)
81         {
82                 children_copy.push_back(*i);
83         }
84         for (core::list<gui::IGUIElement*>::Iterator i = children_copy.begin(); i
85                  != children_copy.end(); i++)
86         {
87                 (*i)->remove();
88         }
89 }
90
91 void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
92 {
93         removeChildren();
94         v2s32 size(620, 430);
95         
96         core::rect < s32 > rect(screensize.X / 2 - size.X / 2,
97                                                         screensize.Y / 2 - size.Y / 2, screensize.X / 2 + size.X / 2,
98                                                         screensize.Y / 2 + size.Y / 2);
99
100         DesiredRect = rect;
101         recalculateAbsolutePosition(false);
102
103         v2s32 topleft(0, 0);
104         changeCtype("");
105         {
106                 core::rect < s32 > rect(0, 0, 600, 40);
107                 rect += topleft + v2s32(25, 3);
108                 //gui::IGUIStaticText *t =
109                 Environment->addStaticText(wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)"),
110                                                                    rect, false, true, this, -1);
111                 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
112         }
113
114         // Build buttons
115
116         v2s32 offset(25, 60);
117
118         for(size_t i = 0; i < key_settings.size(); i++)
119         {
120                 key_setting *k = key_settings.at(i);
121                 {
122                         core::rect < s32 > rect(0, 0, 100, 20);
123                         rect += topleft + v2s32(offset.X, offset.Y);
124                         Environment->addStaticText(k->button_name, rect, false, true, this, -1);
125                 }
126
127                 {
128                         core::rect < s32 > rect(0, 0, 100, 30);
129                         rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
130                         k->button = Environment->addButton(rect, this, k->id, wgettext(k->key.name()));
131                 }
132                 if(i + 1 == KMaxButtonPerColumns)
133                         offset = v2s32(250, 60);
134                 else
135                         offset += v2s32(0, 25);
136         }
137
138         {
139                 core::rect < s32 > rect(0, 0, 100, 30);
140                 rect += topleft + v2s32(size.X - 100 - 20, size.Y - 40);
141                 Environment->addButton(rect, this, GUI_ID_BACK_BUTTON,
142                                                            wgettext("Save"));
143         }
144         {
145                 core::rect < s32 > rect(0, 0, 100, 30);
146                 rect += topleft + v2s32(size.X - 100 - 20 - 100 - 20, size.Y - 40);
147                 Environment->addButton(rect, this, GUI_ID_ABORT_BUTTON,
148                                                            wgettext("Cancel"));
149         }
150         changeCtype("C");
151         
152 }
153
154 void GUIKeyChangeMenu::drawMenu()
155 {
156         gui::IGUISkin* skin = Environment->getSkin();
157         if (!skin)
158                 return;
159         video::IVideoDriver* driver = Environment->getVideoDriver();
160
161         video::SColor bgcolor(140, 0, 0, 0);
162
163         {
164                 core::rect < s32 > rect(0, 0, 620, 620);
165                 rect += AbsoluteRect.UpperLeftCorner;
166                 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
167         }
168
169         gui::IGUIElement::draw();
170 }
171
172 bool GUIKeyChangeMenu::acceptInput()
173 {
174         for(size_t i = 0; i < key_settings.size(); i++)
175         {
176                 key_setting *k = key_settings.at(i);
177                 g_settings->set(k->setting_name, k->key.sym());
178         }
179         clearKeyCache();
180         return true;
181 }
182
183 bool GUIKeyChangeMenu::resetMenu()
184 {
185         if (activeKey >= 0)
186         {
187                 for(size_t i = 0; i < key_settings.size(); i++)
188                 {
189                         key_setting *k = key_settings.at(i);
190                         if(k->id == activeKey)
191                         {
192                                 k->button->setText(wgettext(k->key.name()));
193                                 break;
194                         }
195                 }
196                 activeKey = -1;
197                 return false;
198         }
199         return true;
200 }
201 bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
202 {
203         if (event.EventType == EET_KEY_INPUT_EVENT && activeKey >= 0
204                 && event.KeyInput.PressedDown)
205         {
206                 changeCtype("");
207                 KeyPress kp(event.KeyInput);
208
209                 // Remove Key already in use message
210                 if(this->key_used_text)
211                 {
212                         this->key_used_text->remove();
213                         this->key_used_text = NULL;
214                 }
215                 // Display Key already in use message
216                 if (std::find(this->key_used.begin(), this->key_used.end(), kp) != this->key_used.end())
217                 {
218                         core::rect < s32 > rect(0, 0, 600, 40);
219                         rect += v2s32(0, 0) + v2s32(25, 30);
220                         this->key_used_text = Environment->addStaticText(wgettext("Key already in use"),
221                                                                         rect, false, true, this, -1);
222                         //infostream << "Key already in use" << std::endl;
223                 }
224
225                 // But go on
226                 {
227                         key_setting *k=NULL;
228                         for(size_t i = 0; i < key_settings.size(); i++)
229                         {
230                                 if(key_settings.at(i)->id == activeKey)
231                                 {
232                                         k = key_settings.at(i);
233                                         break;
234                                 }
235                         }
236                         assert(k);
237                         k->key = kp;
238                         k->button->setText(wgettext(k->key.name()));
239
240                         this->key_used.push_back(kp);
241
242                         changeCtype("C");
243                         activeKey = -1;
244                         return true;
245                 }
246         }
247         if (event.EventType == EET_GUI_EVENT)
248         {
249                 if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
250                         && isVisible())
251                 {
252                         if (!canTakeFocus(event.GUIEvent.Element))
253                         {
254                                 dstream << "GUIMainMenu: Not allowing focus change."
255                                 << std::endl;
256                                 // Returning true disables focus change
257                                 return true;
258                         }
259                 }
260                 if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
261                 {
262                         if(event.GUIEvent.Caller->getID() != GUI_ID_BACK_BUTTON &&
263                            event.GUIEvent.Caller->getID() != GUI_ID_ABORT_BUTTON)
264                         {
265                                 changeCtype("");
266                         }
267
268                         switch (event.GUIEvent.Caller->getID())
269                         {
270                                 case GUI_ID_BACK_BUTTON: //back
271                                         acceptInput();
272                                         quitMenu();
273                                         return true;
274                                 case GUI_ID_ABORT_BUTTON: //abort
275                                         quitMenu();
276                                         return true;
277                                 default:
278                                         key_setting *k = NULL;
279                                         for(size_t i = 0; i < key_settings.size(); i++)
280                                         {
281                                                 if(key_settings.at(i)->id == event.GUIEvent.Caller->getID())
282                                                 {
283                                                         k = key_settings.at(i);
284                                                         break;
285                                                 }
286                                         }
287                                         assert(k);
288
289                                         resetMenu();
290                                         activeKey = event.GUIEvent.Caller->getID();
291                                         k->button->setText(wgettext("press key"));
292                                         this->key_used.erase(std::remove(this->key_used.begin(),
293                                                         this->key_used.end(), k->key), this->key_used.end());
294                                         break;
295                         }
296                         Environment->setFocus(this);
297                         //Buttons
298                         changeCtype("C");
299                 }
300         }
301         return Parent ? Parent->OnEvent(event) : false;
302 }
303
304 void GUIKeyChangeMenu::add_key(int id, std::string button_name, std::string setting_name)
305 {
306         key_setting *k = new key_setting;
307         k->id = id;
308         k->button_name = wgettext(button_name.c_str());
309         k->setting_name = setting_name;
310         k->key = getKeySetting(k->setting_name.c_str());
311         key_settings.push_back(k);
312 }
313
314 void GUIKeyChangeMenu::init_keys()
315 {
316         this->add_key(GUI_ID_KEY_FORWARD_BUTTON, "Forward", "keymap_forward");
317         this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, "Backward", "keymap_backward");
318         this->add_key(GUI_ID_KEY_LEFT_BUTTON, "Left", "keymap_left");
319         this->add_key(GUI_ID_KEY_RIGHT_BUTTON, "Right", "keymap_right");
320         this->add_key(GUI_ID_KEY_USE_BUTTON, "Use", "keymap_special1");
321         this->add_key(GUI_ID_KEY_JUMP_BUTTON, "Jump", "keymap_jump");
322         this->add_key(GUI_ID_KEY_SNEAK_BUTTON, "Sneak", "keymap_sneak");
323         this->add_key(GUI_ID_KEY_DROP_BUTTON, "Drop", "keymap_drop");
324         this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, "Inventory", "keymap_inventory");
325         this->add_key(GUI_ID_KEY_CHAT_BUTTON, "Chat", "keymap_chat");
326         this->add_key(GUI_ID_KEY_CMD_BUTTON, "Command", "keymap_cmd");
327         this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, "Console", "keymap_console");
328         this->add_key(GUI_ID_KEY_FLY_BUTTON, "Toggle fly", "keymap_freemove");
329         this->add_key(GUI_ID_KEY_FAST_BUTTON, "Toggle fast", "keymap_fastmove");
330         this->add_key(GUI_ID_KEY_RANGE_BUTTON, "Range select", "keymap_rangeselect");
331         this->add_key(GUI_ID_KEY_DUMP_BUTTON, "Print stacks", "keymap_print_debug_stacks");
332 }