3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
20 #include "guiMainMenu.h"
21 #include "guiKeyChangeMenu.h"
22 #include "guiCreateWorld.h"
23 #include "guiConfigureWorld.h"
24 #include "guiMessageMenu.h"
25 #include "guiConfirmMenu.h"
27 #include "serialization.h"
29 #include <IGUICheckBox.h>
30 #include <IGUIEditBox.h>
31 #include <IGUIButton.h>
32 #include <IGUIStaticText.h>
34 #include <IGUIListBox.h>
35 #include <IGUITabControl.h>
36 #include <IGUIImage.h>
38 #include "guiPauseMenu.h"
40 #include "tile.h" // getTexturePath
42 #include "util/string.h"
45 #define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
46 #define LSTRING(x) LSTRING_(x)
47 #define LSTRING_(x) L##x
49 const wchar_t *contrib_core_strs[] = {
50 L"Perttu Ahola (celeron55) <celeron55@gmail.com>",
51 L"Ryan Kwolek (kwolekr) <kwolekr@minetest.net>",
52 L"PilzAdam <pilzadam@minetest.net>",
53 L"Ilya Zhuravlev (thexyz) <xyz@minetest.net>",
54 L"Lisa Milne (darkrose) <lisa@ltmnet.com>",
55 L"Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>",
56 L"proller <proler@gmail.com>"
59 const wchar_t *contrib_active_strs[] = {
60 L"sfan5 <sfan5@live.de>",
61 L"sapier <sapier@gmx.net>",
62 L"Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>",
63 L"Jurgen Doser (doserj) <jurgen.doser@gmail.com>",
64 L"Jeija <jeija@mesecons.net>",
65 L"MirceaKitsune <mirceakitsune@gmail.com>",
67 L"dannydark <the_skeleton_of_a_child@yahoo.co.uk>",
68 L"0gb.us <0gb.us@0gb.us>"
71 const wchar_t *contrib_previous_strs[] = {
72 L"kahrl <kahrl@gmx.net>",
73 L"Giuseppe Bilotta (Oblomov) <giuseppe.bilotta@gmail.com>",
74 L"Jonathan Neuschafer <j.neuschaefer@gmx.net>",
75 L"Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>",
76 L"Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>",
77 L"matttpt <matttpt@gmail.com>",
78 L"JacobF <queatz@gmail.com>"
82 struct CreateWorldDestMainMenu : public CreateWorldDest
84 CreateWorldDestMainMenu(GUIMainMenu *menu):
87 void accepted(std::wstring name, std::string gameid)
89 std::string name_narrow = wide_to_narrow(name);
90 if(!string_allowed_blacklist(name_narrow, WORLDNAME_BLACKLISTED_CHARS))
92 m_menu->displayMessageMenu(wgettext("Cannot create world: Name contains invalid characters"));
95 std::vector<WorldSpec> worlds = getAvailableWorlds();
96 for(std::vector<WorldSpec>::iterator i = worlds.begin();
97 i != worlds.end(); i++)
99 if((*i).name == name_narrow)
101 m_menu->displayMessageMenu(wgettext("Cannot create world: A world by this name already exists"));
105 m_menu->createNewWorld(name, gameid);
110 struct ConfirmDestDeleteWorld : public ConfirmDest
112 ConfirmDestDeleteWorld(WorldSpec spec, GUIMainMenu *menu,
113 const std::vector<std::string> &paths):
118 void answer(bool answer)
122 m_menu->deleteWorld(m_paths);
126 std::vector<std::string> m_paths;
131 GUI_ID_QUIT_BUTTON = 101,
133 GUI_ID_ADDRESS_INPUT,
136 GUI_ID_SMOOTH_LIGHTING_CB,
138 GUI_ID_OPAQUE_WATER_CB,
140 GUI_ID_ANISOTROPIC_CB,
144 GUI_ID_PRELOAD_ITEM_VISUALS_CB,
145 GUI_ID_ENABLE_PARTICLES_CB,
146 GUI_ID_LIQUID_FINITE_CB,
150 GUI_ID_JOIN_GAME_BUTTON,
151 GUI_ID_CHANGE_KEYS_BUTTON,
152 GUI_ID_DELETE_WORLD_BUTTON,
153 GUI_ID_CREATE_WORLD_BUTTON,
154 GUI_ID_CONFIGURE_WORLD_BUTTON,
155 GUI_ID_WORLD_LISTBOX,
158 GUI_ID_SERVERLIST_TOGGLE,
159 GUI_ID_SERVERLIST_DELETE,
160 GUI_ID_SERVERLIST_TITLE,
172 GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env,
173 gui::IGUIElement* parent, s32 id,
174 IMenuManager *menumgr,
176 IGameCallback *gamecallback
178 GUIModalMenu(env, parent, id, menumgr),
181 m_gamecallback(gamecallback),
182 m_is_regenerating(false)
186 this->parent = parent;
188 this->menumgr = menumgr;
191 GUIMainMenu::~GUIMainMenu()
196 void GUIMainMenu::removeChildren()
198 const core::list<gui::IGUIElement*> &children = getChildren();
199 core::list<gui::IGUIElement*> children_copy;
200 for(core::list<gui::IGUIElement*>::ConstIterator
201 i = children.begin(); i != children.end(); i++)
203 children_copy.push_back(*i);
205 for(core::list<gui::IGUIElement*>::Iterator
206 i = children_copy.begin();
207 i != children_copy.end(); i++)
213 void GUIMainMenu::regenerateGui(v2u32 screensize)
215 m_is_regenerating = true;
217 Read stuff from elements into m_data
227 Calculate new sizes and positions
230 v2s32 size(screensize.X, screensize.Y);
232 core::rect<s32> rect(
233 screensize.X/2 - size.X/2,
234 screensize.Y/2 - size.Y/2,
235 screensize.X/2 + size.X/2,
236 screensize.Y/2 + size.Y/2
240 recalculateAbsolutePosition(false);
242 //v2s32 size = rect.getSize();
252 core::rect<s32> rect(0, 0, size.X, 40);
254 Environment->addStaticText(narrow_to_wide(
255 "Minetest " VERSION_STRING).c_str(),
256 rect, false, true, this, -1);
259 //v2s32 center(size.X/2, size.Y/2);
260 v2s32 c800(size.X/2-400, size.Y/2-270);
262 m_topleft_client = c800 + v2s32(90, 70+50+30);
263 m_size_client = v2s32(620, 270);
265 m_size_server = v2s32(620, 140);
267 if(m_data->selected_tab == TAB_ADVANCED)
269 m_topleft_client = c800 + v2s32(90, 70+50+30);
270 m_size_client = v2s32(620, 200);
272 m_size_server = v2s32(620, 140);
275 m_topleft_server = m_topleft_client + v2s32(0, m_size_client.Y+20);
279 core::rect<s32> rect(0, 0, m_size_client.X, 30);
280 rect += m_topleft_client + v2s32(0, -30);
281 gui::IGUITabControl *e = Environment->addTabControl(
282 rect, this, true, true, GUI_ID_TAB_CONTROL);
283 e->addTab(wgettext("Singleplayer"));
284 e->addTab(wgettext("Multiplayer"));
285 e->addTab(wgettext("Advanced"));
286 e->addTab(wgettext("Settings"));
287 e->addTab(wgettext("Credits"));
288 e->setActiveTab(m_data->selected_tab);
291 if(m_data->selected_tab == TAB_SINGLEPLAYER)
295 core::rect<s32> rect(0, 0, 10, m_size_client.Y);
296 rect += m_topleft_client + v2s32(15, 0);
297 //const wchar_t *text = L"H\nY\nB\nR\nI\nD";
298 const wchar_t *text = L"S\nI\nN\nG\nL\nE\n \nP\nL\nA\nY\nE\nR\n";
299 gui::IGUIStaticText *t =
300 Environment->addStaticText(text, rect, false, true, this, -1);
301 t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
304 // World selection listbox
305 u32 world_sel_h = 160;
306 u32 world_sel_w = 365;
307 //s32 world_sel_x = 50;
308 s32 world_sel_x = m_size_client.X-world_sel_w-30;
309 s32 world_sel_y = 30;
310 u32 world_button_count = 3;
311 u32 world_button_w = (world_sel_w)/world_button_count - bs
312 + bs/(world_button_count-1);
314 core::rect<s32> rect(0, 0, world_sel_w-4, 20);
315 rect += m_topleft_client + v2s32(world_sel_x+4, world_sel_y-20);
316 /*gui::IGUIStaticText *e =*/ Environment->addStaticText(
317 wgettext("Select World:"),
318 rect, false, true, this, -1);
319 /*e->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);*/
322 core::rect<s32> rect(0, 0, world_sel_w, world_sel_h);
323 rect += m_topleft_client + v2s32(world_sel_x, world_sel_y);
324 gui::IGUIListBox *e = Environment->addListBox(rect, this,
325 GUI_ID_WORLD_LISTBOX);
326 e->setDrawBackground(true);
327 for(std::vector<WorldSpec>::const_iterator i = m_data->worlds.begin();
328 i != m_data->worlds.end(); i++){
329 e->addItem(narrow_to_wide(i->name+" ["+i->gameid+"]").c_str());
331 e->setSelected(m_data->selected_world);
332 Environment->setFocus(e);
334 // Delete world button
336 core::rect<s32> rect(0, 0, world_button_w, 30);
337 rect += m_topleft_client + v2s32(world_sel_x, world_sel_y+world_sel_h+0);
338 Environment->addButton(rect, this, GUI_ID_DELETE_WORLD_BUTTON,
341 // Create world button
343 core::rect<s32> rect(0, 0, world_button_w, 30);
344 rect += m_topleft_client + v2s32(world_sel_x+world_button_w+bs, world_sel_y+world_sel_h+0);
345 Environment->addButton(rect, this, GUI_ID_CREATE_WORLD_BUTTON,
348 // Configure world button
350 core::rect<s32> rect(0, 0, world_button_w, 30);
351 rect += m_topleft_client + v2s32(world_sel_x+(world_button_w+bs)*2,
352 world_sel_y+world_sel_h+0);
353 Environment->addButton(rect, this, GUI_ID_CONFIGURE_WORLD_BUTTON,
354 wgettext("Configure"));
358 /*core::rect<s32> rect(0, 0, world_button_w, 30);
359 rect += m_topleft_client + v2s32(world_sel_x+(world_button_w+bs)*3,
360 world_sel_y+world_sel_h+0);*/
362 /*core::rect<s32> rect(0, 0, bw, 30);
363 rect += m_topleft_client + v2s32(m_size_client.X-bw-30,
364 m_size_client.Y-30-15);*/
365 core::rect<s32> rect(0, 0, bw, 30);
366 rect += m_topleft_client + v2s32(world_sel_x+world_sel_w-bw,
367 world_sel_y+world_sel_h+30+bs);
368 Environment->addButton(rect, this,
369 GUI_ID_JOIN_GAME_BUTTON, wgettext("Play"));
373 //s32 option_x = 50+world_sel_w+20;
377 core::rect<s32> rect(0, 0, option_w, 30);
378 rect += m_topleft_client + v2s32(option_x, option_y+20*0);
379 Environment->addCheckBox(m_data->creative_mode, rect, this,
380 GUI_ID_CREATIVE_CB, wgettext("Creative Mode"));
383 core::rect<s32> rect(0, 0, option_w, 30);
384 rect += m_topleft_client + v2s32(option_x, option_y+20*1);
385 Environment->addCheckBox(m_data->enable_damage, rect, this,
386 GUI_ID_DAMAGE_CB, wgettext("Enable Damage"));
390 else if(m_data->selected_tab == TAB_MULTIPLAYER)
395 core::rect<s32> rect(0, 0, 10, m_size_client.Y);
396 rect += m_topleft_client + v2s32(15, 0);
397 const wchar_t *text = L"C\nL\nI\nE\nN\nT";
398 gui::IGUIStaticText *t =
399 Environment->addStaticText(text, rect, false, true, this, -1);
400 t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
402 // Nickname + password
404 core::rect<s32> rect(0, 0, 110, 20);
405 rect += m_topleft_client + v2s32(m_size_client.X-60-100, 10+6);
406 Environment->addStaticText(wgettext("Name/Password"),
407 rect, false, true, this, -1);
411 core::rect<s32> rect(0, 0, 120, 30);
412 rect += m_topleft_client + v2s32(m_size_client.X-60-100, 50);
413 gui::IGUIElement *e =
414 Environment->addEditBox(m_data->name.c_str(), rect, true, this, GUI_ID_NAME_INPUT);
415 if(m_data->name == L"")
416 Environment->setFocus(e);
419 core::rect<s32> rect(0, 0, 120, 30);
420 rect += m_topleft_client + v2s32(m_size_client.X-60-100, 90);
421 gui::IGUIEditBox *e =
422 Environment->addEditBox(L"", rect, true, this, 264);
423 e->setPasswordBox(true);
424 if(m_data->name != L"" && m_data->address != L"")
425 Environment->setFocus(e);
431 core::rect<s32> rect(0, 0, 390, 140);
432 rect += m_topleft_client + v2s32(50, 30);
433 gui::IGUIListBox *e = Environment->addListBox(rect, this,
435 e->setDrawBackground(true);
437 if(m_data->selected_serverlist == SERVERLIST_FAVORITES) {
438 m_data->servers = ServerList::getLocal();
440 core::rect<s32> rect(0, 0, 390, 20);
441 rect += m_topleft_client + v2s32(50, 10);
442 Environment->addStaticText(wgettext("Favorites:"),
443 rect, false, true, this, GUI_ID_SERVERLIST_TITLE);
446 m_data->servers = ServerList::getOnline();
448 core::rect<s32> rect(0, 0, 390, 20);
449 rect += m_topleft_client + v2s32(50, 10);
450 Environment->addStaticText(wgettext("Public Server List:"),
451 rect, false, true, this, GUI_ID_SERVERLIST_TITLE);
455 m_data->servers = ServerList::getLocal();
457 core::rect<s32> rect(0, 0, 390, 20);
458 rect += m_topleft_client + v2s32(50, 10);
459 Environment->addStaticText(wgettext("Favorites:"),
460 rect, false, true, this, GUI_ID_SERVERLIST_TITLE);
463 updateGuiServerList();
468 core::rect<s32> rect(0, 0, 110, 20);
469 rect += m_topleft_client + v2s32(50, m_size_client.Y-50-15+6);
470 Environment->addStaticText(wgettext("Address/Port"),
471 rect, false, true, this, -1);
475 core::rect<s32> rect(0, 0, 260, 30);
476 rect += m_topleft_client + v2s32(50, m_size_client.Y-25-15);
477 gui::IGUIElement *e =
478 Environment->addEditBox(m_data->address.c_str(), rect, true,
479 this, GUI_ID_ADDRESS_INPUT);
480 if(m_data->name != L"" && m_data->address == L"")
481 Environment->setFocus(e);
484 core::rect<s32> rect(0, 0, 120, 30);
485 rect += m_topleft_client + v2s32(50+260+10, m_size_client.Y-25-15);
486 Environment->addEditBox(m_data->port.c_str(), rect, true,
487 this, GUI_ID_PORT_INPUT);
491 // Toggle Serverlist (Favorites/Online)
493 core::rect<s32> rect(0, 0, 260, 30);
494 rect += m_topleft_client + v2s32(50,
496 gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_TOGGLE,
497 wgettext("Show Public"));
498 e->setIsPushButton(true);
499 if (m_data->selected_serverlist == SERVERLIST_PUBLIC)
501 e->setText(wgettext("Show Favorites"));
506 // Delete Local Favorite
508 core::rect<s32> rect(0, 0, 120, 30);
509 rect += m_topleft_client + v2s32(50+260+10, 180);
510 gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_DELETE,
512 if (m_data->selected_serverlist == SERVERLIST_PUBLIC) // Hidden when on public list
513 e->setVisible(false);
517 core::rect<s32> rect(0, 0, 120, 30);
518 rect += m_topleft_client + v2s32(m_size_client.X-130-30,
519 m_size_client.Y-25-15);
520 Environment->addButton(rect, this, GUI_ID_JOIN_GAME_BUTTON,
521 wgettext("Connect"));
525 else if(m_data->selected_tab == TAB_ADVANCED)
530 core::rect<s32> rect(0, 0, 10, m_size_client.Y);
531 rect += m_topleft_client + v2s32(15, 0);
532 const wchar_t *text = L"C\nL\nI\nE\nN\nT";
533 gui::IGUIStaticText *t =
534 Environment->addStaticText(text, rect, false, true, this, -1);
535 t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
537 // Nickname + password
539 core::rect<s32> rect(0, 0, 110, 20);
540 rect += m_topleft_client + v2s32(35+30, 35+6);
541 Environment->addStaticText(wgettext("Name/Password"),
542 rect, false, true, this, -1);
546 core::rect<s32> rect(0, 0, 230, 30);
547 rect += m_topleft_client + v2s32(160+30, 35);
548 gui::IGUIElement *e =
549 Environment->addEditBox(m_data->name.c_str(), rect, true, this, GUI_ID_NAME_INPUT);
550 if(m_data->name == L"")
551 Environment->setFocus(e);
554 core::rect<s32> rect(0, 0, 120, 30);
555 rect += m_topleft_client + v2s32(m_size_client.X-60-100, 35);
556 gui::IGUIEditBox *e =
557 Environment->addEditBox(L"", rect, true, this, 264);
558 e->setPasswordBox(true);
559 if(m_data->name != L"" && m_data->address != L"")
560 Environment->setFocus(e);
566 core::rect<s32> rect(0, 0, 110, 20);
567 rect += m_topleft_client + v2s32(35+30, 75+6);
568 Environment->addStaticText(wgettext("Address/Port"),
569 rect, false, true, this, -1);
573 core::rect<s32> rect(0, 0, 230, 30);
574 rect += m_topleft_client + v2s32(160+30, 75);
575 gui::IGUIElement *e =
576 Environment->addEditBox(m_data->address.c_str(), rect, true,
577 this, GUI_ID_ADDRESS_INPUT);
578 if(m_data->name != L"" && m_data->address == L"")
579 Environment->setFocus(e);
582 core::rect<s32> rect(0, 0, 120, 30);
583 rect += m_topleft_client + v2s32(m_size_client.X-60-100, 75);
584 Environment->addEditBox(m_data->port.c_str(), rect, true,
585 this, GUI_ID_PORT_INPUT);
589 core::rect<s32> rect(0, 0, 400, 20);
590 rect += m_topleft_client + v2s32(160+30, 75+35);
591 Environment->addStaticText(wgettext("Leave address blank to start a local server."),
592 rect, false, true, this, -1);
596 core::rect<s32> rect(0, 0, 180, 30);
597 rect += m_topleft_client + v2s32(m_size_client.X-180-30,
598 m_size_client.Y-30-20);
599 Environment->addButton(rect, this, GUI_ID_JOIN_GAME_BUTTON,
600 wgettext("Start Game / Connect"));
607 core::rect<s32> rect(0, 0, 10, m_size_server.Y);
608 rect += m_topleft_server + v2s32(15, 0);
609 const wchar_t *text = L"S\nE\nR\nV\nE\nR";
610 gui::IGUIStaticText *t =
611 Environment->addStaticText(text, rect, false, true, this, -1);
612 t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
616 core::rect<s32> rect(0, 0, 250, 30);
617 rect += m_topleft_server + v2s32(30+20+250+20, 20);
618 Environment->addCheckBox(m_data->creative_mode, rect, this, GUI_ID_CREATIVE_CB,
619 wgettext("Creative Mode"));
622 core::rect<s32> rect(0, 0, 250, 30);
623 rect += m_topleft_server + v2s32(30+20+250+20, 40);
624 Environment->addCheckBox(m_data->enable_damage, rect, this, GUI_ID_DAMAGE_CB,
625 wgettext("Enable Damage"));
629 core::rect<s32> rect(0, 0, 250, 30);
630 rect += m_topleft_server + v2s32(30+20+250+20, 60);
631 Environment->addCheckBox(m_data->enable_public, rect, this, GUI_ID_PUBLIC_CB,
635 // Delete world button
637 core::rect<s32> rect(0, 0, 130, 30);
638 rect += m_topleft_server + v2s32(30+20+250+20, 90);
639 Environment->addButton(rect, this, GUI_ID_DELETE_WORLD_BUTTON,
640 wgettext("Delete world"));
642 // Create world button
644 core::rect<s32> rect(0, 0, 130, 30);
645 rect += m_topleft_server + v2s32(30+20+250+20+140, 90);
646 Environment->addButton(rect, this, GUI_ID_CREATE_WORLD_BUTTON,
647 wgettext("Create world"));
649 // World selection listbox
651 core::rect<s32> rect(0, 0, 250, 120);
652 rect += m_topleft_server + v2s32(30+20, 10);
653 gui::IGUIListBox *e = Environment->addListBox(rect, this,
654 GUI_ID_WORLD_LISTBOX);
655 e->setDrawBackground(true);
656 for(std::vector<WorldSpec>::const_iterator i = m_data->worlds.begin();
657 i != m_data->worlds.end(); i++){
658 e->addItem(narrow_to_wide(i->name+" ["+i->gameid+"]").c_str());
660 e->setSelected(m_data->selected_world);
664 else if(m_data->selected_tab == TAB_SETTINGS)
667 core::rect<s32> rect(0, 0, 10, m_size_client.Y);
668 rect += m_topleft_client + v2s32(15, 0);
669 const wchar_t *text = L"S\nE\nT\nT\nI\nN\nG\nS";
670 gui::IGUIStaticText *t =
671 Environment->addStaticText(text, rect, false, true, this, -1);
672 t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
678 core::rect<s32> rect(0, 0, option_w, 30);
679 rect += m_topleft_client + v2s32(option_x, option_y);
680 Environment->addCheckBox(m_data->fancy_trees, rect, this,
681 GUI_ID_FANCYTREE_CB, wgettext("Fancy trees"));
684 core::rect<s32> rect(0, 0, option_w, 30);
685 rect += m_topleft_client + v2s32(option_x, option_y+20);
686 Environment->addCheckBox(m_data->smooth_lighting, rect, this,
687 GUI_ID_SMOOTH_LIGHTING_CB, wgettext("Smooth Lighting"));
690 core::rect<s32> rect(0, 0, option_w, 30);
691 rect += m_topleft_client + v2s32(option_x, option_y+20*2);
692 Environment->addCheckBox(m_data->clouds_3d, rect, this,
693 GUI_ID_3D_CLOUDS_CB, wgettext("3D Clouds"));
696 core::rect<s32> rect(0, 0, option_w, 30);
697 rect += m_topleft_client + v2s32(option_x, option_y+20*3);
698 Environment->addCheckBox(m_data->opaque_water, rect, this,
699 GUI_ID_OPAQUE_WATER_CB, wgettext("Opaque water"));
703 // Anisotropic/mipmap/bi-/trilinear settings
706 core::rect<s32> rect(0, 0, option_w+20, 30);
707 rect += m_topleft_client + v2s32(option_x+175, option_y);
708 Environment->addCheckBox(m_data->mip_map, rect, this,
709 GUI_ID_MIPMAP_CB, wgettext("Mip-Mapping"));
713 core::rect<s32> rect(0, 0, option_w+20, 30);
714 rect += m_topleft_client + v2s32(option_x+175, option_y+20);
715 Environment->addCheckBox(m_data->anisotropic_filter, rect, this,
716 GUI_ID_ANISOTROPIC_CB, wgettext("Anisotropic Filtering"));
720 core::rect<s32> rect(0, 0, option_w+20, 30);
721 rect += m_topleft_client + v2s32(option_x+175, option_y+20*2);
722 Environment->addCheckBox(m_data->bilinear_filter, rect, this,
723 GUI_ID_BILINEAR_CB, wgettext("Bi-Linear Filtering"));
727 core::rect<s32> rect(0, 0, option_w+20, 30);
728 rect += m_topleft_client + v2s32(option_x+175, option_y+20*3);
729 Environment->addCheckBox(m_data->trilinear_filter, rect, this,
730 GUI_ID_TRILINEAR_CB, wgettext("Tri-Linear Filtering"));
733 // shader/on demand image loading/particles settings
735 core::rect<s32> rect(0, 0, option_w+20, 30);
736 rect += m_topleft_client + v2s32(option_x+175*2, option_y);
737 Environment->addCheckBox(m_data->enable_shaders, rect, this,
738 GUI_ID_SHADERS_CB, wgettext("Shaders"));
742 core::rect<s32> rect(0, 0, option_w+20+20, 30);
743 rect += m_topleft_client + v2s32(option_x+175*2, option_y+20);
744 Environment->addCheckBox(m_data->preload_item_visuals, rect, this,
745 GUI_ID_PRELOAD_ITEM_VISUALS_CB, wgettext("Preload item visuals"));
749 core::rect<s32> rect(0, 0, option_w+20+20, 30);
750 rect += m_topleft_client + v2s32(option_x+175*2, option_y+20*2);
751 Environment->addCheckBox(m_data->enable_particles, rect, this,
752 GUI_ID_ENABLE_PARTICLES_CB, wgettext("Enable Particles"));
756 core::rect<s32> rect(0, 0, option_w+20+20, 30);
757 rect += m_topleft_client + v2s32(option_x+175*2, option_y+20*3);
758 Environment->addCheckBox(m_data->liquid_finite, rect, this,
759 GUI_ID_LIQUID_FINITE_CB, wgettext("Finite liquid"));
764 core::rect<s32> rect(0, 0, 120, 30);
765 /*rect += m_topleft_client + v2s32(m_size_client.X-120-30,
766 m_size_client.Y-30-20);*/
767 rect += m_topleft_client + v2s32(option_x, option_y+120);
768 Environment->addButton(rect, this,
769 GUI_ID_CHANGE_KEYS_BUTTON, wgettext("Change keys"));
773 else if(m_data->selected_tab == TAB_CREDITS)
777 core::rect<s32> rect(0, 0, 9, m_size_client.Y);
778 rect += m_topleft_client + v2s32(15, 0);
779 const wchar_t *text = L"C\nR\nE\nD\nI\nT\nS";
780 gui::IGUIStaticText *t =
781 Environment->addStaticText(text, rect, false, true, this, -1);
782 t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
785 core::rect<s32> rect(0, 0, 130, 70);
786 rect += m_topleft_client + v2s32(35, 160);
787 Environment->addStaticText(
788 L"Minetest " LSTRING(VERSION_STRING) L"\nhttp://minetest.net/",
789 rect, false, true, this, -1);
792 video::SColor yellow(255, 255, 255, 0);
793 core::rect<s32> rect(0, 0, 450, 260);
794 rect += m_topleft_client + v2s32(168, 5);
796 irr::gui::IGUIListBox *list = Environment->addListBox(rect, this);
798 list->addItem(L"Core Developers");
799 list->setItemOverrideColor(list->getItemCount() - 1, yellow);
800 for (int i = 0; i != ARRAYLEN(contrib_core_strs); i++)
801 list->addItem(contrib_core_strs[i]);
803 list->addItem(L"Active Contributors");
804 list->setItemOverrideColor(list->getItemCount() - 1, yellow);
805 for (int i = 0; i != ARRAYLEN(contrib_active_strs); i++)
806 list->addItem(contrib_active_strs[i]);
808 list->addItem(L"Previous Contributors");
809 list->setItemOverrideColor(list->getItemCount() - 1, yellow);
810 for (int i = 0; i != ARRAYLEN(contrib_previous_strs); i++)
811 list->addItem(contrib_previous_strs[i]);
816 m_is_regenerating = false;
819 void GUIMainMenu::drawMenu()
821 gui::IGUISkin* skin = Environment->getSkin();
824 video::IVideoDriver* driver = Environment->getVideoDriver();
826 /*video::SColor bgcolor(140,0,0,0);
827 driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);*/
829 video::SColor bgcolor(140,0,0,0);
831 if(getTab() == TAB_SINGLEPLAYER)
834 core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
835 rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
836 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
839 else if(getTab() == TAB_MULTIPLAYER)
842 core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
843 rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
844 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
847 else if(getTab() == TAB_ADVANCED)
850 core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
851 rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
852 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
855 core::rect<s32> rect(0, 0, m_size_server.X, m_size_server.Y);
856 rect += AbsoluteRect.UpperLeftCorner + m_topleft_server;
857 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
860 else if(getTab() == TAB_SETTINGS)
863 core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
864 rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
865 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
868 else if(getTab() == TAB_CREDITS)
871 core::rect<s32> rect(0, 0, m_size_client.X, m_size_client.Y);
872 rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
873 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
875 video::ITexture *logotexture =
876 driver->getTexture(getTexturePath("logo.png").c_str());
879 v2s32 logosize(logotexture->getOriginalSize().Width,
880 logotexture->getOriginalSize().Height);
882 core::rect<s32> rect(0,0,logosize.X,logosize.Y);
883 rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
884 rect += v2s32(50, 60);
885 driver->draw2DImage(logotexture, rect,
886 core::rect<s32>(core::position2d<s32>(0,0),
887 core::dimension2di(logotexture->getSize())),
892 gui::IGUIElement::draw();
895 void GUIMainMenu::readInput(MainMenuData *dst)
898 gui::IGUIElement *e = getElementFromId(GUI_ID_TAB_CONTROL);
899 if(e != NULL && e->getType() == gui::EGUIET_TAB_CONTROL)
900 dst->selected_tab = ((gui::IGUITabControl*)e)->getActiveTab();
902 if(dst->selected_tab == TAB_SINGLEPLAYER)
904 dst->simple_singleplayer_mode = true;
908 dst->simple_singleplayer_mode = false;
910 gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT);
912 dst->name = e->getText();
915 gui::IGUIElement *e = getElementFromId(264);
917 dst->password = e->getText();
920 gui::IGUIElement *e = getElementFromId(GUI_ID_ADDRESS_INPUT);
922 dst->address = e->getText();
925 gui::IGUIElement *e = getElementFromId(GUI_ID_PORT_INPUT);
927 dst->port = e->getText();
931 gui::IGUIElement *e = getElementFromId(GUI_ID_CREATIVE_CB);
932 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
933 dst->creative_mode = ((gui::IGUICheckBox*)e)->isChecked();
936 gui::IGUIElement *e = getElementFromId(GUI_ID_DAMAGE_CB);
937 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
938 dst->enable_damage = ((gui::IGUICheckBox*)e)->isChecked();
941 gui::IGUIElement *e = getElementFromId(GUI_ID_PUBLIC_CB);
942 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
943 dst->enable_public = ((gui::IGUICheckBox*)e)->isChecked();
946 gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB);
947 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
948 dst->fancy_trees = ((gui::IGUICheckBox*)e)->isChecked();
951 gui::IGUIElement *e = getElementFromId(GUI_ID_SMOOTH_LIGHTING_CB);
952 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
953 dst->smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked();
956 gui::IGUIElement *e = getElementFromId(GUI_ID_3D_CLOUDS_CB);
957 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
958 dst->clouds_3d = ((gui::IGUICheckBox*)e)->isChecked();
961 gui::IGUIElement *e = getElementFromId(GUI_ID_OPAQUE_WATER_CB);
962 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
963 dst->opaque_water = ((gui::IGUICheckBox*)e)->isChecked();
967 gui::IGUIElement *e = getElementFromId(GUI_ID_MIPMAP_CB);
968 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
969 dst->mip_map = ((gui::IGUICheckBox*)e)->isChecked();
973 gui::IGUIElement *e = getElementFromId(GUI_ID_ANISOTROPIC_CB);
974 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
975 dst->anisotropic_filter = ((gui::IGUICheckBox*)e)->isChecked();
979 gui::IGUIElement *e = getElementFromId(GUI_ID_BILINEAR_CB);
980 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
981 dst->bilinear_filter = ((gui::IGUICheckBox*)e)->isChecked();
985 gui::IGUIElement *e = getElementFromId(GUI_ID_TRILINEAR_CB);
986 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
987 dst->trilinear_filter = ((gui::IGUICheckBox*)e)->isChecked();
991 gui::IGUIElement *e = getElementFromId(GUI_ID_SHADERS_CB);
992 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
993 dst->enable_shaders = ((gui::IGUICheckBox*)e)->isChecked() ? 2 : 0;
997 gui::IGUIElement *e = getElementFromId(GUI_ID_PRELOAD_ITEM_VISUALS_CB);
998 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
999 dst->preload_item_visuals = ((gui::IGUICheckBox*)e)->isChecked();
1003 gui::IGUIElement *e = getElementFromId(GUI_ID_ENABLE_PARTICLES_CB);
1004 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
1005 dst->enable_particles = ((gui::IGUICheckBox*)e)->isChecked();
1009 gui::IGUIElement *e = getElementFromId(GUI_ID_LIQUID_FINITE_CB);
1010 if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
1011 dst->liquid_finite = ((gui::IGUICheckBox*)e)->isChecked();
1015 gui::IGUIElement *e = getElementFromId(GUI_ID_WORLD_LISTBOX);
1016 if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX)
1017 dst->selected_world = ((gui::IGUIListBox*)e)->getSelected();
1020 ServerListSpec server =
1021 getServerListSpec(wide_to_narrow(dst->address), wide_to_narrow(dst->port));
1022 dst->servername = server["name"].asString();
1023 dst->serverdescription = server["description"].asString();
1027 void GUIMainMenu::acceptInput()
1033 bool GUIMainMenu::OnEvent(const SEvent& event)
1035 if(event.EventType==EET_KEY_INPUT_EVENT)
1037 if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
1039 m_gamecallback->exitToOS();
1043 if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
1050 if(event.EventType==EET_GUI_EVENT)
1052 if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
1055 if(!canTakeFocus(event.GUIEvent.Element))
1057 dstream<<"GUIMainMenu: Not allowing focus change."
1059 // Returning true disables focus change
1063 if(event.GUIEvent.EventType==gui::EGET_TAB_CHANGED)
1065 if(!m_is_regenerating)
1066 regenerateGui(m_screensize_old);
1069 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED && event.GUIEvent.Caller->getID() == GUI_ID_SERVERLIST)
1071 serverListOnSelected();
1074 if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
1076 switch(event.GUIEvent.Caller->getID())
1078 case GUI_ID_JOIN_GAME_BUTTON: {
1081 if (getTab() == TAB_MULTIPLAYER && cur.address == L"")
1083 (new GUIMessageMenu(env, parent, -1, menumgr,
1084 wgettext("Address required."))
1092 case GUI_ID_CHANGE_KEYS_BUTTON: {
1093 GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(env, parent, -1,menumgr);
1097 case GUI_ID_DELETE_WORLD_BUTTON: {
1100 if(cur.selected_world == -1){
1101 (new GUIMessageMenu(env, parent, -1, menumgr,
1102 wgettext("Cannot delete world: Nothing selected"))
1105 WorldSpec spec = m_data->worlds[cur.selected_world];
1106 // Get files and directories involved
1107 std::vector<std::string> paths;
1108 paths.push_back(spec.path);
1109 fs::GetRecursiveSubPaths(spec.path, paths);
1110 // Launch confirmation dialog
1111 ConfirmDestDeleteWorld *dest = new
1112 ConfirmDestDeleteWorld(spec, this, paths);
1113 std::wstring text = wgettext("Delete world");
1115 text += narrow_to_wide(spec.name);
1117 text += wgettext("Files to be deleted");
1119 for(u32 i=0; i<paths.size(); i++){
1120 if(i == 3){ text += L"..."; break; }
1121 text += narrow_to_wide(paths[i]) + L"\n";
1123 (new GUIConfirmMenu(env, parent, -1, menumgr, dest,
1124 text.c_str()))->drop();
1128 case GUI_ID_CREATE_WORLD_BUTTON: {
1129 std::vector<SubgameSpec> games = getAvailableGames();
1130 if(games.size() == 0){
1131 GUIMessageMenu *menu = new GUIMessageMenu(env, parent,
1133 wgettext("Cannot create world: No games found"));
1136 CreateWorldDest *dest = new CreateWorldDestMainMenu(this);
1137 GUICreateWorld *menu = new GUICreateWorld(env, parent, -1,
1138 menumgr, dest, games);
1143 case GUI_ID_CONFIGURE_WORLD_BUTTON: {
1146 if(cur.selected_world == -1)
1148 (new GUIMessageMenu(env, parent, -1, menumgr,
1149 wgettext("Cannot configure world: Nothing selected"))
1154 WorldSpec wspec = m_data->worlds[cur.selected_world];
1155 GUIConfigureWorld *menu = new GUIConfigureWorld(env, parent,
1156 -1, menumgr, wspec);
1161 case GUI_ID_SERVERLIST_DELETE: {
1162 gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
1163 s32 selected = ((gui::IGUIListBox*)serverlist)->getSelected();
1164 if (selected == -1) return true;
1165 ServerList::deleteEntry(m_data->servers[selected]);
1166 m_data->servers = ServerList::getLocal();
1167 updateGuiServerList();
1170 serverlist->setSelected(selected);
1171 serverListOnSelected();
1175 case GUI_ID_SERVERLIST_TOGGLE: {
1176 gui::IGUIElement *togglebutton = getElementFromId(GUI_ID_SERVERLIST_TOGGLE);
1177 gui::IGUIElement *deletebutton = getElementFromId(GUI_ID_SERVERLIST_DELETE);
1178 gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
1179 gui::IGUIElement *title = getElementFromId(GUI_ID_SERVERLIST_TITLE);
1180 if (m_data->selected_serverlist == SERVERLIST_PUBLIC) // switch to favorite list
1182 m_data->servers = ServerList::getLocal();
1183 togglebutton->setText(wgettext("Show Public"));
1184 title->setText(wgettext("Favorites:"));
1185 deletebutton->setVisible(true);
1186 updateGuiServerList();
1187 serverlist->setSelected(0);
1188 m_data->selected_serverlist = SERVERLIST_FAVORITES;
1190 else // switch to online list
1192 m_data->servers = ServerList::getOnline();
1193 togglebutton->setText(wgettext("Show Favorites"));
1194 title->setText(wgettext("Public Server List:"));
1195 deletebutton->setVisible(false);
1196 updateGuiServerList();
1197 serverlist->setSelected(0);
1198 m_data->selected_serverlist = SERVERLIST_PUBLIC;
1200 serverListOnSelected();
1205 if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER)
1207 switch(event.GUIEvent.Caller->getID())
1209 case GUI_ID_ADDRESS_INPUT: case GUI_ID_PORT_INPUT: case GUI_ID_NAME_INPUT: case 264:
1215 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN)
1217 switch(event.GUIEvent.Caller->getID())
1219 case GUI_ID_WORLD_LISTBOX:
1221 if(getTab() != TAB_SINGLEPLAYER)
1222 m_data->address = L""; // Force local game
1225 case GUI_ID_SERVERLIST:
1226 gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
1227 if (serverlist->getSelected() > -1)
1237 return Parent ? Parent->OnEvent(event) : false;
1240 void GUIMainMenu::createNewWorld(std::wstring name, std::string gameid)
1245 m_data->create_world_name = name;
1246 m_data->create_world_gameid = gameid;
1250 void GUIMainMenu::deleteWorld(const std::vector<std::string> &paths)
1253 bool did = fs::DeletePaths(paths);
1255 GUIMessageMenu *menu = new GUIMessageMenu(env, parent,
1256 -1, menumgr, wgettext("Failed to delete all world files"));
1259 // Quit menu to refresh it
1261 m_data->only_refresh = true;
1265 int GUIMainMenu::getTab()
1267 gui::IGUIElement *e = getElementFromId(GUI_ID_TAB_CONTROL);
1268 if(e != NULL && e->getType() == gui::EGUIET_TAB_CONTROL)
1269 return ((gui::IGUITabControl*)e)->getActiveTab();
1270 return TAB_SINGLEPLAYER; // Default
1273 void GUIMainMenu::displayMessageMenu(std::wstring msg)
1275 (new GUIMessageMenu(env, parent, -1, menumgr, msg))->drop();
1278 void GUIMainMenu::updateGuiServerList()
1280 gui::IGUIListBox *serverlist = (gui::IGUIListBox *)getElementFromId(GUI_ID_SERVERLIST);
1281 serverlist->clear();
1283 for(std::vector<ServerListSpec>::iterator i = m_data->servers.begin();
1284 i != m_data->servers.end(); i++)
1288 if ((*i)["clients"].asString().size())
1289 text += (*i)["clients"].asString();
1290 if ((*i)["clients_max"].asString().size())
1291 text += "/" + (*i)["clients_max"].asString();
1293 if ((*i)["version"].asString().size())
1294 text += (*i)["version"].asString() + " ";
1295 if ((*i)["password"].asString().size())
1297 if ((*i)["creative"].asString().size())
1299 if ((*i)["damage"].asString().size())
1301 if ((*i)["pvp"].asString().size())
1305 if ((*i)["name"] != "" && (*i)["description"] != "")
1306 text += (*i)["name"].asString() + " (" + (*i)["description"].asString() + ")";
1307 else if ((*i)["name"] !="")
1308 text += (*i)["name"].asString();
1310 text += (*i)["address"].asString() + ":" + (*i)["port"].asString();
1312 serverlist->addItem(narrow_to_wide(text).c_str());
1316 void GUIMainMenu::serverListOnSelected()
1318 if (!m_data->servers.empty())
1320 gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
1321 u16 id = serverlist->getSelected();
1322 //if (id < 0) return; // u16>0!
1323 ((gui::IGUIEditBox*)getElementFromId(GUI_ID_ADDRESS_INPUT))
1324 ->setText(narrow_to_wide(m_data->servers[id]["address"].asString()).c_str());
1325 ((gui::IGUIEditBox*)getElementFromId(GUI_ID_PORT_INPUT))
1326 ->setText(narrow_to_wide(m_data->servers[id]["port"].asString()).c_str());
1330 ServerListSpec GUIMainMenu::getServerListSpec(std::string address, std::string port)
1332 ServerListSpec server;
1333 server["address"] = address;
1334 server["port"] = port;
1335 for(std::vector<ServerListSpec>::iterator i = m_data->servers.begin();
1336 i != m_data->servers.end(); i++)
1338 if ((*i)["address"] == address && (*i)["port"] == port)
1340 server["description"] = (*i)["description"];
1341 server["name"] = (*i)["name"];