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