Remove duplicate code in main menu
[oweals/minetest.git] / src / guiMainMenu.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "guiMainMenu.h"
21 #include "guiKeyChangeMenu.h"
22 #include "debug.h"
23 #include "serialization.h"
24 #include <string>
25 #include <IGUICheckBox.h>
26 #include <IGUIEditBox.h>
27 #include <IGUIButton.h>
28 #include <IGUIStaticText.h>
29 #include <IGUIFont.h>
30 #include <IGUIListBox.h>
31
32
33 #include "gettext.h"
34
35 GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env,
36                 gui::IGUIElement* parent, s32 id,
37                 IMenuManager *menumgr,
38                 MainMenuData *data,
39                 IGameCallback *gamecallback
40 ):
41         GUIModalMenu(env, parent, id, menumgr),
42         m_data(data),
43         m_accepted(false),
44         m_gamecallback(gamecallback)
45 {
46         assert(m_data);
47         this->env = env;
48         this->parent = parent;
49         this->id = id;
50         this->menumgr = menumgr;
51 }
52
53 GUIMainMenu::~GUIMainMenu()
54 {
55         removeChildren();
56 }
57
58 void GUIMainMenu::removeChildren()
59 {
60         const core::list<gui::IGUIElement*> &children = getChildren();
61         core::list<gui::IGUIElement*> children_copy;
62         for(core::list<gui::IGUIElement*>::ConstIterator
63                         i = children.begin(); i != children.end(); i++)
64         {
65                 children_copy.push_back(*i);
66         }
67         for(core::list<gui::IGUIElement*>::Iterator
68                         i = children_copy.begin();
69                         i != children_copy.end(); i++)
70         {
71                 (*i)->remove();
72         }
73 }
74
75 void GUIMainMenu::regenerateGui(v2u32 screensize)
76 {
77         /*
78                 Read stuff from elements into m_data
79         */
80         readInput(m_data);
81         
82         /*
83                 Remove stuff
84         */
85         removeChildren();
86         
87         /*
88                 Calculate new sizes and positions
89         */
90         
91         v2s32 size(620, 430);
92
93         core::rect<s32> rect(
94                         screensize.X/2 - size.X/2,
95                         screensize.Y/2 - size.Y/2,
96                         screensize.X/2 + size.X/2,
97                         screensize.Y/2 + size.Y/2
98         );
99
100         DesiredRect = rect;
101         recalculateAbsolutePosition(false);
102
103         //v2s32 size = rect.getSize();
104
105         /*
106                 Add stuff
107         */
108
109         /*
110                 Client section
111         */
112
113         v2s32 topleft_client(40, 0);
114         v2s32 size_client = size - v2s32(40, 0);
115         
116         changeCtype("");
117         
118         // Version
119         {
120                 core::rect<s32> rect(0, 0, 300, 30);
121                 rect += topleft_client + v2s32(-36, 0);
122                 Environment->addStaticText(narrow_to_wide(VERSION_STRING).c_str(), 
123                         rect, false, true, this, -1);
124         }
125         // CLIENT
126         {
127                 core::rect<s32> rect(0, 0, 20, 125);
128                 rect += topleft_client + v2s32(-15, 80);
129                 const wchar_t *text = L"C\nL\nI\nE\nN\nT";
130                 //gui::IGUIStaticText *t =
131                 Environment->addStaticText(text, rect, false, true, this, -1);
132                 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
133         }
134         // Nickname + password
135         {
136                 core::rect<s32> rect(0, 0, 110, 20);
137                 rect += topleft_client + v2s32(35, 50+6);
138                 Environment->addStaticText(wgettext("Name/Password"), 
139                         rect, false, true, this, -1);
140         }
141         changeCtype("C");
142         {
143                 core::rect<s32> rect(0, 0, 230, 30);
144                 rect += topleft_client + v2s32(160, 50);
145                 gui::IGUIElement *e = 
146                 Environment->addEditBox(m_data->name.c_str(), rect, true, this, GUI_ID_NAME_INPUT);
147                 if(m_data->name == L"")
148                         Environment->setFocus(e);
149         }
150         {
151                 core::rect<s32> rect(0, 0, 120, 30);
152                 rect += topleft_client + v2s32(size_client.X-60-100, 50);
153                 gui::IGUIEditBox *e =
154                 Environment->addEditBox(L"", rect, true, this, 264);
155                 e->setPasswordBox(true);
156                 if(m_data->name != L"" && m_data->address != L"")
157                         Environment->setFocus(e);
158
159         }
160         changeCtype("");
161         // Address + port
162         {
163                 core::rect<s32> rect(0, 0, 110, 20);
164                 rect += topleft_client + v2s32(35, 100+6);
165                 Environment->addStaticText(wgettext("Address/Port"),
166                         rect, false, true, this, -1);
167         }
168         changeCtype("C");
169         {
170                 core::rect<s32> rect(0, 0, 230, 30);
171                 rect += topleft_client + v2s32(160, 100);
172                 gui::IGUIElement *e = 
173                 Environment->addEditBox(m_data->address.c_str(), rect, true, this, GUI_ID_ADDRESS_INPUT);
174                 if(m_data->name != L"" && m_data->address == L"")
175                         Environment->setFocus(e);
176         }
177         {
178                 core::rect<s32> rect(0, 0, 120, 30);
179                 //rect += topleft_client + v2s32(160+250+20, 125);
180                 rect += topleft_client + v2s32(size_client.X-60-100, 100);
181                 Environment->addEditBox(m_data->port.c_str(), rect, true, this, GUI_ID_PORT_INPUT);
182         }
183         changeCtype("");
184         {
185                 core::rect<s32> rect(0, 0, 400, 20);
186                 rect += topleft_client + v2s32(160, 100+35);
187                 Environment->addStaticText(wgettext("Leave address blank to start a local server."),
188                         rect, false, true, this, -1);
189         }
190         {
191                 core::rect<s32> rect(0, 0, 250, 30);
192                 rect += topleft_client + v2s32(35, 150);
193                 Environment->addCheckBox(m_data->fancy_trees, rect, this, GUI_ID_FANCYTREE_CB,
194                         wgettext("Fancy trees")); 
195         }
196         {
197                 core::rect<s32> rect(0, 0, 250, 30);
198                 rect += topleft_client + v2s32(35, 150+20);
199                 Environment->addCheckBox(m_data->smooth_lighting, rect, this, GUI_ID_SMOOTH_LIGHTING_CB,
200                                 wgettext("Smooth Lighting"));
201         }
202         {
203                 core::rect<s32> rect(0, 0, 250, 30);
204                 rect += topleft_client + v2s32(35, 150+40);
205                 Environment->addCheckBox(m_data->clouds_3d, rect, this, GUI_ID_3D_CLOUDS_CB,
206                                 wgettext("3D Clouds"));
207         }
208         {
209                 core::rect<s32> rect(0, 0, 250, 30);
210                 rect += topleft_client + v2s32(35, 150+60);
211                 Environment->addCheckBox(m_data->opaque_water, rect, this, GUI_ID_OPAQUE_WATER_CB,
212                                 wgettext("Opaque water"));
213         }
214         // Start game button
215         {
216                 core::rect<s32> rect(0, 0, 180, 30);
217                 //rect += topleft_client + v2s32(size_client.X/2-180/2, 225-30/2);
218                 rect += topleft_client + v2s32(size_client.X-180-40, 150+25);
219                 Environment->addButton(rect, this, GUI_ID_JOIN_GAME_BUTTON,
220                         wgettext("Start Game / Connect"));
221         }
222
223         // Key change button
224         {
225                 core::rect<s32> rect(0, 0, 100, 30);
226                 //rect += topleft_client + v2s32(size_client.X/2-180/2, 225-30/2);
227                 rect += topleft_client + v2s32(size_client.X-180-40-100-20, 150+25);
228                 Environment->addButton(rect, this, GUI_ID_CHANGE_KEYS_BUTTON,
229                         wgettext("Change keys"));
230         }
231         /*
232                 Server section
233         */
234
235         v2s32 topleft_server(40, 290);
236         v2s32 size_server = size - v2s32(40, 0);
237         
238         // SERVER
239         {
240                 core::rect<s32> rect(0, 0, 20, 125);
241                 rect += topleft_server + v2s32(-15, 15);
242                 const wchar_t *text = L"S\nE\nR\nV\nE\nR";
243                 //gui::IGUIStaticText *t =
244                 Environment->addStaticText(text, rect, false, true, this, -1);
245                 //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
246         }
247         // Server parameters
248         {
249                 core::rect<s32> rect(0, 0, 250, 30);
250                 rect += topleft_server + v2s32(20+250+20, 20);
251                 Environment->addCheckBox(m_data->creative_mode, rect, this, GUI_ID_CREATIVE_CB,
252                         wgettext("Creative Mode"));
253         }
254         {
255                 core::rect<s32> rect(0, 0, 250, 30);
256                 rect += topleft_server + v2s32(20+250+20, 40);
257                 Environment->addCheckBox(m_data->enable_damage, rect, this, GUI_ID_DAMAGE_CB,
258                         wgettext("Enable Damage"));
259         }
260         // Delete world button
261         {
262                 core::rect<s32> rect(0, 0, 130, 30);
263                 rect += topleft_server + v2s32(20+250+20, 90);
264                 Environment->addButton(rect, this, GUI_ID_DELETE_WORLD_BUTTON,
265                           wgettext("Delete world"));
266         }
267         // World selection listbox
268         {
269                 core::rect<s32> rect(0, 0, 250, 120);
270                 rect += topleft_server + v2s32(20, 10);
271                 gui::IGUIListBox *e = Environment->addListBox(rect, this,
272                                 GUI_ID_WORLD_LISTBOX);
273                 e->setDrawBackground(true);
274                 for(std::list<std::wstring>::const_iterator i = m_data->worlds.begin();
275                                 i != m_data->worlds.end(); i++){
276                         e->addItem(i->c_str());
277                 }
278                 e->setSelected(m_data->selected_world);
279         }
280         changeCtype("C");
281 }
282
283 void GUIMainMenu::drawMenu()
284 {
285         gui::IGUISkin* skin = Environment->getSkin();
286         if (!skin)
287                 return;
288         video::IVideoDriver* driver = Environment->getVideoDriver();
289         
290         /*video::SColor bgcolor(140,0,0,0);
291         driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);*/
292
293         video::SColor bgcolor(140,0,0,0);
294
295         {
296                 core::rect<s32> rect(0, 0, 620, 270);
297                 rect += AbsoluteRect.UpperLeftCorner;
298                 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
299         }
300
301         {
302                 core::rect<s32> rect(0, 290, 620, 430);
303                 rect += AbsoluteRect.UpperLeftCorner;
304                 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
305         }
306
307         gui::IGUIElement::draw();
308 }
309
310 void GUIMainMenu::readInput(MainMenuData *dst)
311 {
312         {
313                 gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT);
314                 if(e != NULL)
315                         dst->name = e->getText();
316         }
317         {
318                 gui::IGUIElement *e = getElementFromId(264);
319                 if(e != NULL)
320                         dst->password = e->getText();
321         }
322         {
323                 gui::IGUIElement *e = getElementFromId(GUI_ID_ADDRESS_INPUT);
324                 if(e != NULL)
325                         dst->address = e->getText();
326         }
327         {
328                 gui::IGUIElement *e = getElementFromId(GUI_ID_PORT_INPUT);
329                 if(e != NULL)
330                         dst->port = e->getText();
331         }
332         {
333                 gui::IGUIElement *e = getElementFromId(GUI_ID_CREATIVE_CB);
334                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
335                         dst->creative_mode = ((gui::IGUICheckBox*)e)->isChecked();
336         }
337         {
338                 gui::IGUIElement *e = getElementFromId(GUI_ID_DAMAGE_CB);
339                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
340                         dst->enable_damage = ((gui::IGUICheckBox*)e)->isChecked();
341         }
342         {
343                 gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB);
344                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
345                         dst->fancy_trees = ((gui::IGUICheckBox*)e)->isChecked();
346         }
347         {
348                 gui::IGUIElement *e = getElementFromId(GUI_ID_SMOOTH_LIGHTING_CB);
349                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
350                         dst->smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked();
351         }
352         {
353                 gui::IGUIElement *e = getElementFromId(GUI_ID_3D_CLOUDS_CB);
354                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
355                         dst->clouds_3d = ((gui::IGUICheckBox*)e)->isChecked();
356         }
357         {
358                 gui::IGUIElement *e = getElementFromId(GUI_ID_OPAQUE_WATER_CB);
359                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
360                         dst->opaque_water = ((gui::IGUICheckBox*)e)->isChecked();
361         }
362
363         {
364                 gui::IGUIElement *e = getElementFromId(GUI_ID_WORLD_LISTBOX);
365                 if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX)
366                         dst->selected_world = ((gui::IGUIListBox*)e)->getSelected();
367         }
368 }
369
370 void GUIMainMenu::acceptInput()
371 {
372         readInput(m_data);
373         m_accepted = true;
374 }
375
376 bool GUIMainMenu::OnEvent(const SEvent& event)
377 {
378         if(event.EventType==EET_KEY_INPUT_EVENT)
379         {
380                 if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
381                 {
382                         m_gamecallback->exitToOS();
383                         quitMenu();
384                         return true;
385                 }
386                 if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
387                 {
388                         acceptInput();
389                         quitMenu();
390                         return true;
391                 }
392         }
393         if(event.EventType==EET_GUI_EVENT)
394         {
395                 if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
396                                 && isVisible())
397                 {
398                         if(!canTakeFocus(event.GUIEvent.Element))
399                         {
400                                 dstream<<"GUIMainMenu: Not allowing focus change."
401                                                 <<std::endl;
402                                 // Returning true disables focus change
403                                 return true;
404                         }
405                 }
406                 if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
407                 {
408                         switch(event.GUIEvent.Caller->getID())
409                         {
410                         case GUI_ID_JOIN_GAME_BUTTON: // Start game
411                                 acceptInput();
412                                 quitMenu();
413                                 return true;
414                         case GUI_ID_CHANGE_KEYS_BUTTON: {
415                                 GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(env, parent, -1,menumgr);
416                                 kmenu->drop();
417                                 return true;
418                         }
419                         case GUI_ID_DELETE_WORLD_BUTTON: // Delete world
420                                 acceptInput();
421                                 m_data->delete_world = true;
422                                 quitMenu();
423                                 return true;
424                         }
425                 }
426                 if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER)
427                 {
428                         switch(event.GUIEvent.Caller->getID())
429                         {
430                                 case GUI_ID_ADDRESS_INPUT: case GUI_ID_PORT_INPUT: case GUI_ID_NAME_INPUT: case 264:
431                                 acceptInput();
432                                 quitMenu();
433                                 return true;
434                         }
435                 }
436                 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN)
437                 {
438                         switch(event.GUIEvent.Caller->getID())
439                         {
440                                 case GUI_ID_WORLD_LISTBOX:
441                                 acceptInput();
442                                 m_data->address = L""; // Force local game
443                                 quitMenu();
444                                 return true;
445                         }
446                 }
447         }
448
449         return Parent ? Parent->OnEvent(event) : false;
450 }
451