Fix camera "jumping" when attached and the parent goes too fast
[oweals/minetest.git] / src / guiMainMenu.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 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 "guiConfigureWorld.h"
24 #include "guiMessageMenu.h"
25 #include "guiConfirmMenu.h"
26 #include "debug.h"
27 #include "serialization.h"
28 #include <string>
29 #include <IGUICheckBox.h>
30 #include <IGUIEditBox.h>
31 #include <IGUIButton.h>
32 #include <IGUIStaticText.h>
33 #include <IGUIFont.h>
34 #include <IGUIListBox.h>
35 #include <IGUITabControl.h>
36 #include <IGUIImage.h>
37 // For IGameCallback
38 #include "guiPauseMenu.h"
39 #include "gettext.h"
40 #include "tile.h" // getTexturePath
41 #include "filesys.h"
42 #include "util/string.h"
43 #include "subgame.h"
44
45 #define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
46 #define LSTRING(x) LSTRING_(x)
47 #define LSTRING_(x) L##x
48
49 const wchar_t *contrib_core_strs[] = {
50         L"Perttu Ahola (celeron55) <celeron55@gmail.com>",
51         L"Ryan Kwolek (kwolekr) <kwolekr@minetest.net>",
52         L"PilzAdam <pilzadam@minetest.net>",
53         L"Ilya Zhuravlev (thexyz) <xyz@minetest.net>",
54         L"Lisa Milne (darkrose) <lisa@ltmnet.com>",
55         L"Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>",
56         L"proller <proler@gmail.com>"
57 };
58
59 const wchar_t *contrib_active_strs[] = {
60         L"sfan5 <sfan5@live.de>",
61         L"sapier <sapier@gmx.net>",
62         L"Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>",
63         L"Jurgen Doser (doserj) <jurgen.doser@gmail.com>",
64         L"Jeija <jeija@mesecons.net>",
65         L"MirceaKitsune <mirceakitsune@gmail.com>",
66         L"ShadowNinja",
67         L"dannydark <the_skeleton_of_a_child@yahoo.co.uk>",
68         L"0gb.us <0gb.us@0gb.us>"
69 };
70
71 const wchar_t *contrib_previous_strs[] = {
72         L"kahrl <kahrl@gmx.net>",
73         L"Giuseppe Bilotta (Oblomov) <giuseppe.bilotta@gmail.com>",
74         L"Jonathan Neuschafer <j.neuschaefer@gmx.net>",
75         L"Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>",
76         L"Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>",
77         L"matttpt <matttpt@gmail.com>",
78         L"JacobF <queatz@gmail.com>" 
79 };
80
81
82 struct CreateWorldDestMainMenu : public CreateWorldDest
83 {
84         CreateWorldDestMainMenu(GUIMainMenu *menu):
85                 m_menu(menu)
86         {}
87         void accepted(std::wstring name, std::string gameid)
88         {
89                 std::string name_narrow = wide_to_narrow(name);
90                 if(!string_allowed_blacklist(name_narrow, WORLDNAME_BLACKLISTED_CHARS))
91                 {
92                         m_menu->displayMessageMenu(wgettext("Cannot create world: Name contains invalid characters"));
93                         return;
94                 }
95                 std::vector<WorldSpec> worlds = getAvailableWorlds();
96                 for(std::vector<WorldSpec>::iterator i = worlds.begin();
97                     i != worlds.end(); i++)
98                 {
99                         if((*i).name == name_narrow)
100                         {
101                                 m_menu->displayMessageMenu(wgettext("Cannot create world: A world by this name already exists"));
102                                 return;
103                         }
104                 }
105                 m_menu->createNewWorld(name, gameid);
106         }
107         GUIMainMenu *m_menu;
108 };
109
110 struct ConfirmDestDeleteWorld : public ConfirmDest
111 {
112         ConfirmDestDeleteWorld(WorldSpec spec, GUIMainMenu *menu,
113                         const std::vector<std::string> &paths):
114                 m_spec(spec),
115                 m_menu(menu),
116                 m_paths(paths)
117         {}
118         void answer(bool answer)
119         {
120                 if(answer == false)
121                         return;
122                 m_menu->deleteWorld(m_paths);
123         }
124         WorldSpec m_spec;
125         GUIMainMenu *m_menu;
126         std::vector<std::string> m_paths;
127 };
128
129 enum
130 {
131         GUI_ID_QUIT_BUTTON = 101,
132         GUI_ID_NAME_INPUT,
133         GUI_ID_ADDRESS_INPUT,
134         GUI_ID_PORT_INPUT,
135         GUI_ID_FANCYTREE_CB,
136         GUI_ID_SMOOTH_LIGHTING_CB,
137         GUI_ID_3D_CLOUDS_CB,
138         GUI_ID_OPAQUE_WATER_CB,
139         GUI_ID_MIPMAP_CB,
140         GUI_ID_ANISOTROPIC_CB,
141         GUI_ID_BILINEAR_CB,
142         GUI_ID_TRILINEAR_CB,
143         GUI_ID_SHADERS_CB,
144         GUI_ID_PRELOAD_ITEM_VISUALS_CB,
145         GUI_ID_ENABLE_PARTICLES_CB,
146         GUI_ID_LIQUID_FINITE_CB,
147         GUI_ID_DAMAGE_CB,
148         GUI_ID_CREATIVE_CB,
149         GUI_ID_PUBLIC_CB,
150         GUI_ID_JOIN_GAME_BUTTON,
151         GUI_ID_CHANGE_KEYS_BUTTON,
152         GUI_ID_DELETE_WORLD_BUTTON,
153         GUI_ID_CREATE_WORLD_BUTTON,
154         GUI_ID_CONFIGURE_WORLD_BUTTON,
155         GUI_ID_WORLD_LISTBOX,
156         GUI_ID_TAB_CONTROL,
157         GUI_ID_SERVERLIST,
158         GUI_ID_SERVERLIST_TOGGLE,
159         GUI_ID_SERVERLIST_DELETE,
160         GUI_ID_SERVERLIST_TITLE,
161 };
162
163 enum
164 {
165         TAB_SINGLEPLAYER=0,
166         TAB_MULTIPLAYER,
167         TAB_ADVANCED,
168         TAB_SETTINGS,
169         TAB_CREDITS
170 };
171
172 GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env,
173                 gui::IGUIElement* parent, s32 id,
174                 IMenuManager *menumgr,
175                 MainMenuData *data,
176                 IGameCallback *gamecallback
177 ):
178         GUIModalMenu(env, parent, id, menumgr),
179         m_data(data),
180         m_accepted(false),
181         m_gamecallback(gamecallback),
182         m_is_regenerating(false)
183 {
184         assert(m_data);
185         this->env = env;
186         this->parent = parent;
187         this->id = id;
188         this->menumgr = menumgr;
189 }
190
191 GUIMainMenu::~GUIMainMenu()
192 {
193         removeChildren();
194 }
195
196 void GUIMainMenu::removeChildren()
197 {
198         const core::list<gui::IGUIElement*> &children = getChildren();
199         core::list<gui::IGUIElement*> children_copy;
200         for(core::list<gui::IGUIElement*>::ConstIterator
201                         i = children.begin(); i != children.end(); i++)
202         {
203                 children_copy.push_back(*i);
204         }
205         for(core::list<gui::IGUIElement*>::Iterator
206                         i = children_copy.begin();
207                         i != children_copy.end(); i++)
208         {
209                 (*i)->remove();
210         }
211 }
212
213 void GUIMainMenu::regenerateGui(v2u32 screensize)
214 {
215         m_is_regenerating = true;
216         /*
217                 Read stuff from elements into m_data
218         */
219         readInput(m_data);
220
221         /*
222                 Remove stuff
223         */
224         removeChildren();
225         
226         /*
227                 Calculate new sizes and positions
228         */
229         
230         v2s32 size(screensize.X, screensize.Y);
231
232         core::rect<s32> rect(
233                         screensize.X/2 - size.X/2,
234                         screensize.Y/2 - size.Y/2,
235                         screensize.X/2 + size.X/2,
236                         screensize.Y/2 + size.Y/2
237         );
238
239         DesiredRect = rect;
240         recalculateAbsolutePosition(false);
241
242         //v2s32 size = rect.getSize();
243
244         /*
245                 Add stuff
246         */
247
248         changeCtype("");
249
250         // Version
251         {
252                 core::rect<s32> rect(0, 0, size.X, 40);
253                 rect += v2s32(4, 0);
254                 Environment->addStaticText(narrow_to_wide(
255                                 "Minetest " VERSION_STRING).c_str(),
256                                 rect, false, true, this, -1);
257         }
258
259         //v2s32 center(size.X/2, size.Y/2);
260         v2s32 c800(size.X/2-400, size.Y/2-270);
261         
262         m_topleft_client = c800 + v2s32(90, 70+50+30);
263         m_size_client = v2s32(620, 270);
264
265         m_size_server = v2s32(620, 140);
266
267         if(m_data->selected_tab == TAB_ADVANCED)
268         {
269                 m_topleft_client = c800 + v2s32(90, 70+50+30);
270                 m_size_client = v2s32(620, 200);
271
272                 m_size_server = v2s32(620, 140);
273         }
274
275         m_topleft_server = m_topleft_client + v2s32(0, m_size_client.Y+20);
276         
277         // Tabs
278         {
279                 core::rect<s32> rect(0, 0, m_size_client.X, 30);
280                 rect += m_topleft_client + v2s32(0, -30);
281                 gui::IGUITabControl *e = Environment->addTabControl(
282                                 rect, this, true, true, GUI_ID_TAB_CONTROL);
283                 e->addTab(wgettext("Singleplayer"));
284                 e->addTab(wgettext("Multiplayer"));
285                 e->addTab(wgettext("Advanced"));
286                 e->addTab(wgettext("Settings"));
287                 e->addTab(wgettext("Credits"));
288                 e->setActiveTab(m_data->selected_tab);
289         }
290         
291         if(m_data->selected_tab == TAB_SINGLEPLAYER)
292         {
293                 // HYBRID
294                 {
295                         core::rect<s32> rect(0, 0, 10, m_size_client.Y);
296                         rect += m_topleft_client + v2s32(15, 0);
297                         //const wchar_t *text = L"H\nY\nB\nR\nI\nD";
298                         const wchar_t *text = L"S\nI\nN\nG\nL\nE\n \nP\nL\nA\nY\nE\nR\n";
299                         gui::IGUIStaticText *t =
300                         Environment->addStaticText(text, rect, false, true, this, -1);
301                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
302                 }
303                 u32 bs = 5;
304                 // World selection listbox
305                 u32 world_sel_h = 160;
306                 u32 world_sel_w = 365;
307                 //s32 world_sel_x = 50;
308                 s32 world_sel_x = m_size_client.X-world_sel_w-30;
309                 s32 world_sel_y = 30;
310                 u32 world_button_count = 3;
311                 u32 world_button_w = (world_sel_w)/world_button_count - bs
312                                 + bs/(world_button_count-1);
313                 {
314                         core::rect<s32> rect(0, 0, world_sel_w-4, 20);
315                         rect += m_topleft_client + v2s32(world_sel_x+4, world_sel_y-20);
316                         /*gui::IGUIStaticText *e =*/ Environment->addStaticText(
317                                         wgettext("Select World:"), 
318                                         rect, false, true, this, -1);
319                         /*e->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);*/
320                 }
321                 {
322                         core::rect<s32> rect(0, 0, world_sel_w, world_sel_h);
323                         rect += m_topleft_client + v2s32(world_sel_x, world_sel_y);
324                         gui::IGUIListBox *e = Environment->addListBox(rect, this,
325                                         GUI_ID_WORLD_LISTBOX);
326                         e->setDrawBackground(true);
327                         for(std::vector<WorldSpec>::const_iterator i = m_data->worlds.begin();
328                                         i != m_data->worlds.end(); i++){
329                                 e->addItem(narrow_to_wide(i->name+" ["+i->gameid+"]").c_str());
330                         }
331                         e->setSelected(m_data->selected_world);
332                         Environment->setFocus(e);
333                 }
334                 // Delete world button
335                 {
336                         core::rect<s32> rect(0, 0, world_button_w, 30);
337                         rect += m_topleft_client + v2s32(world_sel_x, world_sel_y+world_sel_h+0);
338                         Environment->addButton(rect, this, GUI_ID_DELETE_WORLD_BUTTON,
339                                   wgettext("Delete"));
340                 }
341                 // Create world button
342                 {
343                         core::rect<s32> rect(0, 0, world_button_w, 30);
344                         rect += m_topleft_client + v2s32(world_sel_x+world_button_w+bs, world_sel_y+world_sel_h+0);
345                         Environment->addButton(rect, this, GUI_ID_CREATE_WORLD_BUTTON,
346                                   wgettext("New"));
347                 }
348                 // Configure world button
349                 {
350                         core::rect<s32> rect(0, 0, world_button_w, 30);
351                         rect += m_topleft_client + v2s32(world_sel_x+(world_button_w+bs)*2,
352                                         world_sel_y+world_sel_h+0);
353                         Environment->addButton(rect, this, GUI_ID_CONFIGURE_WORLD_BUTTON,
354                                   wgettext("Configure"));
355                 }
356                 // Start game button
357                 {
358                         /*core::rect<s32> rect(0, 0, world_button_w, 30);
359                         rect += m_topleft_client + v2s32(world_sel_x+(world_button_w+bs)*3,
360                                         world_sel_y+world_sel_h+0);*/
361                         u32 bw = 160;
362                         /*core::rect<s32> rect(0, 0, bw, 30);
363                         rect += m_topleft_client + v2s32(m_size_client.X-bw-30,
364                                         m_size_client.Y-30-15);*/
365                         core::rect<s32> rect(0, 0, bw, 30);
366                         rect += m_topleft_client + v2s32(world_sel_x+world_sel_w-bw,
367                                         world_sel_y+world_sel_h+30+bs);
368                         Environment->addButton(rect, this,
369                                         GUI_ID_JOIN_GAME_BUTTON, wgettext("Play"));
370                 }
371                 // Options
372                 s32 option_x = 50;
373                 //s32 option_x = 50+world_sel_w+20;
374                 s32 option_y = 30;
375                 u32 option_w = 150;
376                 {
377                         core::rect<s32> rect(0, 0, option_w, 30);
378                         rect += m_topleft_client + v2s32(option_x, option_y+20*0);
379                         Environment->addCheckBox(m_data->creative_mode, rect, this,
380                                         GUI_ID_CREATIVE_CB, wgettext("Creative Mode"));
381                 }
382                 {
383                         core::rect<s32> rect(0, 0, option_w, 30);
384                         rect += m_topleft_client + v2s32(option_x, option_y+20*1);
385                         Environment->addCheckBox(m_data->enable_damage, rect, this,
386                                         GUI_ID_DAMAGE_CB, wgettext("Enable Damage"));
387                 }
388                 changeCtype("C");
389         }
390         else if(m_data->selected_tab == TAB_MULTIPLAYER)
391         {
392                 changeCtype("");
393                 // CLIENT
394                 {
395                         core::rect<s32> rect(0, 0, 10, m_size_client.Y);
396                         rect += m_topleft_client + v2s32(15, 0);
397                         const wchar_t *text = L"C\nL\nI\nE\nN\nT";
398                         gui::IGUIStaticText *t =
399                         Environment->addStaticText(text, rect, false, true, this, -1);
400                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
401                 }
402                 // Nickname + password
403                 {
404                         core::rect<s32> rect(0, 0, 110, 20);
405                         rect += m_topleft_client + v2s32(m_size_client.X-60-100, 10+6);
406                         Environment->addStaticText(wgettext("Name/Password"), 
407                                 rect, false, true, this, -1);
408                 }
409                 changeCtype("C");
410                 {
411                         core::rect<s32> rect(0, 0, 120, 30);
412                         rect += m_topleft_client + v2s32(m_size_client.X-60-100, 50);
413                         gui::IGUIElement *e = 
414                         Environment->addEditBox(m_data->name.c_str(), rect, true, this, GUI_ID_NAME_INPUT);
415                         if(m_data->name == L"")
416                                 Environment->setFocus(e);
417                 }
418                 {
419                         core::rect<s32> rect(0, 0, 120, 30);
420                         rect += m_topleft_client + v2s32(m_size_client.X-60-100, 90);
421                         gui::IGUIEditBox *e =
422                         Environment->addEditBox(L"", rect, true, this, 264);
423                         e->setPasswordBox(true);
424                         if(m_data->name != L"" && m_data->address != L"")
425                                 Environment->setFocus(e);
426
427                 }
428                 changeCtype("");
429                 // Server List
430                 {
431                         core::rect<s32> rect(0, 0, 390, 140);
432                         rect += m_topleft_client + v2s32(50, 30);
433                         gui::IGUIListBox *e = Environment->addListBox(rect, this,
434                                         GUI_ID_SERVERLIST);
435                         e->setDrawBackground(true);
436 #if USE_CURL
437                         if(m_data->selected_serverlist == SERVERLIST_FAVORITES) {
438                                 m_data->servers = ServerList::getLocal();
439                                 {
440                                         core::rect<s32> rect(0, 0, 390, 20);
441                                         rect += m_topleft_client + v2s32(50, 10);
442                                         Environment->addStaticText(wgettext("Favorites:"),
443                                                 rect, false, true, this, GUI_ID_SERVERLIST_TITLE);
444                                 }
445                         } else {
446                                 m_data->servers = ServerList::getOnline();
447                                 {
448                                         core::rect<s32> rect(0, 0, 390, 20);
449                                         rect += m_topleft_client + v2s32(50, 10);
450                                         Environment->addStaticText(wgettext("Public Server List:"),
451                                                 rect, false, true, this, GUI_ID_SERVERLIST_TITLE);
452                                 }
453                         }
454 #else
455                         m_data->servers = ServerList::getLocal();
456                         {
457                                 core::rect<s32> rect(0, 0, 390, 20);
458                                 rect += m_topleft_client + v2s32(50, 10);
459                                 Environment->addStaticText(wgettext("Favorites:"),
460                                         rect, false, true, this, GUI_ID_SERVERLIST_TITLE);
461                         }
462 #endif
463                         updateGuiServerList();
464                         e->setSelected(0);
465                 }
466                 // Address + port
467                 {
468                         core::rect<s32> rect(0, 0, 110, 20);
469                         rect += m_topleft_client + v2s32(50, m_size_client.Y-50-15+6);
470                         Environment->addStaticText(wgettext("Address/Port"),
471                                 rect, false, true, this, -1);
472                 }
473                 changeCtype("C");
474                 {
475                         core::rect<s32> rect(0, 0, 260, 30);
476                         rect += m_topleft_client + v2s32(50, m_size_client.Y-25-15);
477                         gui::IGUIElement *e = 
478                         Environment->addEditBox(m_data->address.c_str(), rect, true,
479                                         this, GUI_ID_ADDRESS_INPUT);
480                         if(m_data->name != L"" && m_data->address == L"")
481                                 Environment->setFocus(e);
482                 }
483                 {
484                         core::rect<s32> rect(0, 0, 120, 30);
485                         rect += m_topleft_client + v2s32(50+260+10, m_size_client.Y-25-15);
486                         Environment->addEditBox(m_data->port.c_str(), rect, true,
487                                         this, GUI_ID_PORT_INPUT);
488                 }
489                 changeCtype("");
490                 #if USE_CURL
491                 // Toggle Serverlist (Favorites/Online)
492                 {
493                         core::rect<s32> rect(0, 0, 260, 30);
494                         rect += m_topleft_client + v2s32(50,
495                                         180);
496                         gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_TOGGLE,
497                                 wgettext("Show Public"));
498                         e->setIsPushButton(true);
499                         if (m_data->selected_serverlist == SERVERLIST_PUBLIC)
500                         {
501                                 e->setText(wgettext("Show Favorites"));
502                                 e->setPressed();
503                         }
504                 }
505                 #endif
506                 // Delete Local Favorite
507                 {
508                         core::rect<s32> rect(0, 0, 120, 30);
509                         rect += m_topleft_client + v2s32(50+260+10, 180);
510                         gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_DELETE,
511                                 wgettext("Delete"));
512                         if (m_data->selected_serverlist == SERVERLIST_PUBLIC) // Hidden when on public list
513                                 e->setVisible(false);
514                 }
515                 // Start game button
516                 {
517                         core::rect<s32> rect(0, 0, 120, 30);
518                         rect += m_topleft_client + v2s32(m_size_client.X-130-30,
519                                         m_size_client.Y-25-15);
520                         Environment->addButton(rect, this, GUI_ID_JOIN_GAME_BUTTON,
521                                 wgettext("Connect"));
522                 }
523                 changeCtype("C");
524         }
525         else if(m_data->selected_tab == TAB_ADVANCED)
526         {
527                 changeCtype("");
528                 // CLIENT
529                 {
530                         core::rect<s32> rect(0, 0, 10, m_size_client.Y);
531                         rect += m_topleft_client + v2s32(15, 0);
532                         const wchar_t *text = L"C\nL\nI\nE\nN\nT";
533                         gui::IGUIStaticText *t =
534                         Environment->addStaticText(text, rect, false, true, this, -1);
535                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
536                 }
537                 // Nickname + password
538                 {
539                         core::rect<s32> rect(0, 0, 110, 20);
540                         rect += m_topleft_client + v2s32(35+30, 35+6);
541                         Environment->addStaticText(wgettext("Name/Password"), 
542                                 rect, false, true, this, -1);
543                 }
544                 changeCtype("C");
545                 {
546                         core::rect<s32> rect(0, 0, 230, 30);
547                         rect += m_topleft_client + v2s32(160+30, 35);
548                         gui::IGUIElement *e = 
549                         Environment->addEditBox(m_data->name.c_str(), rect, true, this, GUI_ID_NAME_INPUT);
550                         if(m_data->name == L"")
551                                 Environment->setFocus(e);
552                 }
553                 {
554                         core::rect<s32> rect(0, 0, 120, 30);
555                         rect += m_topleft_client + v2s32(m_size_client.X-60-100, 35);
556                         gui::IGUIEditBox *e =
557                         Environment->addEditBox(L"", rect, true, this, 264);
558                         e->setPasswordBox(true);
559                         if(m_data->name != L"" && m_data->address != L"")
560                                 Environment->setFocus(e);
561
562                 }
563                 changeCtype("");
564                 // Address + port
565                 {
566                         core::rect<s32> rect(0, 0, 110, 20);
567                         rect += m_topleft_client + v2s32(35+30, 75+6);
568                         Environment->addStaticText(wgettext("Address/Port"),
569                                 rect, false, true, this, -1);
570                 }
571                 changeCtype("C");
572                 {
573                         core::rect<s32> rect(0, 0, 230, 30);
574                         rect += m_topleft_client + v2s32(160+30, 75);
575                         gui::IGUIElement *e = 
576                         Environment->addEditBox(m_data->address.c_str(), rect, true,
577                                         this, GUI_ID_ADDRESS_INPUT);
578                         if(m_data->name != L"" && m_data->address == L"")
579                                 Environment->setFocus(e);
580                 }
581                 {
582                         core::rect<s32> rect(0, 0, 120, 30);
583                         rect += m_topleft_client + v2s32(m_size_client.X-60-100, 75);
584                         Environment->addEditBox(m_data->port.c_str(), rect, true,
585                                         this, GUI_ID_PORT_INPUT);
586                 }
587                 changeCtype("");
588                 {
589                         core::rect<s32> rect(0, 0, 400, 20);
590                         rect += m_topleft_client + v2s32(160+30, 75+35);
591                         Environment->addStaticText(wgettext("Leave address blank to start a local server."),
592                                 rect, false, true, this, -1);
593                 }
594                 // Start game button
595                 {
596                         core::rect<s32> rect(0, 0, 180, 30);
597                         rect += m_topleft_client + v2s32(m_size_client.X-180-30,
598                                         m_size_client.Y-30-20);
599                         Environment->addButton(rect, this, GUI_ID_JOIN_GAME_BUTTON,
600                                 wgettext("Start Game / Connect"));
601                 }
602                 /*
603                         Server section
604                 */
605                 // SERVER
606                 {
607                         core::rect<s32> rect(0, 0, 10, m_size_server.Y);
608                         rect += m_topleft_server + v2s32(15, 0);
609                         const wchar_t *text = L"S\nE\nR\nV\nE\nR";
610                         gui::IGUIStaticText *t =
611                         Environment->addStaticText(text, rect, false, true, this, -1);
612                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
613                 }
614                 // Server parameters
615                 {
616                         core::rect<s32> rect(0, 0, 250, 30);
617                         rect += m_topleft_server + v2s32(30+20+250+20, 20);
618                         Environment->addCheckBox(m_data->creative_mode, rect, this, GUI_ID_CREATIVE_CB,
619                                 wgettext("Creative Mode"));
620                 }
621                 {
622                         core::rect<s32> rect(0, 0, 250, 30);
623                         rect += m_topleft_server + v2s32(30+20+250+20, 40);
624                         Environment->addCheckBox(m_data->enable_damage, rect, this, GUI_ID_DAMAGE_CB,
625                                 wgettext("Enable Damage"));
626                 }
627                 #if USE_CURL
628                 {
629                         core::rect<s32> rect(0, 0, 250, 30);
630                         rect += m_topleft_server + v2s32(30+20+250+20, 60);
631                         Environment->addCheckBox(m_data->enable_public, rect, this, GUI_ID_PUBLIC_CB,
632                                 wgettext("Public"));
633                 }
634                 #endif
635                 // Delete world button
636                 {
637                         core::rect<s32> rect(0, 0, 130, 30);
638                         rect += m_topleft_server + v2s32(30+20+250+20, 90);
639                         Environment->addButton(rect, this, GUI_ID_DELETE_WORLD_BUTTON,
640                                   wgettext("Delete world"));
641                 }
642                 // Create world button
643                 {
644                         core::rect<s32> rect(0, 0, 130, 30);
645                         rect += m_topleft_server + v2s32(30+20+250+20+140, 90);
646                         Environment->addButton(rect, this, GUI_ID_CREATE_WORLD_BUTTON,
647                                   wgettext("Create world"));
648                 }
649                 // World selection listbox
650                 {
651                         core::rect<s32> rect(0, 0, 250, 120);
652                         rect += m_topleft_server + v2s32(30+20, 10);
653                         gui::IGUIListBox *e = Environment->addListBox(rect, this,
654                                         GUI_ID_WORLD_LISTBOX);
655                         e->setDrawBackground(true);
656                         for(std::vector<WorldSpec>::const_iterator i = m_data->worlds.begin();
657                                         i != m_data->worlds.end(); i++){
658                                 e->addItem(narrow_to_wide(i->name+" ["+i->gameid+"]").c_str());
659                         }
660                         e->setSelected(m_data->selected_world);
661                 }
662                 changeCtype("C");
663         }
664         else if(m_data->selected_tab == TAB_SETTINGS)
665         {
666                 {
667                         core::rect<s32> rect(0, 0, 10, m_size_client.Y);
668                         rect += m_topleft_client + v2s32(15, 0);
669                         const wchar_t *text = L"S\nE\nT\nT\nI\nN\nG\nS";
670                         gui::IGUIStaticText *t =
671                         Environment->addStaticText(text, rect, false, true, this, -1);
672                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
673                 }
674                 s32 option_x = 70;
675                 s32 option_y = 50;
676                 u32 option_w = 150;
677                 {
678                         core::rect<s32> rect(0, 0, option_w, 30);
679                         rect += m_topleft_client + v2s32(option_x, option_y);
680                         Environment->addCheckBox(m_data->fancy_trees, rect, this,
681                                         GUI_ID_FANCYTREE_CB, wgettext("Fancy trees")); 
682                 }
683                 {
684                         core::rect<s32> rect(0, 0, option_w, 30);
685                         rect += m_topleft_client + v2s32(option_x, option_y+20);
686                         Environment->addCheckBox(m_data->smooth_lighting, rect, this,
687                                         GUI_ID_SMOOTH_LIGHTING_CB, wgettext("Smooth Lighting"));
688                 }
689                 {
690                         core::rect<s32> rect(0, 0, option_w, 30);
691                         rect += m_topleft_client + v2s32(option_x, option_y+20*2);
692                         Environment->addCheckBox(m_data->clouds_3d, rect, this,
693                                         GUI_ID_3D_CLOUDS_CB, wgettext("3D Clouds"));
694                 }
695                 {
696                         core::rect<s32> rect(0, 0, option_w, 30);
697                         rect += m_topleft_client + v2s32(option_x, option_y+20*3);
698                         Environment->addCheckBox(m_data->opaque_water, rect, this,
699                                         GUI_ID_OPAQUE_WATER_CB, wgettext("Opaque water"));
700                 }
701
702
703                 // Anisotropic/mipmap/bi-/trilinear settings
704
705                 {
706                         core::rect<s32> rect(0, 0, option_w+20, 30);
707                         rect += m_topleft_client + v2s32(option_x+175, option_y);
708                         Environment->addCheckBox(m_data->mip_map, rect, this,
709                                        GUI_ID_MIPMAP_CB, wgettext("Mip-Mapping"));
710                 }
711
712                 {
713                         core::rect<s32> rect(0, 0, option_w+20, 30);
714                         rect += m_topleft_client + v2s32(option_x+175, option_y+20);
715                         Environment->addCheckBox(m_data->anisotropic_filter, rect, this,
716                                        GUI_ID_ANISOTROPIC_CB, wgettext("Anisotropic Filtering"));
717                 }
718
719                 {
720                         core::rect<s32> rect(0, 0, option_w+20, 30);
721                         rect += m_topleft_client + v2s32(option_x+175, option_y+20*2);
722                         Environment->addCheckBox(m_data->bilinear_filter, rect, this,
723                                        GUI_ID_BILINEAR_CB, wgettext("Bi-Linear Filtering"));
724                 }
725
726                 {
727                         core::rect<s32> rect(0, 0, option_w+20, 30);
728                         rect += m_topleft_client + v2s32(option_x+175, option_y+20*3);
729                         Environment->addCheckBox(m_data->trilinear_filter, rect, this,
730                                        GUI_ID_TRILINEAR_CB, wgettext("Tri-Linear Filtering"));
731                 }
732
733                 // shader/on demand image loading/particles settings
734                 {
735                         core::rect<s32> rect(0, 0, option_w+20, 30);
736                         rect += m_topleft_client + v2s32(option_x+175*2, option_y);
737                         Environment->addCheckBox(m_data->enable_shaders, rect, this,
738                                         GUI_ID_SHADERS_CB, wgettext("Shaders"));
739                 }
740
741                 {
742                         core::rect<s32> rect(0, 0, option_w+20+20, 30);
743                         rect += m_topleft_client + v2s32(option_x+175*2, option_y+20);
744                         Environment->addCheckBox(m_data->preload_item_visuals, rect, this,
745                                         GUI_ID_PRELOAD_ITEM_VISUALS_CB, wgettext("Preload item visuals"));
746                 }
747
748                 {
749                         core::rect<s32> rect(0, 0, option_w+20+20, 30);
750                         rect += m_topleft_client + v2s32(option_x+175*2, option_y+20*2);
751                         Environment->addCheckBox(m_data->enable_particles, rect, this,
752                                         GUI_ID_ENABLE_PARTICLES_CB, wgettext("Enable Particles"));
753                 }
754
755                 {
756                         core::rect<s32> rect(0, 0, option_w+20+20, 30);
757                         rect += m_topleft_client + v2s32(option_x+175*2, option_y+20*3);
758                         Environment->addCheckBox(m_data->liquid_finite, rect, this,
759                                         GUI_ID_LIQUID_FINITE_CB, wgettext("Finite liquid"));
760                 }
761
762                 // Key change button
763                 {
764                         core::rect<s32> rect(0, 0, 120, 30);
765                         /*rect += m_topleft_client + v2s32(m_size_client.X-120-30,
766                                         m_size_client.Y-30-20);*/
767                         rect += m_topleft_client + v2s32(option_x, option_y+120);
768                         Environment->addButton(rect, this,
769                                         GUI_ID_CHANGE_KEYS_BUTTON, wgettext("Change keys"));
770                 }
771                 changeCtype("C");
772         }
773         else if(m_data->selected_tab == TAB_CREDITS)
774         {
775                 // CREDITS
776                 {
777                         core::rect<s32> rect(0, 0, 9, m_size_client.Y);
778                         rect += m_topleft_client + v2s32(15, 0);
779                         const wchar_t *text = L"C\nR\nE\nD\nI\nT\nS";
780                         gui::IGUIStaticText *t =
781                         Environment->addStaticText(text, rect, false, true, this, -1);
782                         t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
783                 }
784                 {
785                         core::rect<s32> rect(0, 0, 130, 70);
786                         rect += m_topleft_client + v2s32(35, 160);
787                         Environment->addStaticText(
788                                 L"Minetest " LSTRING(VERSION_STRING) L"\nhttp://minetest.net/",
789                                  rect, false, true, this, -1);
790                 }
791                 {
792                         video::SColor yellow(255, 255, 255, 0);
793                         core::rect<s32> rect(0, 0, 450, 260);
794                         rect += m_topleft_client + v2s32(168, 5);
795                         
796                         irr::gui::IGUIListBox *list = Environment->addListBox(rect, this);
797                         
798                         list->addItem(L"Core Developers");
799                         list->setItemOverrideColor(list->getItemCount() - 1, yellow);
800                         for (int i = 0; i != ARRAYLEN(contrib_core_strs); i++)
801                                 list->addItem(contrib_core_strs[i]);
802                         list->addItem(L"");
803                         list->addItem(L"Active Contributors");
804                         list->setItemOverrideColor(list->getItemCount() - 1, yellow);
805                         for (int i = 0; i != ARRAYLEN(contrib_active_strs); i++)
806                                 list->addItem(contrib_active_strs[i]);
807                         list->addItem(L"");
808                         list->addItem(L"Previous Contributors");
809                         list->setItemOverrideColor(list->getItemCount() - 1, yellow);
810                         for (int i = 0; i != ARRAYLEN(contrib_previous_strs); i++)
811                                 list->addItem(contrib_previous_strs[i]);
812                         list->addItem(L"");
813                 }
814         }
815
816         m_is_regenerating = false;
817 }
818
819 void GUIMainMenu::drawMenu()
820 {
821         gui::IGUISkin* skin = Environment->getSkin();
822         if (!skin)
823                 return;
824         video::IVideoDriver* driver = Environment->getVideoDriver();
825         
826         /*video::SColor bgcolor(140,0,0,0);
827         driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);*/
828
829         video::SColor bgcolor(140,0,0,0);
830
831         if(getTab() == TAB_SINGLEPLAYER)
832         {
833                 {
834                         core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
835                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
836                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
837                 }
838         }
839         else if(getTab() == TAB_MULTIPLAYER)
840         {
841                 {
842                         core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
843                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
844                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
845                 }
846         }
847         else if(getTab() == TAB_ADVANCED)
848         {
849                 {
850                         core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
851                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
852                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
853                 }
854                 {
855                         core::rect<s32> rect(0, 0, m_size_server.X, m_size_server.Y);
856                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_server;
857                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
858                 }
859         }
860         else if(getTab() == TAB_SETTINGS)
861         {
862                 {
863                         core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
864                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
865                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
866                 }
867         }
868         else if(getTab() == TAB_CREDITS)
869         {
870                 {
871                         core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
872                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
873                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
874                 }
875                 video::ITexture *logotexture =
876                                 driver->getTexture(getTexturePath("logo.png").c_str());
877                 if(logotexture)
878                 {
879                         v2s32 logosize(logotexture->getOriginalSize().Width,
880                                         logotexture->getOriginalSize().Height);
881
882                         core::rect<s32> rect(0,0,logosize.X,logosize.Y);
883                         rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
884                         rect += v2s32(50, 60);
885                         driver->draw2DImage(logotexture, rect,
886                                 core::rect<s32>(core::position2d<s32>(0,0),
887                                 core::dimension2di(logotexture->getSize())),
888                                 NULL, NULL, true);
889                 }
890         }
891
892         gui::IGUIElement::draw();
893 }
894
895 void GUIMainMenu::readInput(MainMenuData *dst)
896 {
897         {
898                 gui::IGUIElement *e = getElementFromId(GUI_ID_TAB_CONTROL);
899                 if(e != NULL && e->getType() == gui::EGUIET_TAB_CONTROL)
900                         dst->selected_tab = ((gui::IGUITabControl*)e)->getActiveTab();
901         }
902         if(dst->selected_tab == TAB_SINGLEPLAYER)
903         {
904                 dst->simple_singleplayer_mode = true;
905         }
906         else
907         {
908                 dst->simple_singleplayer_mode = false;
909                 {
910                         gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT);
911                         if(e != NULL)
912                                 dst->name = e->getText();
913                 }
914                 {
915                         gui::IGUIElement *e = getElementFromId(264);
916                         if(e != NULL)
917                                 dst->password = e->getText();
918                 }
919                 {
920                         gui::IGUIElement *e = getElementFromId(GUI_ID_ADDRESS_INPUT);
921                         if(e != NULL)
922                                 dst->address = e->getText();
923                 }
924                 {
925                         gui::IGUIElement *e = getElementFromId(GUI_ID_PORT_INPUT);
926                         if(e != NULL)
927                                 dst->port = e->getText();
928                 }
929         }
930         {
931                 gui::IGUIElement *e = getElementFromId(GUI_ID_CREATIVE_CB);
932                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
933                         dst->creative_mode = ((gui::IGUICheckBox*)e)->isChecked();
934         }
935         {
936                 gui::IGUIElement *e = getElementFromId(GUI_ID_DAMAGE_CB);
937                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
938                         dst->enable_damage = ((gui::IGUICheckBox*)e)->isChecked();
939         }
940         {
941                 gui::IGUIElement *e = getElementFromId(GUI_ID_PUBLIC_CB);
942                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
943                         dst->enable_public = ((gui::IGUICheckBox*)e)->isChecked();
944         }
945         {
946                 gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB);
947                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
948                         dst->fancy_trees = ((gui::IGUICheckBox*)e)->isChecked();
949         }
950         {
951                 gui::IGUIElement *e = getElementFromId(GUI_ID_SMOOTH_LIGHTING_CB);
952                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
953                         dst->smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked();
954         }
955         {
956                 gui::IGUIElement *e = getElementFromId(GUI_ID_3D_CLOUDS_CB);
957                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
958                         dst->clouds_3d = ((gui::IGUICheckBox*)e)->isChecked();
959         }
960         {
961                 gui::IGUIElement *e = getElementFromId(GUI_ID_OPAQUE_WATER_CB);
962                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
963                         dst->opaque_water = ((gui::IGUICheckBox*)e)->isChecked();
964         }
965
966         {
967                 gui::IGUIElement *e = getElementFromId(GUI_ID_MIPMAP_CB);
968                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
969                         dst->mip_map = ((gui::IGUICheckBox*)e)->isChecked();
970         }
971
972         {
973                 gui::IGUIElement *e = getElementFromId(GUI_ID_ANISOTROPIC_CB);
974                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
975                         dst->anisotropic_filter = ((gui::IGUICheckBox*)e)->isChecked();
976         }
977
978         {
979                 gui::IGUIElement *e = getElementFromId(GUI_ID_BILINEAR_CB);
980                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
981                         dst->bilinear_filter = ((gui::IGUICheckBox*)e)->isChecked();
982         }
983
984         {
985                 gui::IGUIElement *e = getElementFromId(GUI_ID_TRILINEAR_CB);
986                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
987                         dst->trilinear_filter = ((gui::IGUICheckBox*)e)->isChecked();
988         }
989
990         {
991                 gui::IGUIElement *e = getElementFromId(GUI_ID_SHADERS_CB);
992                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
993                         dst->enable_shaders = ((gui::IGUICheckBox*)e)->isChecked() ? 2 : 0;
994         }
995
996         {
997                 gui::IGUIElement *e = getElementFromId(GUI_ID_PRELOAD_ITEM_VISUALS_CB);
998                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
999                         dst->preload_item_visuals = ((gui::IGUICheckBox*)e)->isChecked();
1000         }
1001
1002         {
1003                 gui::IGUIElement *e = getElementFromId(GUI_ID_ENABLE_PARTICLES_CB);
1004                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
1005                         dst->enable_particles = ((gui::IGUICheckBox*)e)->isChecked();
1006         }
1007
1008         {
1009                 gui::IGUIElement *e = getElementFromId(GUI_ID_LIQUID_FINITE_CB);
1010                 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
1011                         dst->liquid_finite = ((gui::IGUICheckBox*)e)->isChecked();
1012         }
1013
1014         {
1015                 gui::IGUIElement *e = getElementFromId(GUI_ID_WORLD_LISTBOX);
1016                 if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX)
1017                         dst->selected_world = ((gui::IGUIListBox*)e)->getSelected();
1018         }
1019         {
1020                 ServerListSpec server =
1021                 getServerListSpec(wide_to_narrow(dst->address), wide_to_narrow(dst->port));
1022                 dst->servername = server["name"].asString();
1023                 dst->serverdescription = server["description"].asString();
1024         }
1025 }
1026
1027 void GUIMainMenu::acceptInput()
1028 {
1029         readInput(m_data);
1030         m_accepted = true;
1031 }
1032
1033 bool GUIMainMenu::OnEvent(const SEvent& event)
1034 {
1035         if(event.EventType==EET_KEY_INPUT_EVENT)
1036         {
1037                 if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
1038                 {
1039                         m_gamecallback->exitToOS();
1040                         quitMenu();
1041                         return true;
1042                 }
1043                 if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
1044                 {
1045                         acceptInput();
1046                         quitMenu();
1047                         return true;
1048                 }
1049         }
1050         if(event.EventType==EET_GUI_EVENT)
1051         {
1052                 if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
1053                                 && isVisible())
1054                 {
1055                         if(!canTakeFocus(event.GUIEvent.Element))
1056                         {
1057                                 dstream<<"GUIMainMenu: Not allowing focus change."
1058                                                 <<std::endl;
1059                                 // Returning true disables focus change
1060                                 return true;
1061                         }
1062                 }
1063                 if(event.GUIEvent.EventType==gui::EGET_TAB_CHANGED)
1064                 {
1065                         if(!m_is_regenerating)
1066                                 regenerateGui(m_screensize_old);
1067                         return true;
1068                 }
1069                 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED && event.GUIEvent.Caller->getID() == GUI_ID_SERVERLIST)
1070                 {
1071                         serverListOnSelected();
1072                         return true;
1073                 }
1074                 if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
1075                 {
1076                         switch(event.GUIEvent.Caller->getID())
1077                         {
1078                         case GUI_ID_JOIN_GAME_BUTTON: {
1079                                 MainMenuData cur;
1080                                 readInput(&cur);
1081                                 if (getTab() == TAB_MULTIPLAYER && cur.address == L"")
1082                                 {
1083                                         (new GUIMessageMenu(env, parent, -1, menumgr,
1084                                                         wgettext("Address required."))
1085                                                         )->drop();
1086                                         return true;
1087                                 }
1088                                 acceptInput();
1089                                 quitMenu();
1090                                 return true;
1091                         }
1092                         case GUI_ID_CHANGE_KEYS_BUTTON: {
1093                                 GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(env, parent, -1,menumgr);
1094                                 kmenu->drop();
1095                                 return true;
1096                         }
1097                         case GUI_ID_DELETE_WORLD_BUTTON: {
1098                                 MainMenuData cur;
1099                                 readInput(&cur);
1100                                 if(cur.selected_world == -1){
1101                                         (new GUIMessageMenu(env, parent, -1, menumgr,
1102                                                         wgettext("Cannot delete world: Nothing selected"))
1103                                                         )->drop();
1104                                 } else {
1105                                         WorldSpec spec = m_data->worlds[cur.selected_world];
1106                                         // Get files and directories involved
1107                                         std::vector<std::string> paths;
1108                                         paths.push_back(spec.path);
1109                                         fs::GetRecursiveSubPaths(spec.path, paths);
1110                                         // Launch confirmation dialog
1111                                         ConfirmDestDeleteWorld *dest = new
1112                                                         ConfirmDestDeleteWorld(spec, this, paths);
1113                                         std::wstring text = wgettext("Delete world");
1114                                         text += L" \"";
1115                                         text += narrow_to_wide(spec.name);
1116                                         text += L"\"?\n\n";
1117                                         text += wgettext("Files to be deleted");
1118                                         text += L":\n";
1119                                         for(u32 i=0; i<paths.size(); i++){
1120                                                 if(i == 3){ text += L"..."; break; }
1121                                                 text += narrow_to_wide(paths[i]) + L"\n";
1122                                         }
1123                                         (new GUIConfirmMenu(env, parent, -1, menumgr, dest,
1124                                                         text.c_str()))->drop();
1125                                 }
1126                                 return true;
1127                         }
1128                         case GUI_ID_CREATE_WORLD_BUTTON: {
1129                                 std::vector<SubgameSpec> games = getAvailableGames();
1130                                 if(games.size() == 0){
1131                                         GUIMessageMenu *menu = new GUIMessageMenu(env, parent,
1132                                                         -1, menumgr,
1133                                                         wgettext("Cannot create world: No games found"));
1134                                         menu->drop();
1135                                 } else {
1136                                         CreateWorldDest *dest = new CreateWorldDestMainMenu(this);
1137                                         GUICreateWorld *menu = new GUICreateWorld(env, parent, -1,
1138                                                         menumgr, dest, games);
1139                                         menu->drop();
1140                                 }
1141                                 return true;
1142                         }
1143                         case GUI_ID_CONFIGURE_WORLD_BUTTON: {
1144                                 MainMenuData cur;
1145                                 readInput(&cur);
1146                                 if(cur.selected_world == -1)
1147                                 {
1148                                         (new GUIMessageMenu(env, parent, -1, menumgr,
1149                                                         wgettext("Cannot configure world: Nothing selected"))
1150                                                         )->drop();
1151                                 } 
1152                                 else 
1153                                 {
1154                                         WorldSpec wspec = m_data->worlds[cur.selected_world];
1155                                         GUIConfigureWorld *menu = new GUIConfigureWorld(env, parent,
1156                                                                                 -1, menumgr, wspec);
1157                                         menu->drop();
1158                                 }
1159                                 return true;
1160                         }
1161                         case GUI_ID_SERVERLIST_DELETE: {
1162                                 gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
1163                                 s32 selected = ((gui::IGUIListBox*)serverlist)->getSelected();
1164                                 if (selected == -1) return true;
1165                                 ServerList::deleteEntry(m_data->servers[selected]);
1166                                 m_data->servers = ServerList::getLocal();
1167                                 updateGuiServerList();
1168                                 if (selected > 0)
1169                                         selected -= 1;
1170                                 serverlist->setSelected(selected);
1171                                 serverListOnSelected();
1172                                 return true;
1173                         }
1174                         #if USE_CURL
1175                         case GUI_ID_SERVERLIST_TOGGLE: {
1176                                 gui::IGUIElement *togglebutton = getElementFromId(GUI_ID_SERVERLIST_TOGGLE);
1177                                 gui::IGUIElement *deletebutton = getElementFromId(GUI_ID_SERVERLIST_DELETE);
1178                                 gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
1179                                 gui::IGUIElement *title = getElementFromId(GUI_ID_SERVERLIST_TITLE);
1180                                 if (m_data->selected_serverlist == SERVERLIST_PUBLIC) // switch to favorite list
1181                                 {
1182                                         m_data->servers = ServerList::getLocal();
1183                                         togglebutton->setText(wgettext("Show Public"));
1184                                         title->setText(wgettext("Favorites:"));
1185                                         deletebutton->setVisible(true);
1186                                         updateGuiServerList();
1187                                         serverlist->setSelected(0);
1188                                         m_data->selected_serverlist = SERVERLIST_FAVORITES;
1189                                 }
1190                                 else // switch to online list
1191                                 {
1192                                         m_data->servers = ServerList::getOnline();
1193                                         togglebutton->setText(wgettext("Show Favorites"));
1194                                         title->setText(wgettext("Public Server List:"));
1195                                         deletebutton->setVisible(false);
1196                                         updateGuiServerList();
1197                                         serverlist->setSelected(0);
1198                                         m_data->selected_serverlist = SERVERLIST_PUBLIC;
1199                                 }
1200                                 serverListOnSelected();
1201                         }
1202                         #endif
1203                         }
1204                 }
1205                 if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER)
1206                 {
1207                         switch(event.GUIEvent.Caller->getID())
1208                         {
1209                                 case GUI_ID_ADDRESS_INPUT: case GUI_ID_PORT_INPUT: case GUI_ID_NAME_INPUT: case 264:
1210                                 acceptInput();
1211                                 quitMenu();
1212                                 return true;
1213                         }
1214                 }
1215                 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN)
1216                 {
1217                         switch(event.GUIEvent.Caller->getID())
1218                         {
1219                         case GUI_ID_WORLD_LISTBOX:
1220                                 acceptInput();
1221                                 if(getTab() != TAB_SINGLEPLAYER)
1222                                         m_data->address = L""; // Force local game
1223                                 quitMenu();
1224                                 return true;
1225                         case GUI_ID_SERVERLIST:
1226                                 gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
1227                                 if (serverlist->getSelected() > -1)
1228                                 {
1229                                         acceptInput();
1230                                         quitMenu();
1231                                         return true;
1232                                 }
1233                         }
1234                 }
1235         }
1236
1237         return Parent ? Parent->OnEvent(event) : false;
1238 }
1239
1240 void GUIMainMenu::createNewWorld(std::wstring name, std::string gameid)
1241 {
1242         if(name == L"")
1243                 return;
1244         acceptInput();
1245         m_data->create_world_name = name;
1246         m_data->create_world_gameid = gameid;
1247         quitMenu();
1248 }
1249
1250 void GUIMainMenu::deleteWorld(const std::vector<std::string> &paths)
1251 {
1252         // Delete files
1253         bool did = fs::DeletePaths(paths);
1254         if(!did){
1255                 GUIMessageMenu *menu = new GUIMessageMenu(env, parent,
1256                                 -1, menumgr, wgettext("Failed to delete all world files"));
1257                 menu->drop();
1258         }
1259         // Quit menu to refresh it
1260         acceptInput();
1261         m_data->only_refresh = true;
1262         quitMenu();
1263 }
1264         
1265 int GUIMainMenu::getTab()
1266 {
1267         gui::IGUIElement *e = getElementFromId(GUI_ID_TAB_CONTROL);
1268         if(e != NULL && e->getType() == gui::EGUIET_TAB_CONTROL)
1269                 return ((gui::IGUITabControl*)e)->getActiveTab();
1270         return TAB_SINGLEPLAYER; // Default
1271 }
1272
1273 void GUIMainMenu::displayMessageMenu(std::wstring msg)
1274 {
1275         (new GUIMessageMenu(env, parent, -1, menumgr, msg))->drop();
1276 }
1277
1278 void GUIMainMenu::updateGuiServerList()
1279 {
1280         gui::IGUIListBox *serverlist = (gui::IGUIListBox *)getElementFromId(GUI_ID_SERVERLIST);
1281         serverlist->clear();
1282
1283         for(std::vector<ServerListSpec>::iterator i = m_data->servers.begin();
1284                 i != m_data->servers.end(); i++)
1285         {
1286                 std::string text;
1287
1288                 if ((*i)["clients"].asString().size())
1289                         text += (*i)["clients"].asString();
1290                 if ((*i)["clients_max"].asString().size())
1291                         text += "/" + (*i)["clients_max"].asString();
1292                 text += " ";
1293                 if ((*i)["version"].asString().size())
1294                         text += (*i)["version"].asString() + " ";
1295                 if ((*i)["password"].asString().size())
1296                         text += "*";
1297                 if ((*i)["creative"].asString().size())
1298                         text += "C";
1299                 if ((*i)["damage"].asString().size())
1300                         text += "D";
1301                 if ((*i)["pvp"].asString().size())
1302                         text += "P";
1303                 text += " ";
1304
1305                 if ((*i)["name"] != "" && (*i)["description"] != "")
1306                         text += (*i)["name"].asString() + " (" +  (*i)["description"].asString() + ")";
1307                 else if ((*i)["name"] !="")
1308                         text += (*i)["name"].asString();
1309                 else
1310                         text += (*i)["address"].asString() + ":" + (*i)["port"].asString();
1311                 
1312                 serverlist->addItem(narrow_to_wide(text).c_str());
1313         }
1314 }
1315
1316 void GUIMainMenu::serverListOnSelected()
1317 {
1318         if (!m_data->servers.empty())
1319         {
1320                 gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
1321                 u16 id = serverlist->getSelected();
1322                 //if (id < 0) return; // u16>0!
1323                 ((gui::IGUIEditBox*)getElementFromId(GUI_ID_ADDRESS_INPUT))
1324                 ->setText(narrow_to_wide(m_data->servers[id]["address"].asString()).c_str());
1325                 ((gui::IGUIEditBox*)getElementFromId(GUI_ID_PORT_INPUT))
1326                 ->setText(narrow_to_wide(m_data->servers[id]["port"].asString()).c_str());
1327         }
1328 }
1329
1330 ServerListSpec GUIMainMenu::getServerListSpec(std::string address, std::string port)
1331 {
1332         ServerListSpec server;
1333         server["address"] = address;
1334         server["port"] = port;
1335         for(std::vector<ServerListSpec>::iterator i = m_data->servers.begin();
1336                 i != m_data->servers.end(); i++)
1337         {
1338                 if ((*i)["address"] == address && (*i)["port"] == port)
1339                 {
1340                         server["description"] = (*i)["description"];
1341                         server["name"] = (*i)["name"];
1342                         break;
1343                 }
1344         }
1345         return server;
1346 }