]> git.lizzy.rs Git - dragonfireclient.git/blob - src/guiMainMenu.cpp
Enforce stricter world names using a blacklist
[dragonfireclient.git] / src / guiMainMenu.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-12 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 "guiCreateWorld.h"
23 #include "guiMessageMenu.h"
24 #include "guiConfirmMenu.h"
25 #include "debug.h"
26 #include "serialization.h"
27 #include <string>
28 #include <IGUICheckBox.h>
29 #include <IGUIEditBox.h>
30 #include <IGUIButton.h>
31 #include <IGUIStaticText.h>
32 #include <IGUIFont.h>
33 #include <IGUIListBox.h>
34 #include <IGUITabControl.h>
35 #include <IGUIImage.h>
36 // For IGameCallback
37 #include "guiPauseMenu.h"
38 #include "gettext.h"
39 #include "tile.h" // getTexturePath
40 #include "filesys.h"
41 #include "util/string.h"
42 #include "subgame.h"
43
44 struct CreateWorldDestMainMenu : public CreateWorldDest
45 {
46         CreateWorldDestMainMenu(GUIMainMenu *menu):
47                 m_menu(menu)
48         {}
49         void accepted(std::wstring name, std::string gameid)
50         {
51                 if(!string_allowed_blacklist(wide_to_narrow(name), WORLDNAME_BLACKLISTED_CHARS))
52                         m_menu->displayMessageMenu(wgettext("Cannot create world: Name contains invalid characters"));
53                 else
54                         m_menu->createNewWorld(name, gameid);
55         }
56         GUIMainMenu *m_menu;
57 };
58
59 struct ConfirmDestDeleteWorld : public ConfirmDest
60 {
61         ConfirmDestDeleteWorld(WorldSpec spec, GUIMainMenu *menu,
62                         const std::vector<std::string> &paths):
63                 m_spec(spec),
64                 m_menu(menu),
65                 m_paths(paths)
66         {}
67         void answer(bool answer)
68         {
69                 if(answer == false)
70                         return;
71                 m_menu->deleteWorld(m_paths);
72         }
73         WorldSpec m_spec;
74         GUIMainMenu *m_menu;
75         std::vector<std::string> m_paths;
76 };
77
78 enum
79 {
80         GUI_ID_QUIT_BUTTON = 101,
81         GUI_ID_NAME_INPUT,
82         GUI_ID_ADDRESS_INPUT,
83         GUI_ID_PORT_INPUT,
84         GUI_ID_FANCYTREE_CB,
85         GUI_ID_SMOOTH_LIGHTING_CB,
86         GUI_ID_3D_CLOUDS_CB,
87         GUI_ID_OPAQUE_WATER_CB,
88         GUI_ID_DAMAGE_CB,
89         GUI_ID_CREATIVE_CB,
90         GUI_ID_JOIN_GAME_BUTTON,
91         GUI_ID_CHANGE_KEYS_BUTTON,
92         GUI_ID_DELETE_WORLD_BUTTON,
93         GUI_ID_CREATE_WORLD_BUTTON,
94         GUI_ID_CONFIGURE_WORLD_BUTTON,
95         GUI_ID_WORLD_LISTBOX,
96         GUI_ID_TAB_CONTROL,
97 };
98
99 enum
100 {
101         TAB_SINGLEPLAYER=0,
102         TAB_MULTIPLAYER,
103         TAB_ADVANCED,
104         TAB_SETTINGS,
105         TAB_CREDITS
106 };
107
108 GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env,
109                 gui::IGUIElement* parent, s32 id,
110                 IMenuManager *menumgr,
111                 MainMenuData *data,
112                 IGameCallback *gamecallback
113 ):
114         GUIModalMenu(env, parent, id, menumgr),
115         m_data(data),
116         m_accepted(false),
117         m_gamecallback(gamecallback),
118         m_is_regenerating(false)
119 {
120         assert(m_data);
121         this->env = env;
122         this->parent = parent;
123         this->id = id;
124         this->menumgr = menumgr;
125 }
126
127 GUIMainMenu::~GUIMainMenu()
128 {
129         removeChildren();
130 }
131
132 void GUIMainMenu::removeChildren()
133 {
134         const core::list<gui::IGUIElement*> &children = getChildren();
135         core::list<gui::IGUIElement*> children_copy;
136         for(core::list<gui::IGUIElement*>::ConstIterator
137                         i = children.begin(); i != children.end(); i++)
138         {
139                 children_copy.push_back(*i);
140         }
141         for(core::list<gui::IGUIElement*>::Iterator
142                         i = children_copy.begin();
143                         i != children_copy.end(); i++)
144         {
145                 (*i)->remove();
146         }
147 }
148
149 void GUIMainMenu::regenerateGui(v2u32 screensize)
150 {
151         m_is_regenerating = true;
152         /*
153                 Read stuff from elements into m_data
154         */
155         readInput(m_data);
156
157         /*
158                 Remove stuff
159         */
160         removeChildren();
161         
162         /*
163                 Calculate new sizes and positions
164         */
165         
166         v2s32 size(screensize.X, screensize.Y);
167
168         core::rect<s32> rect(
169                         screensize.X/2 - size.X/2,
170                         screensize.Y/2 - size.Y/2,
171                         screensize.X/2 + size.X/2,
172                         screensize.Y/2 + size.Y/2
173         );
174
175         DesiredRect = rect;
176         recalculateAbsolutePosition(false);
177
178         //v2s32 size = rect.getSize();
179
180         /*
181                 Add stuff
182         */
183
184         changeCtype("");
185
186         // Version
187         //if(m_data->selected_tab != TAB_CREDITS)
188         {
189                 core::rect<s32> rect(0, 0, size.X, 40);
190                 rect += v2s32(4, 0);
191                 Environment->addStaticText(narrow_to_wide(
192                                 "Minetest-c55 " VERSION_STRING).c_str(),
193                                 rect, false, true, this, -1);
194         }
195
196         //v2s32 center(size.X/2, size.Y/2);
197         v2s32 c800(size.X/2-400, size.Y/2-300);
198         
199         m_topleft_client = c800 + v2s32(90, 70+50+30);
200         m_size_client = v2s32(620, 270);
201
202         m_size_server = v2s32(620, 140);
203
204         if(m_data->selected_tab == TAB_ADVANCED)
205         {
206                 m_topleft_client = c800 + v2s32(90, 70+50+30);
207                 m_size_client = v2s32(620, 200);
208
209                 m_size_server = v2s32(620, 140);
210         }
211
212         m_topleft_server = m_topleft_client + v2s32(0, m_size_client.Y+20);
213         
214         // Tabs
215 #if 1
216         {
217                 core::rect<s32> rect(0, 0, m_size_client.X, 30);
218                 rect += m_topleft_client + v2s32(0, -30);
219                 gui::IGUITabControl *e = Environment->addTabControl(
220                                 rect, this, true, true, GUI_ID_TAB_CONTROL);
221                 e->addTab(wgettext("Singleplayer"));
222                 e->addTab(wgettext("Multiplayer"));
223                 e->addTab(wgettext("Advanced"));
224                 e->addTab(wgettext("Settings"));
225                 e->addTab(wgettext("Credits"));
226                 e->setActiveTab(m_data->selected_tab);
227         }
228 #endif
229         
230         if(m_data->selected_tab == TAB_SINGLEPLAYER)
231         {
232                 // HYBRID
233                 {
234                         core::rect<s32> rect(0, 0, 10, m_size_client.Y);
235                         rect += m_topleft_client + v2s32(15, 0);
236                         //const wchar_t *text = L"H\nY\nB\nR\nI\nD";
237                         const wchar_t *text = L"T\nA\nP\nE\n\nA\nN\nD\n\nG\nL\nU\nE";
238                         gui::IGUIStaticText *t =
239                         Environment->addStaticText(text, rect, false, false, this, -1);
240                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
241                 }
242                 u32 bs = 5;
243                 // World selection listbox
244                 u32 world_sel_h = 160;
245                 u32 world_sel_w = 365;
246                 //s32 world_sel_x = 50;
247                 s32 world_sel_x = m_size_client.X-world_sel_w-30;
248                 s32 world_sel_y = 30;
249                 u32 world_button_count = 3;
250                 u32 world_button_w = (world_sel_w)/world_button_count - bs
251                                 + bs/(world_button_count-1);
252                 {
253                         core::rect<s32> rect(0, 0, world_sel_w-4, 20);
254                         rect += m_topleft_client + v2s32(world_sel_x+4, world_sel_y-20);
255                         /*gui::IGUIStaticText *e =*/ Environment->addStaticText(
256                                         wgettext("Select World:"), 
257                                         rect, false, true, this, -1);
258                         /*e->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);*/
259                 }
260                 {
261                         core::rect<s32> rect(0, 0, world_sel_w, world_sel_h);
262                         rect += m_topleft_client + v2s32(world_sel_x, world_sel_y);
263                         gui::IGUIListBox *e = Environment->addListBox(rect, this,
264                                         GUI_ID_WORLD_LISTBOX);
265                         e->setDrawBackground(true);
266                         for(std::vector<WorldSpec>::const_iterator i = m_data->worlds.begin();
267                                         i != m_data->worlds.end(); i++){
268                                 e->addItem(narrow_to_wide(i->name+" ["+i->gameid+"]").c_str());
269                         }
270                         e->setSelected(m_data->selected_world);
271                         Environment->setFocus(e);
272                 }
273                 // Delete world button
274                 {
275                         core::rect<s32> rect(0, 0, world_button_w, 30);
276                         rect += m_topleft_client + v2s32(world_sel_x, world_sel_y+world_sel_h+0);
277                         Environment->addButton(rect, this, GUI_ID_DELETE_WORLD_BUTTON,
278                                   wgettext("Delete"));
279                 }
280                 // Create world button
281                 {
282                         core::rect<s32> rect(0, 0, world_button_w, 30);
283                         rect += m_topleft_client + v2s32(world_sel_x+world_button_w+bs, world_sel_y+world_sel_h+0);
284                         Environment->addButton(rect, this, GUI_ID_CREATE_WORLD_BUTTON,
285                                   wgettext("New"));
286                 }
287                 // Configure world button
288                 {
289                         core::rect<s32> rect(0, 0, world_button_w, 30);
290                         rect += m_topleft_client + v2s32(world_sel_x+(world_button_w+bs)*2,
291                                         world_sel_y+world_sel_h+0);
292                         Environment->addButton(rect, this, GUI_ID_CONFIGURE_WORLD_BUTTON,
293                                   wgettext("Configure"));
294                 }
295                 // Start game button
296                 {
297                         /*core::rect<s32> rect(0, 0, world_button_w, 30);
298                         rect += m_topleft_client + v2s32(world_sel_x+(world_button_w+bs)*3,
299                                         world_sel_y+world_sel_h+0);*/
300                         u32 bw = 160;
301                         /*core::rect<s32> rect(0, 0, bw, 30);
302                         rect += m_topleft_client + v2s32(m_size_client.X-bw-30,
303                                         m_size_client.Y-30-15);*/
304                         core::rect<s32> rect(0, 0, bw, 30);
305                         rect += m_topleft_client + v2s32(world_sel_x+world_sel_w-bw,
306                                         world_sel_y+world_sel_h+30+bs);
307                         Environment->addButton(rect, this,
308                                         GUI_ID_JOIN_GAME_BUTTON, wgettext("Play"));
309                 }
310                 // Options
311                 s32 option_x = 50;
312                 //s32 option_x = 50+world_sel_w+20;
313                 s32 option_y = 30;
314                 u32 option_w = 150;
315                 {
316                         core::rect<s32> rect(0, 0, option_w, 30);
317                         rect += m_topleft_client + v2s32(option_x, option_y+20*0);
318                         Environment->addCheckBox(m_data->creative_mode, rect, this,
319                                         GUI_ID_CREATIVE_CB, wgettext("Creative Mode"));
320                 }
321                 {
322                         core::rect<s32> rect(0, 0, option_w, 30);
323                         rect += m_topleft_client + v2s32(option_x, option_y+20*1);
324                         Environment->addCheckBox(m_data->enable_damage, rect, this,
325                                         GUI_ID_DAMAGE_CB, wgettext("Enable Damage"));
326                 }
327                 changeCtype("C");
328         }
329         else if(m_data->selected_tab == TAB_MULTIPLAYER)
330         {
331                 changeCtype("");
332                 // CLIENT
333                 {
334                         core::rect<s32> rect(0, 0, 10, m_size_client.Y);
335                         rect += m_topleft_client + v2s32(15, 0);
336                         const wchar_t *text = L"C\nL\nI\nE\nN\nT";
337                         gui::IGUIStaticText *t =
338                         Environment->addStaticText(text, rect, false, false, this, -1);
339                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
340                 }
341                 // Nickname + password
342                 {
343                         core::rect<s32> rect(0, 0, 110, 20);
344                         rect += m_topleft_client + v2s32(35+30, 50+6);
345                         Environment->addStaticText(wgettext("Name/Password"), 
346                                 rect, false, true, this, -1);
347                 }
348                 changeCtype("C");
349                 {
350                         core::rect<s32> rect(0, 0, 230, 30);
351                         rect += m_topleft_client + v2s32(160+30, 50);
352                         gui::IGUIElement *e = 
353                         Environment->addEditBox(m_data->name.c_str(), rect, true, this, GUI_ID_NAME_INPUT);
354                         if(m_data->name == L"")
355                                 Environment->setFocus(e);
356                 }
357                 {
358                         core::rect<s32> rect(0, 0, 120, 30);
359                         rect += m_topleft_client + v2s32(m_size_client.X-60-100, 50);
360                         gui::IGUIEditBox *e =
361                         Environment->addEditBox(L"", rect, true, this, 264);
362                         e->setPasswordBox(true);
363                         if(m_data->name != L"" && m_data->address != L"")
364                                 Environment->setFocus(e);
365
366                 }
367                 changeCtype("");
368                 // Address + port
369                 {
370                         core::rect<s32> rect(0, 0, 110, 20);
371                         rect += m_topleft_client + v2s32(35+30, 100+6);
372                         Environment->addStaticText(wgettext("Address/Port"),
373                                 rect, false, true, this, -1);
374                 }
375                 changeCtype("C");
376                 {
377                         core::rect<s32> rect(0, 0, 230, 30);
378                         rect += m_topleft_client + v2s32(160+30, 100);
379                         gui::IGUIElement *e = 
380                         Environment->addEditBox(m_data->address.c_str(), rect, true,
381                                         this, GUI_ID_ADDRESS_INPUT);
382                         if(m_data->name != L"" && m_data->address == L"")
383                                 Environment->setFocus(e);
384                 }
385                 {
386                         core::rect<s32> rect(0, 0, 120, 30);
387                         rect += m_topleft_client + v2s32(m_size_client.X-60-100, 100);
388                         Environment->addEditBox(m_data->port.c_str(), rect, true,
389                                         this, GUI_ID_PORT_INPUT);
390                 }
391                 changeCtype("");
392                 // Start game button
393                 {
394                         core::rect<s32> rect(0, 0, 180, 30);
395                         rect += m_topleft_client + v2s32(m_size_client.X-180-30,
396                                         m_size_client.Y-30-15);
397                         Environment->addButton(rect, this, GUI_ID_JOIN_GAME_BUTTON,
398                                 wgettext("Start Game / Connect"));
399                 }
400                 changeCtype("C");
401         }
402         else if(m_data->selected_tab == TAB_ADVANCED)
403         {
404                 changeCtype("");
405                 // CLIENT
406                 {
407                         core::rect<s32> rect(0, 0, 10, m_size_client.Y);
408                         rect += m_topleft_client + v2s32(15, 0);
409                         const wchar_t *text = L"C\nL\nI\nE\nN\nT";
410                         gui::IGUIStaticText *t =
411                         Environment->addStaticText(text, rect, false, false, this, -1);
412                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
413                 }
414                 // Nickname + password
415                 {
416                         core::rect<s32> rect(0, 0, 110, 20);
417                         rect += m_topleft_client + v2s32(35+30, 35+6);
418                         Environment->addStaticText(wgettext("Name/Password"), 
419                                 rect, false, true, this, -1);
420                 }
421                 changeCtype("C");
422                 {
423                         core::rect<s32> rect(0, 0, 230, 30);
424                         rect += m_topleft_client + v2s32(160+30, 35);
425                         gui::IGUIElement *e = 
426                         Environment->addEditBox(m_data->name.c_str(), rect, true, this, GUI_ID_NAME_INPUT);
427                         if(m_data->name == L"")
428                                 Environment->setFocus(e);
429                 }
430                 {
431                         core::rect<s32> rect(0, 0, 120, 30);
432                         rect += m_topleft_client + v2s32(m_size_client.X-60-100, 35);
433                         gui::IGUIEditBox *e =
434                         Environment->addEditBox(L"", rect, true, this, 264);
435                         e->setPasswordBox(true);
436                         if(m_data->name != L"" && m_data->address != L"")
437                                 Environment->setFocus(e);
438
439                 }
440                 changeCtype("");
441                 // Address + port
442                 {
443                         core::rect<s32> rect(0, 0, 110, 20);
444                         rect += m_topleft_client + v2s32(35+30, 75+6);
445                         Environment->addStaticText(wgettext("Address/Port"),
446                                 rect, false, true, this, -1);
447                 }
448                 changeCtype("C");
449                 {
450                         core::rect<s32> rect(0, 0, 230, 30);
451                         rect += m_topleft_client + v2s32(160+30, 75);
452                         gui::IGUIElement *e = 
453                         Environment->addEditBox(m_data->address.c_str(), rect, true,
454                                         this, GUI_ID_ADDRESS_INPUT);
455                         if(m_data->name != L"" && m_data->address == L"")
456                                 Environment->setFocus(e);
457                 }
458                 {
459                         core::rect<s32> rect(0, 0, 120, 30);
460                         rect += m_topleft_client + v2s32(m_size_client.X-60-100, 75);
461                         Environment->addEditBox(m_data->port.c_str(), rect, true,
462                                         this, GUI_ID_PORT_INPUT);
463                 }
464                 changeCtype("");
465                 {
466                         core::rect<s32> rect(0, 0, 400, 20);
467                         rect += m_topleft_client + v2s32(160+30, 75+35);
468                         Environment->addStaticText(wgettext("Leave address blank to start a local server."),
469                                 rect, false, true, this, -1);
470                 }
471                 // Start game button
472                 {
473                         core::rect<s32> rect(0, 0, 180, 30);
474                         rect += m_topleft_client + v2s32(m_size_client.X-180-30,
475                                         m_size_client.Y-30-20);
476                         Environment->addButton(rect, this, GUI_ID_JOIN_GAME_BUTTON,
477                                 wgettext("Start Game / Connect"));
478                 }
479                 /*
480                         Server section
481                 */
482                 // SERVER
483                 {
484                         core::rect<s32> rect(0, 0, 10, m_size_server.Y);
485                         rect += m_topleft_server + v2s32(15, 0);
486                         const wchar_t *text = L"S\nE\nR\nV\nE\nR";
487                         gui::IGUIStaticText *t =
488                         Environment->addStaticText(text, rect, false, false, this, -1);
489                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
490                 }
491                 // Server parameters
492                 {
493                         core::rect<s32> rect(0, 0, 250, 30);
494                         rect += m_topleft_server + v2s32(30+20+250+20, 20);
495                         Environment->addCheckBox(m_data->creative_mode, rect, this, GUI_ID_CREATIVE_CB,
496                                 wgettext("Creative Mode"));
497                 }
498                 {
499                         core::rect<s32> rect(0, 0, 250, 30);
500                         rect += m_topleft_server + v2s32(30+20+250+20, 40);
501                         Environment->addCheckBox(m_data->enable_damage, rect, this, GUI_ID_DAMAGE_CB,
502                                 wgettext("Enable Damage"));
503                 }
504                 // Delete world button
505                 {
506                         core::rect<s32> rect(0, 0, 130, 30);
507                         rect += m_topleft_server + v2s32(30+20+250+20, 90);
508                         Environment->addButton(rect, this, GUI_ID_DELETE_WORLD_BUTTON,
509                                   wgettext("Delete world"));
510                 }
511                 // Create world button
512                 {
513                         core::rect<s32> rect(0, 0, 130, 30);
514                         rect += m_topleft_server + v2s32(30+20+250+20+140, 90);
515                         Environment->addButton(rect, this, GUI_ID_CREATE_WORLD_BUTTON,
516                                   wgettext("Create world"));
517                 }
518                 // World selection listbox
519                 {
520                         core::rect<s32> rect(0, 0, 250, 120);
521                         rect += m_topleft_server + v2s32(30+20, 10);
522                         gui::IGUIListBox *e = Environment->addListBox(rect, this,
523                                         GUI_ID_WORLD_LISTBOX);
524                         e->setDrawBackground(true);
525                         for(std::vector<WorldSpec>::const_iterator i = m_data->worlds.begin();
526                                         i != m_data->worlds.end(); i++){
527                                 e->addItem(narrow_to_wide(i->name+" ["+i->gameid+"]").c_str());
528                         }
529                         e->setSelected(m_data->selected_world);
530                 }
531                 changeCtype("C");
532         }
533         else if(m_data->selected_tab == TAB_SETTINGS)
534         {
535                 {
536                         core::rect<s32> rect(0, 0, 10, m_size_client.Y);
537                         rect += m_topleft_client + v2s32(15, 0);
538                         const wchar_t *text = L"S\nE\nT\nT\nI\nN\nG\nS";
539                         gui::IGUIStaticText *t =
540                         Environment->addStaticText(text, rect, false, false, this, -1);
541                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
542                 }
543                 s32 option_x = 70;
544                 s32 option_y = 50;
545                 u32 option_w = 150;
546                 {
547                         core::rect<s32> rect(0, 0, option_w, 30);
548                         rect += m_topleft_client + v2s32(option_x, option_y);
549                         Environment->addCheckBox(m_data->fancy_trees, rect, this,
550                                         GUI_ID_FANCYTREE_CB, wgettext("Fancy trees")); 
551                 }
552                 {
553                         core::rect<s32> rect(0, 0, option_w, 30);
554                         rect += m_topleft_client + v2s32(option_x, option_y+20);
555                         Environment->addCheckBox(m_data->smooth_lighting, rect, this,
556                                         GUI_ID_SMOOTH_LIGHTING_CB, wgettext("Smooth Lighting"));
557                 }
558                 {
559                         core::rect<s32> rect(0, 0, option_w, 30);
560                         rect += m_topleft_client + v2s32(option_x, option_y+20*2);
561                         Environment->addCheckBox(m_data->clouds_3d, rect, this,
562                                         GUI_ID_3D_CLOUDS_CB, wgettext("3D Clouds"));
563                 }
564                 {
565                         core::rect<s32> rect(0, 0, option_w, 30);
566                         rect += m_topleft_client + v2s32(option_x, option_y+20*3);
567                         Environment->addCheckBox(m_data->opaque_water, rect, this,
568                                         GUI_ID_OPAQUE_WATER_CB, wgettext("Opaque water"));
569                 }
570                 // Key change button
571                 {
572                         core::rect<s32> rect(0, 0, 120, 30);
573                         /*rect += m_topleft_client + v2s32(m_size_client.X-120-30,
574                                         m_size_client.Y-30-20);*/
575                         rect += m_topleft_client + v2s32(option_x, option_y+120);
576                         Environment->addButton(rect, this,
577                                         GUI_ID_CHANGE_KEYS_BUTTON, wgettext("Change keys"));
578                 }
579                 changeCtype("C");
580         }
581         else if(m_data->selected_tab == TAB_CREDITS)
582         {
583                 // CREDITS
584                 {
585                         core::rect<s32> rect(0, 0, 10, m_size_client.Y);
586                         rect += m_topleft_client + v2s32(15, 0);
587                         const wchar_t *text = L"C\nR\nE\nD\nI\nT\nS";
588                         gui::IGUIStaticText *t =
589                         Environment->addStaticText(text, rect, false, false, this, -1);
590                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
591                 }
592                 {
593                         core::rect<s32> rect(0, 0, 454, 250);
594                         rect += m_topleft_client + v2s32(110, 50+35);
595                         Environment->addStaticText(narrow_to_wide(
596                         "Minetest-c55 " VERSION_STRING "\n"
597                         "http://minetest.net/\n"
598                         "\n"
599                         "by Perttu Ahola <celeron55@gmail.com>\n"
600                         "and contributors: tango_, kahrl (kaaaaaahrl?), erlehmann (the hippie), SpeedProg, JacobF (sqlite worlds), teddydestodes, marktraceur, darkrose, Jonathan Neuschäfer (who the hell?), Felix Krausse (broke liquids, IIRC), sfan5... and >10 more random people."
601                         ).c_str(), rect, false, true, this, -1);
602                 }
603         }
604
605         m_is_regenerating = false;
606 }
607
608 void GUIMainMenu::drawMenu()
609 {
610         gui::IGUISkin* skin = Environment->getSkin();
611         if (!skin)
612                 return;
613         video::IVideoDriver* driver = Environment->getVideoDriver();
614         
615         /*video::SColor bgcolor(140,0,0,0);
616         driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);*/
617
618         video::SColor bgcolor(140,0,0,0);
619
620         if(getTab() == TAB_SINGLEPLAYER)
621         {
622                 {
623                         core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
624                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
625                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
626                 }
627         }
628         else if(getTab() == TAB_MULTIPLAYER)
629         {
630                 {
631                         core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
632                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
633                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
634                 }
635         }
636         else if(getTab() == TAB_ADVANCED)
637         {
638                 {
639                         core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
640                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
641                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
642                 }
643                 {
644                         core::rect<s32> rect(0, 0, m_size_server.X, m_size_server.Y);
645                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_server;
646                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
647                 }
648         }
649         else if(getTab() == TAB_SETTINGS)
650         {
651                 {
652                         core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
653                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
654                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
655                 }
656         }
657         else if(getTab() == TAB_CREDITS)
658         {
659                 {
660                         core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
661                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
662                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
663                 }
664                 video::ITexture *logotexture =
665                                 driver->getTexture(getTexturePath("menulogo.png").c_str());
666                 if(logotexture)
667                 {
668                         v2s32 logosize(logotexture->getOriginalSize().Width,
669                                         logotexture->getOriginalSize().Height);
670                         logosize *= 2;
671                         core::rect<s32> rect(0,0,logosize.X,logosize.Y);
672                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
673                         rect += v2s32(130, 50);
674                         driver->draw2DImage(logotexture, rect,
675                                 core::rect<s32>(core::position2d<s32>(0,0),
676                                 core::dimension2di(logotexture->getSize())),
677                                 NULL, NULL, true);
678                 }
679         }
680
681         gui::IGUIElement::draw();
682 }
683
684 void GUIMainMenu::readInput(MainMenuData *dst)
685 {
686         {
687                 gui::IGUIElement *e = getElementFromId(GUI_ID_TAB_CONTROL);
688                 if(e != NULL && e->getType() == gui::EGUIET_TAB_CONTROL)
689                         dst->selected_tab = ((gui::IGUITabControl*)e)->getActiveTab();
690         }
691         if(dst->selected_tab == TAB_SINGLEPLAYER)
692         {
693                 dst->simple_singleplayer_mode = true;
694         }
695         else
696         {
697                 dst->simple_singleplayer_mode = false;
698                 {
699                         gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT);
700                         if(e != NULL)
701                                 dst->name = e->getText();
702                 }
703                 {
704                         gui::IGUIElement *e = getElementFromId(264);
705                         if(e != NULL)
706                                 dst->password = e->getText();
707                 }
708                 {
709                         gui::IGUIElement *e = getElementFromId(GUI_ID_ADDRESS_INPUT);
710                         if(e != NULL)
711                                 dst->address = e->getText();
712                 }
713                 {
714                         gui::IGUIElement *e = getElementFromId(GUI_ID_PORT_INPUT);
715                         if(e != NULL)
716                                 dst->port = e->getText();
717                 }
718         }
719         {
720                 gui::IGUIElement *e = getElementFromId(GUI_ID_CREATIVE_CB);
721                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
722                         dst->creative_mode = ((gui::IGUICheckBox*)e)->isChecked();
723         }
724         {
725                 gui::IGUIElement *e = getElementFromId(GUI_ID_DAMAGE_CB);
726                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
727                         dst->enable_damage = ((gui::IGUICheckBox*)e)->isChecked();
728         }
729         {
730                 gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB);
731                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
732                         dst->fancy_trees = ((gui::IGUICheckBox*)e)->isChecked();
733         }
734         {
735                 gui::IGUIElement *e = getElementFromId(GUI_ID_SMOOTH_LIGHTING_CB);
736                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
737                         dst->smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked();
738         }
739         {
740                 gui::IGUIElement *e = getElementFromId(GUI_ID_3D_CLOUDS_CB);
741                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
742                         dst->clouds_3d = ((gui::IGUICheckBox*)e)->isChecked();
743         }
744         {
745                 gui::IGUIElement *e = getElementFromId(GUI_ID_OPAQUE_WATER_CB);
746                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
747                         dst->opaque_water = ((gui::IGUICheckBox*)e)->isChecked();
748         }
749
750         {
751                 gui::IGUIElement *e = getElementFromId(GUI_ID_WORLD_LISTBOX);
752                 if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX)
753                         dst->selected_world = ((gui::IGUIListBox*)e)->getSelected();
754         }
755 }
756
757 void GUIMainMenu::acceptInput()
758 {
759         readInput(m_data);
760         m_accepted = true;
761 }
762
763 bool GUIMainMenu::OnEvent(const SEvent& event)
764 {
765         if(event.EventType==EET_KEY_INPUT_EVENT)
766         {
767                 if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
768                 {
769                         m_gamecallback->exitToOS();
770                         quitMenu();
771                         return true;
772                 }
773                 if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
774                 {
775                         acceptInput();
776                         quitMenu();
777                         return true;
778                 }
779         }
780         if(event.EventType==EET_GUI_EVENT)
781         {
782                 if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
783                                 && isVisible())
784                 {
785                         if(!canTakeFocus(event.GUIEvent.Element))
786                         {
787                                 dstream<<"GUIMainMenu: Not allowing focus change."
788                                                 <<std::endl;
789                                 // Returning true disables focus change
790                                 return true;
791                         }
792                 }
793                 if(event.GUIEvent.EventType==gui::EGET_TAB_CHANGED)
794                 {
795                         if(!m_is_regenerating)
796                                 regenerateGui(m_screensize_old);
797                         return true;
798                 }
799                 if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
800                 {
801                         switch(event.GUIEvent.Caller->getID())
802                         {
803                         case GUI_ID_JOIN_GAME_BUTTON: {
804                                 MainMenuData cur;
805                                 readInput(&cur);
806                                 if(cur.address == L"" && getTab() == TAB_MULTIPLAYER){
807                                         (new GUIMessageMenu(env, parent, -1, menumgr,
808                                                         wgettext("Address required."))
809                                                         )->drop();
810                                         return true;
811                                 }
812                                 acceptInput();
813                                 quitMenu();
814                                 return true;
815                         }
816                         case GUI_ID_CHANGE_KEYS_BUTTON: {
817                                 GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(env, parent, -1,menumgr);
818                                 kmenu->drop();
819                                 return true;
820                         }
821                         case GUI_ID_DELETE_WORLD_BUTTON: {
822                                 MainMenuData cur;
823                                 readInput(&cur);
824                                 if(cur.selected_world == -1){
825                                         (new GUIMessageMenu(env, parent, -1, menumgr,
826                                                         wgettext("Cannot delete world: Nothing selected"))
827                                                         )->drop();
828                                 } else {
829                                         WorldSpec spec = m_data->worlds[cur.selected_world];
830                                         // Get files and directories involved
831                                         std::vector<std::string> paths;
832                                         paths.push_back(spec.path);
833                                         fs::GetRecursiveSubPaths(spec.path, paths);
834                                         // Launch confirmation dialog
835                                         ConfirmDestDeleteWorld *dest = new
836                                                         ConfirmDestDeleteWorld(spec, this, paths);
837                                         std::wstring text = wgettext("Delete world");
838                                         text += L" \"";
839                                         text += narrow_to_wide(spec.name);
840                                         text += L"\"?\n\n";
841                                         text += wgettext("Files to be deleted");
842                                         text += L":\n";
843                                         for(u32 i=0; i<paths.size(); i++){
844                                                 if(i == 3){ text += L"..."; break; }
845                                                 text += narrow_to_wide(paths[i]) + L"\n";
846                                         }
847                                         (new GUIConfirmMenu(env, parent, -1, menumgr, dest,
848                                                         text.c_str()))->drop();
849                                 }
850                                 return true;
851                         }
852                         case GUI_ID_CREATE_WORLD_BUTTON: {
853                                 std::vector<SubgameSpec> games = getAvailableGames();
854                                 if(games.size() == 0){
855                                         GUIMessageMenu *menu = new GUIMessageMenu(env, parent,
856                                                         -1, menumgr,
857                                                         wgettext("Cannot create world: No games found"));
858                                         menu->drop();
859                                 } else {
860                                         CreateWorldDest *dest = new CreateWorldDestMainMenu(this);
861                                         GUICreateWorld *menu = new GUICreateWorld(env, parent, -1,
862                                                         menumgr, dest, games);
863                                         menu->drop();
864                                 }
865                                 return true;
866                         }
867                         case GUI_ID_CONFIGURE_WORLD_BUTTON: {
868                                 GUIMessageMenu *menu = new GUIMessageMenu(env, parent,
869                                                 -1, menumgr,
870                                                 wgettext("Nothing here"));
871                                 menu->drop();
872                                 return true;
873                         }
874                         }
875                 }
876                 if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER)
877                 {
878                         switch(event.GUIEvent.Caller->getID())
879                         {
880                                 case GUI_ID_ADDRESS_INPUT: case GUI_ID_PORT_INPUT: case GUI_ID_NAME_INPUT: case 264:
881                                 acceptInput();
882                                 quitMenu();
883                                 return true;
884                         }
885                 }
886                 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN)
887                 {
888                         switch(event.GUIEvent.Caller->getID())
889                         {
890                         case GUI_ID_WORLD_LISTBOX:
891                                 acceptInput();
892                                 if(getTab() != TAB_SINGLEPLAYER)
893                                         m_data->address = L""; // Force local game
894                                 quitMenu();
895                                 return true;
896                         }
897                 }
898         }
899
900         return Parent ? Parent->OnEvent(event) : false;
901 }
902
903 void GUIMainMenu::createNewWorld(std::wstring name, std::string gameid)
904 {
905         if(name == L"")
906                 return;
907         acceptInput();
908         m_data->create_world_name = name;
909         m_data->create_world_gameid = gameid;
910         quitMenu();
911 }
912
913 void GUIMainMenu::deleteWorld(const std::vector<std::string> &paths)
914 {
915         // Delete files
916         bool did = fs::DeletePaths(paths);
917         if(!did){
918                 GUIMessageMenu *menu = new GUIMessageMenu(env, parent,
919                                 -1, menumgr, wgettext("Failed to delete all world files"));
920                 menu->drop();
921         }
922         // Quit menu to refresh it
923         acceptInput();
924         m_data->only_refresh = true;
925         quitMenu();
926 }
927         
928 int GUIMainMenu::getTab()
929 {
930         gui::IGUIElement *e = getElementFromId(GUI_ID_TAB_CONTROL);
931         if(e != NULL && e->getType() == gui::EGUIET_TAB_CONTROL)
932                 return ((gui::IGUITabControl*)e)->getActiveTab();
933         return TAB_SINGLEPLAYER; // Default
934 }
935
936 void GUIMainMenu::displayMessageMenu(std::wstring msg)
937 {
938         (new GUIMessageMenu(env, parent, -1, menumgr, msg))->drop();
939 }