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