aboutsummaryrefslogtreecommitdiff
path: root/src/script
Commit message (Expand)AuthorAge
* Fix crash regression when invsize formspec gets usedest312015-10-17
* Use warningstream for deprecated field messages and refactor log_deprecatedShadowNinja2015-10-15
* Rename macros with two leading underscoresShadowNinja2015-10-14
* Refactor loggingShadowNinja2015-10-14
* Add new ContentParamType2 "CPT2_DEGROTATE"est312015-10-04
* Allow setting chunksize in core.set_mapgen_paramskwolekr2015-10-04
* Hide mapgens from main menu not intended for end userskwolekr2015-10-04
* Add emerge completion callback mechanismkwolekr2015-10-04
* Define and use limit constants for Irrlicht fixed-width typeskwolekr2015-10-04
* Add get_biome_id(biome_name) callbackDuane Robertson2015-10-02
* Add /emergeblocks command and core.emerge_area() Lua APIkwolekr2015-09-23
* Various style cleanups + unused code removalest312015-09-19
* Ore: Add puff ore typekwolekr2015-09-17
* Ore: Add ore sheet column height range selectionkwolekr2015-09-13
* Areastore: fix "attempt to index a number value"est312015-09-03
* l_mainmenu.h: remove unused l_get_dirlist functionest312015-08-30
* Push error handler afresh each time lua_pcall is usedKahrl2015-08-27
* Use numeric indices and raw table access with LUA_REGISTRYINDEXKahrl2015-08-27
* Clean up threadingShadowNinja2015-08-23
* SAPI: Disable unlockable time profilingkwolekr2015-08-18
* SEnv: Remove static_exists from ActiveObjects in deleted blockskwolekr2015-08-16
* minimap: Add ability to disable from serverkwolekr2015-08-13
* SAPI: Track last executed mod and include in error messageskwolekr2015-08-12
* Display Lua memory usage at the time of Out-of-Memory errorkwolekr2015-08-10
* Improve Script CPP API diagnosticskwolekr2015-08-05
* Fix tiling issues for PLANTLIKE and FIRELIKE with FSAARealBadAngel2015-08-05
* Biome API: Make fallback biome stone and water, disable fillerparamat2015-08-03
* Add AreaStore data structureest312015-07-27
* Fix MSVC number conversion warningSmallJoker2015-07-25
* Fix minetest.get_(all)_craft_recipe(s) regressionest312015-07-25
* Cleanup server addparticle(spawner) by merge two identical functions.Loic Blot2015-07-25
* Optional reconnect functionalityest312015-07-23
* Added get_player_velocity() method. Fixes #1176Elia Argentieri2015-07-20
* Refactor particle code to remove the while loopsTeTpaAka2015-07-18
* Make acc and vel deprecated in add_particle and search for acceleration and v...TeTpaAka2015-07-18
* Fix invisible player when the attached entity is removedTeTpaAka2015-07-18
* Fix relief mapping issuesRealBadAngel2015-07-16
* Fix damage flash when damage disabledkwolekr2015-07-10
* Use UTF-8 instead of narrowest312015-07-08
* Fix code style from recent commits and add misc. optimizationskwolekr2015-07-02
* Add Lua errors to error dialogrubenwardy2015-06-29
* Fix bug when craft input isn't replacedTeTpaAka2015-06-22
* Fix some issues with animations, and allow non-looped animations to be definedMirceaKitsune2015-06-22
* Mapgen objects: Enable heatmap and humidmap for all biome api mapgensparamat2015-06-20
* Use utf-8 in formspecsIlya Zhuravlev2015-06-13
* Add minetest.register_on_player_hpchangeTeTpaAka2015-06-13
* Add return list of individual counts to find_node_in_areaTeTpaAka2015-06-13
* dofile error reporting for syntax errorsest312015-06-12
* Fix uninitialized variable errorest312015-06-02
* Make get_biome_list() error message more helpfulkwolekr2015-05-28
id='n435' href='#n435'>435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/


#include <iostream> 
#include <string>
#include <map>

#include "guiConfigureWorld.h"
#include "guiMessageMenu.h"
#include <IGUIButton.h>
#include <IGUICheckBox.h>
#include <IGUIListBox.h>
#include <IGUIStaticText.h>
#include <IGUITreeView.h>
#include "gettext.h"
#include "util/string.h"
#include "settings.h"
#include "filesys.h"

enum
{
	GUI_ID_MOD_TREEVIEW = 101,
	GUI_ID_ENABLED_CHECKBOX,
	GUI_ID_ENABLEALL,
	GUI_ID_DISABLEALL,
	GUI_ID_DEPENDS_LISTBOX,
	GUI_ID_RDEPENDS_LISTBOX,
	GUI_ID_CANCEL,
	GUI_ID_SAVE
};

#define QUESTIONMARK_STR L"?"
#define CHECKMARK_STR    L"\411"
#define CROSS_STR        L"\403"

GUIConfigureWorld::GUIConfigureWorld(gui::IGUIEnvironment* env,
		gui::IGUIElement* parent, s32 id,
		IMenuManager *menumgr, WorldSpec wspec):
	GUIModalMenu(env, parent, id, menumgr),
	m_wspec(wspec),
	m_gspec(findWorldSubgame(m_wspec.path)),
	m_menumgr(menumgr)
{
	//will be initialized in regenerateGUI()
	m_treeview=NULL;

	// game mods
	m_gamemods = flattenModTree(getModsInPath(m_gspec.gamemods_path));

	// world mods
	std::string worldmods_path = wspec.path + DIR_DELIM + "worldmods";
	m_worldmods = flattenModTree(getModsInPath(worldmods_path));

	// fill m_addontree with add-on mods
	std::set<std::string> paths = m_gspec.addon_mods_paths;
	for(std::set<std::string>::iterator it=paths.begin();
		it != paths.end(); ++it)
	{
		std::map<std::string,ModSpec> mods = getModsInPath(*it);
		m_addontree.insert(mods.begin(), mods.end());
	}

	// expand modpacks
	m_addonmods = flattenModTree(m_addontree);

	// collect reverse dependencies
	for(std::map<std::string, ModSpec>::iterator it = m_addonmods.begin();
		it != m_addonmods.end(); ++it)
	{
		std::string modname = (*it).first;
		ModSpec mod = (*it).second;
		for(std::set<std::string>::iterator dep_it = mod.depends.begin();
			dep_it != mod.depends.end(); ++dep_it)
		{
			m_reverse_depends.insert(std::make_pair((*dep_it),modname));
		}
	}

	m_settings.readConfigFile((m_wspec.path + DIR_DELIM + "world.mt").c_str());
	std::vector<std::string> names = m_settings.getNames();

	// mod_names contains the names of mods mentioned in the world.mt file
	std::set<std::string> mod_names;
	for(std::vector<std::string>::iterator it = names.begin(); 
		it != names.end(); ++it)
	{	
		std::string name = *it;  
		if (name.compare(0,9,"load_mod_")==0)
			mod_names.insert(name.substr(9));
	}

	// find new mods (installed but not mentioned in world.mt)
	for(std::map<std::string, ModSpec>::iterator it = m_addonmods.begin();
		it != m_addonmods.end(); ++it)
	{
		std::string modname = (*it).first;
		ModSpec mod = (*it).second;
		// a mod is new if it is not a modpack, and does not occur in
		// mod_names
		if(!mod.is_modpack &&
		   mod_names.count(modname) == 0)
			m_new_mod_names.insert(modname);
	}
	if(!m_new_mod_names.empty())
	{
		GUIMessageMenu *menu = 
			new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
							   wgettext("Warning: Some mods are not configured yet.\n" 
										"They will be enabled by default when you save the configuration.  ")); 
		menu->drop();
	}
	

	// find missing mods (mentioned in world.mt, but not installed)
	std::set<std::string> missing_mods;
	for(std::set<std::string>::iterator it = mod_names.begin();
		it != mod_names.end(); ++it)
	{
		std::string modname = *it;
		if(m_addonmods.count(modname) == 0)
			missing_mods.insert(modname);
	}
	if(!missing_mods.empty())
	{
		GUIMessageMenu *menu = 
			new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
							   wgettext("Warning: Some configured mods are missing.\n"
										"Their setting will be removed when you save the configuration.  ")); 
		for(std::set<std::string>::iterator it = missing_mods.begin();
			it != missing_mods.end(); ++it)
			m_settings.remove("load_mod_"+(*it));
		menu->drop();
	}	
}

void GUIConfigureWorld::drawMenu()
{
	gui::IGUISkin* skin = Environment->getSkin();
	if (!skin)
		return;
	video::IVideoDriver* driver = Environment->getVideoDriver();
	
	video::SColor bgcolor(140,0,0,0);
	driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);

	gui::IGUIElement::draw();
}


void GUIConfigureWorld::regenerateGui(v2u32 screensize)
{

	/*
		Remove stuff
	*/
	removeChildren();
	
	/*
		Calculate new sizes and positions
	*/
	core::rect<s32> rect(
			screensize.X/2 - 580/2,
			screensize.Y/2 - 300/2,
			screensize.X/2 + 580/2,
			screensize.Y/2 + 300/2
	);
	
	DesiredRect = rect;
	recalculateAbsolutePosition(false);

	v2s32 size = rect.getSize();

	v2s32 topleft = v2s32(10, 10);

	/*
		Add stuff
	*/
	changeCtype("");
	{
		core::rect<s32> rect(0, 0, 200, 20);
		rect += topleft;
		//proper text is set below, when a mod is selected
		m_modname_text = Environment->addStaticText(L"Mod: N/A", rect, false, 
													false, this, -1);
	}
	{
		core::rect<s32> rect(0, 0, 200, 20);
		rect += v2s32(0, 25) + topleft;
		m_enabled_checkbox = 
			Environment->addCheckBox(false, rect, this, GUI_ID_ENABLED_CHECKBOX, 
									 wgettext("enabled"));
		m_enabled_checkbox->setVisible(false);
	}
	{
		core::rect<s32> rect(0, 0, 85, 30);
		rect = rect + v2s32(0, 25) + topleft;
		m_enableall = Environment->addButton(rect, this, GUI_ID_ENABLEALL,
											 wgettext("Enable All"));
		m_enableall->setVisible(false);
	}
	{
		core::rect<s32> rect(0, 0, 85, 30);
		rect = rect + v2s32(115, 25) + topleft;
		m_disableall = Environment->addButton(rect, this, GUI_ID_DISABLEALL,
											  wgettext("Disable All"));
		m_disableall->setVisible(false);
	}
	{
		core::rect<s32> rect(0, 0, 200, 20);
		rect += v2s32(0, 60) + topleft;
		Environment->addStaticText(wgettext("depends on:"),
			rect, false, false, this, -1);
	}
	{
		core::rect<s32> rect(0, 0, 200, 85);
		rect += v2s32(0, 80) + topleft;
		m_dependencies_listbox = 
			Environment->addListBox(rect, this, GUI_ID_DEPENDS_LISTBOX, true);
	}
	{
		core::rect<s32> rect(0, 0, 200, 20);
		rect += v2s32(0, 175) + topleft;
		Environment->addStaticText(wgettext("is required by:"),
					rect, false, false, this, -1);
	}
	{
		core::rect<s32> rect(0, 0, 200, 85);
		rect += v2s32(0, 195) + topleft;
		m_rdependencies_listbox = 
			Environment->addListBox(rect,this, GUI_ID_RDEPENDS_LISTBOX,true);
	}
	{
		core::rect<s32> rect(0, 0, 340, 250);
		rect += v2s32(220, 0) + topleft;
		m_treeview = Environment->addTreeView(rect, this,
											  GUI_ID_MOD_TREEVIEW,true);
		gui::IGUITreeViewNode* node 
			= m_treeview->getRoot()->addChildBack(L"Add-Ons");
		buildTreeView(m_addontree, node);
	}
	{
		core::rect<s32> rect(0, 0, 120, 30);
		rect = rect + v2s32(330, 270) - topleft;
		Environment->addButton(rect, this, GUI_ID_CANCEL,
			wgettext("Cancel"));
	}
	{
		core::rect<s32> rect(0, 0, 120, 30);
		rect = rect + v2s32(460, 270) - topleft;
		Environment->addButton(rect, this, GUI_ID_SAVE,
			wgettext("Save"));
	}
	changeCtype("C");

	// at start, none of the treeview nodes is selected, so we select
	// the first element in the treeview of mods manually here.
	if(m_treeview->getRoot()->hasChilds())
	{
		m_treeview->getRoot()->getFirstChild()->setExpanded(true);
		m_treeview->getRoot()->getFirstChild()->setSelected(true);
		// Because a manual ->setSelected() doesn't cause an event, we
		// have to do this here:
		adjustSidebar();
	}
}

bool GUIConfigureWorld::OnEvent(const SEvent& event)
{

	gui::IGUITreeViewNode* selected_node = NULL;
	if(m_treeview != NULL)
		selected_node = m_treeview->getSelected();

	if(event.EventType==EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
	{
		switch (event.KeyInput.Key) {
		case KEY_ESCAPE: {
			quitMenu();
			return true;
		}
		//	irrlicht's built-in TreeView gui has no keyboard control,
		//	so we do it here: up/down to select prev/next node,
		//	left/right to collapse/expand nodes, space to toggle
		//	enabled/disabled.
		case KEY_DOWN: {
			if(selected_node != NULL)
			{
				gui::IGUITreeViewNode* node = selected_node->getNextVisible();
				if(node != NULL)
				{
					node->setSelected(true);
					adjustSidebar();
				}
			}
			return true;
		}
		case KEY_UP: {
			if(selected_node != NULL)
			{
				gui::IGUITreeViewNode* node = selected_node->getPrevSibling();
				if(node!=NULL)
				{
					node->setSelected(true);
					adjustSidebar();
				}
				else 
				{
					gui::IGUITreeViewNode* parent = selected_node->getParent();
					if(selected_node == parent->getFirstChild() &&
					   parent != m_treeview->getRoot()) 
					{
						parent->setSelected(true);
						adjustSidebar();
					}
				}
			}
			return true;
		}
		case KEY_RIGHT: {
			if(selected_node != NULL && selected_node->hasChilds())
				selected_node->setExpanded(true);
			return true;
		}
		case KEY_LEFT: {
			if(selected_node != NULL && selected_node->hasChilds())
				selected_node->setExpanded(false);
			return true;
		}
		case KEY_SPACE: {
			if(selected_node != NULL && !selected_node->hasChilds() && 
			   selected_node->getText() != NULL)
			{
				std::string modname = wide_to_narrow(selected_node->getText());
				bool checked = m_enabled_checkbox->isChecked();
				m_enabled_checkbox->setChecked(!checked);
				setEnabled(modname,!checked);
			}
			return true;
		}
		default: {}
		}
	}
	if(event.EventType==EET_GUI_EVENT)
	{
		if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
				&& isVisible())
		{
			if(!canTakeFocus(event.GUIEvent.Element))
			{
				dstream<<"GUIConfigureWorld: Not allowing focus change."
						<<std::endl;
				// Returning true disables focus change
				return true;
			}
		}
		if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED){
			switch(event.GUIEvent.Caller->getID()){
			case GUI_ID_CANCEL: {
				quitMenu();
				return true;
			}
			case GUI_ID_SAVE: {
				for(std::set<std::string>::iterator it = m_new_mod_names.begin();
					it!= m_new_mod_names.end(); ++it)
				{
					m_settings.setBool("load_mod_"+(*it),true);
				}
				std::string worldmtfile = m_wspec.path+DIR_DELIM+"world.mt";
				m_settings.updateConfigFile(worldmtfile.c_str());

				// The trailing spaces are because there seems to be a
				// bug in the text-size calculation. if the trailing
				// spaces are removed from the message text, the
				// message gets wrapped and parts of it are cut off:
				GUIMessageMenu *menu = 
					new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
									   wgettext("Configuration saved.  "));
				menu->drop();

				ModConfiguration modconf(m_wspec.path);
				if(!modconf.isConsistent())
				{
					GUIMessageMenu *menu = 
						new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
										   wgettext("Warning: Configuration not consistent.  "));
					menu->drop();
				}

				quitMenu();	
				return true;
			}
			case GUI_ID_ENABLEALL: {
				if(selected_node != NULL && selected_node->getParent() == m_treeview->getRoot())
				{  
					enableAllMods(m_addonmods,true);
				} 
				else if(selected_node != NULL && selected_node->getText() != NULL)
				{  
					std::string modname = wide_to_narrow(selected_node->getText());
					std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
					if(mod_it != m_addonmods.end())
						enableAllMods(mod_it->second.modpack_content,true);
				}
				return true;
			}
			case GUI_ID_DISABLEALL: {
				if(selected_node != NULL && selected_node->getParent() == m_treeview->getRoot())
				{
					enableAllMods(m_addonmods,false);
				} 
				if(selected_node != NULL && selected_node->getText() != NULL)
				{
					std::string modname = wide_to_narrow(selected_node->getText());
					std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
					if(mod_it != m_addonmods.end())
						enableAllMods(mod_it->second.modpack_content,false);
				}
				return true;
			}
			}
		}	
		if(event.GUIEvent.EventType==gui::EGET_CHECKBOX_CHANGED &&
			event.GUIEvent.Caller->getID() == GUI_ID_ENABLED_CHECKBOX)
		{
			if(selected_node != NULL && !selected_node->hasChilds() && 
			   selected_node->getText() != NULL)
			{
				std::string modname = wide_to_narrow(selected_node->getText());
				setEnabled(modname, m_enabled_checkbox->isChecked());
			}
			return true;
		}
		if(event.GUIEvent.EventType==gui::EGET_TREEVIEW_NODE_SELECT &&
		   event.GUIEvent.Caller->getID() == GUI_ID_MOD_TREEVIEW)
		{
			selecting_dep = -1;
			selecting_rdep = -1;
			adjustSidebar();
			return true;
		}
		if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED &&
		   event.GUIEvent.Caller->getID() == GUI_ID_DEPENDS_LISTBOX)
		{
			selecting_dep = m_dependencies_listbox->getSelected();
			selecting_rdep = -1;
			return true;
		}
		if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED &&
		   event.GUIEvent.Caller->getID() == GUI_ID_RDEPENDS_LISTBOX)
		{
			selecting_dep = -1;
			selecting_rdep = m_rdependencies_listbox->getSelected();
			return true;
		}

		//double click in a dependency listbox: find corresponding
		//treeviewnode and select it:
		if(event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN)
		{
			gui::IGUIListBox* box = NULL;
			if(event.GUIEvent.Caller->getID() == GUI_ID_DEPENDS_LISTBOX)
			{
				box = m_dependencies_listbox;
				if(box->getSelected() != selecting_dep)
					return true;
			}
			if(event.GUIEvent.Caller->getID() == GUI_ID_RDEPENDS_LISTBOX)
			{
				box = m_rdependencies_listbox;
				if(box->getSelected() != selecting_rdep)
					return true;
			}
			if(box != NULL && box->getSelected() != -1 &&
			   box->getListItem(box->getSelected()) != NULL)
			{
				std::string modname = 
					wide_to_narrow(box->getListItem(box->getSelected()));
				std::map<std::string, gui::IGUITreeViewNode*>::iterator it =
					m_nodes.find(modname);
				if(it != m_nodes.end())
				{
					// select node and make sure node is visible by
					// expanding all parents
					gui::IGUITreeViewNode* node = (*it).second;
					node->setSelected(true);
					while(!node->isVisible() && 
						  node->getParent() != m_treeview->getRoot())
					{
						node = node->getParent();
						node->setExpanded(true);
					}
					adjustSidebar();
				}
			}
			return true;
		}
	}

	return Parent ? Parent->OnEvent(event) : false;
}

void GUIConfigureWorld::buildTreeView(std::map<std::string, ModSpec> mods, 
									  gui::IGUITreeViewNode* node)
{
	for(std::map<std::string,ModSpec>::iterator it = mods.begin();
		it != mods.end(); ++it)    
	{
		std::string modname = (*it).first;
		ModSpec mod = (*it).second;
		gui::IGUITreeViewNode* new_node = 
			node->addChildBack(narrow_to_wide(modname).c_str());
		m_nodes.insert(std::make_pair(modname, new_node));
		if(mod.is_modpack)
			buildTreeView(mod.modpack_content, new_node);
		else
		{
			// set icon for node: ? for new mods, x for disabled mods,
			// checkmark for enabled mods
			if(m_new_mod_names.count(modname) > 0)
			{
				new_node->setIcon(QUESTIONMARK_STR);
			}
			else
			{
				bool mod_enabled = true;
				if(m_settings.exists("load_mod_"+modname))
					mod_enabled = m_settings.getBool("load_mod_"+modname);
				if(mod_enabled)
					new_node->setIcon(CHECKMARK_STR);
				else 
					new_node->setIcon(CROSS_STR);
			}
		}
	}
}


void GUIConfigureWorld::adjustSidebar()
{
	gui::IGUITreeViewNode* node = m_treeview->getSelected();
	std::wstring modname_w;
	if(node->getText() != NULL)
		modname_w = node->getText();
	else 
		modname_w = L"N/A";
	std::string modname = wide_to_narrow(modname_w);

	ModSpec mspec;
	std::map<std::string, ModSpec>::iterator it = m_addonmods.find(modname);
	if(it != m_addonmods.end())
		mspec = it->second;

	m_dependencies_listbox->clear();
	m_rdependencies_listbox->clear();

	// if no mods installed, there is nothing to enable/disable, so we
	// don't show buttons or checkbox on the sidebar
	if(node->getParent() == m_treeview->getRoot() && !node->hasChilds())
	{
		m_disableall->setVisible(false);
		m_enableall->setVisible(false);
		m_enabled_checkbox->setVisible(false);
		return;
	} 
	
    // a modpack is not enabled/disabled by itself, only its cotnents
    // are. so we show show enable/disable all buttons, but hide the
    // checkbox
	if(node->getParent() == m_treeview->getRoot() ||
	   mspec.is_modpack)
	{
		m_enabled_checkbox->setVisible(false);
		m_disableall->setVisible(true);
		m_enableall->setVisible(true);
		m_modname_text->setText((L"Modpack: "+modname_w).c_str());
		return;
	}	

	// for a normal mod, we hide the enable/disable all buttons, but show the checkbox.
	m_disableall->setVisible(false);
	m_enableall->setVisible(false);
	m_enabled_checkbox->setVisible(true);
	m_modname_text->setText((L"Mod: "+modname_w).c_str());

	// the mod is enabled unless it is disabled in the world.mt settings. 
	bool mod_enabled = true;
	if(m_settings.exists("load_mod_"+modname))
		mod_enabled = m_settings.getBool("load_mod_"+modname);
	m_enabled_checkbox->setChecked(mod_enabled);

	for(std::set<std::string>::iterator it=mspec.depends.begin();
		it != mspec.depends.end(); ++it)
	{
		// check if it is an add-on mod or a game/world mod. We only
		// want to show add-ons
		std::string dependency = (*it);
		if(m_gamemods.count(dependency) > 0)
			dependency += " (" + m_gspec.id + ")";
		else if(m_worldmods.count(dependency) > 0)
			dependency += " (" + m_wspec.name + ")";
		else if(m_addonmods.count(dependency) == 0)
			dependency += " (missing)";
		m_dependencies_listbox->addItem(narrow_to_wide(dependency).c_str());
	}

	// reverse dependencies of this mod:
	std::pair< std::multimap<std::string, std::string>::iterator, 
			std::multimap<std::string, std::string>::iterator > rdep = 
		m_reverse_depends.equal_range(modname);
	for(std::multimap<std::string,std::string>::iterator it = rdep.first;
		it != rdep.second; ++it)
	{
		// check if it is an add-on mod or a game/world mod. We only
		// want to show add-ons
		std::string rdependency = (*it).second;
		if(m_addonmods.count(rdependency) > 0)
			m_rdependencies_listbox->addItem(narrow_to_wide(rdependency).c_str());
	}
}

void GUIConfigureWorld::enableAllMods(std::map<std::string, ModSpec> mods,bool enable)
{
	for(std::map<std::string, ModSpec>::iterator it = mods.begin();
		it != mods.end(); ++it)
	{
		ModSpec mod = (*it).second;
		if(mod.is_modpack) 
			// a modpack, recursively enable all mods in it
			enableAllMods(mod.modpack_content,enable);
		else // not a modpack
			setEnabled(mod.name, enable);

	}
}

void GUIConfigureWorld::enableMod(std::string modname)
{
	std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
	if(mod_it == m_addonmods.end()){
		errorstream << "enableMod() called with invalid mod name \"" << modname << "\"" << std::endl;
		return;
	}
	ModSpec mspec = mod_it->second;
	m_settings.setBool("load_mod_"+modname,true);
	std::map<std::string,gui::IGUITreeViewNode*>::iterator it = 
		m_nodes.find(modname);
	if(it != m_nodes.end())
		(*it).second->setIcon(CHECKMARK_STR);
	m_new_mod_names.erase(modname);
	//also enable all dependencies
	for(std::set<std::string>::iterator it=mspec.depends.begin();
		it != mspec.depends.end(); ++it)
	{
		std::string dependency = *it;
		// only enable it if it is an add-on mod
		if(m_addonmods.count(dependency) > 0)
			enableMod(dependency);
	}
}

void GUIConfigureWorld::disableMod(std::string modname)
{
	std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
	if(mod_it == m_addonmods.end()){
		errorstream << "disableMod() called with invalid mod name \"" << modname << "\"" << std::endl;
		return;
	}

	m_settings.setBool("load_mod_"+modname,false);
	std::map<std::string,gui::IGUITreeViewNode*>::iterator it = 
		m_nodes.find(modname);
 	if(it != m_nodes.end())
		(*it).second->setIcon(CROSS_STR);
	m_new_mod_names.erase(modname);
	//also disable all mods that depend on this one
	std::pair<std::multimap<std::string, std::string>::iterator, 
			  std::multimap<std::string, std::string>::iterator > rdep = 
		m_reverse_depends.equal_range(modname);
	for(std::multimap<std::string,std::string>::iterator it = rdep.first;
		it != rdep.second; ++it)
	{
		std::string rdependency = (*it).second;
		// only disable it if it is an add-on mod
		if(m_addonmods.count(rdependency) > 0)
			disableMod(rdependency);
	}	
}