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