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