aboutsummaryrefslogtreecommitdiff
path: root/builtin/mainmenu/tab_mods.lua
blob: 2ddc9b07cbfa516a18eb9a2963289b5f608d7cf6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
--Minetest
--Copyright (C) 2014 sapier
--
--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.

--------------------------------------------------------------------------------
local function get_formspec(tabview, name, tabdata)

	if modmgr.global_mods == nil then
		modmgr.refresh_globals()
	end

	if tabdata.selected_mod == nil then
		tabdata.selected_mod = 1
	end

	local retval =
		"label[0.05,-0.25;".. fgettext("Installed Mods:") .. "]" ..
		"textlist[0,0.25;5.1,4.35;modlist;" ..
		modmgr.render_modlist(modmgr.global_mods) ..
		";" .. tabdata.selected_mod .. "]"

	retval = retval ..
--		"label[0.8,4.2;" .. fgettext("Add mod:") .. "]" ..
--		TODO Disabled due to upcoming release 0.4.8 and irrlicht messing up localization
--		"button[0.75,4.85;1.8,0.5;btn_mod_mgr_install_local;".. fgettext("Local install") .. "]" ..

--		TODO Disabled due to service being offline, and not likely to come online again, in this form
--		"button[0,4.85;5.25,0.5;btn_modstore;".. fgettext("Online mod repository") .. "]"
		""

	local selected_mod = nil

	if filterlist.size(modmgr.global_mods) >= tabdata.selected_mod then
		selected_mod = modmgr.global_mods:get_list()[tabdata.selected_mod]
	end

	if selected_mod ~= nil then
		local modscreenshot = nil

		--check for screenshot beeing available
		local screenshotfilename = selected_mod.path .. DIR_DELIM .. "screenshot.png"
		local error = nil
		local screenshotfile,error = io.open(screenshotfilename,"r")
		if error == nil then
			screenshotfile:close()
			modscreenshot = screenshotfilename
		end

		if modscreenshot == nil then
				modscreenshot = defaulttexturedir .. "no_screenshot.png"
		end

		retval = retval
				.. "image[5.5,0;3,2;" .. core.formspec_escape(modscreenshot) .. "]"
				.. "label[8.25,0.6;" .. selected_mod.name .. "]"

		local descriptionlines = nil
		error = nil
		local descriptionfilename = selected_mod.path .. "description.txt"
		local descriptionfile,error = io.open(descriptionfilename,"r")
		if error == nil then
			local descriptiontext = descriptionfile:read("*all")

			descriptionlines = core.splittext(descriptiontext,42)
			descriptionfile:close()
		else
			descriptionlines = {}
			table.insert(descriptionlines,fgettext("No mod description available"))
		end

		retval = retval ..
			"label[5.5,1.7;".. fgettext("Mod information:") .. "]" ..
			"textlist[5.5,2.2;6.2,2.4;description;"

		for i=1,#descriptionlines,1 do
			retval = retval .. core.formspec_escape(descriptionlines[i]) .. ","
		end


		if selected_mod.is_modpack then
			retval = retval .. ";0]" ..
				"button[10,4.85;2,0.5;btn_mod_mgr_rename_modpack;" ..
				fgettext("Rename") .. "]"
			retval = retval .. "button[5.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
				.. fgettext("Uninstall selected modpack") .. "]"
		else
			--show dependencies

			retval = retval .. "," .. fgettext("Depends:") .. ","

			local toadd = modmgr.get_dependencies(selected_mod.path)

			retval = retval .. toadd .. ";0]"

			retval = retval .. "button[5.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
				.. fgettext("Uninstall selected mod") .. "]"
		end
	end
	return retval
end

--------------------------------------------------------------------------------
local function handle_buttons(tabview, fields, tabname, tabdata)
	if fields["modlist"] ~= nil then
		local event = core.explode_textlist_event(fields["modlist"])
		tabdata.selected_mod = event.index
		return true
	end

	if fields["btn_mod_mgr_install_local"] ~= nil then
		core.show_file_open_dialog("mod_mgt_open_dlg",fgettext("Select Mod File:"))
		return true
	end

	if fields["btn_modstore"] ~= nil then
		local modstore_ui = ui.find_by_name("modstore")
		if modstore_ui ~= nil then
			tabview:hide()
			modstore.update_modlist()
			modstore_ui:show()
		else
			print("modstore ui element not found")
		end
		return true
	end

	if fields["btn_mod_mgr_rename_modpack"] ~= nil then
		local dlg_renamemp = create_rename_modpack_dlg(tabdata.selected_mod)
		dlg_renamemp:set_parent(tabview)
		tabview:hide()
		dlg_renamemp:show()
		return true
	end

	if fields["btn_mod_mgr_delete_mod"] ~= nil then
		local dlg_delmod = create_delete_mod_dlg(tabdata.selected_mod)
		dlg_delmod:set_parent(tabview)
		tabview:hide()
		dlg_delmod:show()
		return true
	end

	if fields["mod_mgt_open_dlg_accepted"] ~= nil and
		fields["mod_mgt_open_dlg_accepted"] ~= "" then
		modmgr.installmod(fields["mod_mgt_open_dlg_accepted"],nil)
		return true
	end

	return false
end

--------------------------------------------------------------------------------
tab_mods = {
	name = "mods",
	caption = fgettext("Mods"),
	cbf_formspec = get_formspec,
	cbf_button_handler = handle_buttons,
	on_change = gamemgr.update_gamelist
}
ass="hl opt">->getText(); if(font && text != "") { v2u32 dim = font->getDimension(narrow_to_wide(text).c_str()); v2s32 sdim(dim.X,dim.Y); core::rect<s32> rect2( /*rect.UpperLeftCorner, core::dimension2d<u32>(rect.getWidth(), 15)*/ rect.LowerRightCorner - sdim, sdim ); video::SColor bgcolor(128,0,0,0); driver->draw2DRectangle(bgcolor, rect2, clip); font->draw(text.c_str(), rect2, video::SColor(255,255,255,255), false, false, clip); } } } /* GUIInventoryMenu */ GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, v2s16 menu_size, InventoryContext *c, InventoryManager *invmgr, ITextureSource *tsrc ): GUIModalMenu(env, parent, id, menumgr), m_menu_size(menu_size), m_c(c), m_invmgr(invmgr), m_tsrc(tsrc) { m_selected_item = NULL; } GUIInventoryMenu::~GUIInventoryMenu() { removeChildren(); if(m_selected_item) delete m_selected_item; } void GUIInventoryMenu::removeChildren() { const core::list<gui::IGUIElement*> &children = getChildren(); core::list<gui::IGUIElement*> children_copy; for(core::list<gui::IGUIElement*>::ConstIterator i = children.begin(); i != children.end(); i++) { children_copy.push_back(*i); } for(core::list<gui::IGUIElement*>::Iterator i = children_copy.begin(); i != children_copy.end(); i++) { (*i)->remove(); } /*{ gui::IGUIElement *e = getElementFromId(256); if(e != NULL) e->remove(); }*/ } void GUIInventoryMenu::regenerateGui(v2u32 screensize) { // Remove children removeChildren(); /*padding = v2s32(24,24); spacing = v2s32(60,56); imgsize = v2s32(48,48);*/ padding = v2s32(screensize.Y/40, screensize.Y/40); spacing = v2s32(screensize.Y/12, screensize.Y/13); imgsize = v2s32(screensize.Y/15, screensize.Y/15); s32 helptext_h = 15; v2s32 size( padding.X*2+spacing.X*(m_menu_size.X-1)+imgsize.X, padding.Y*2+spacing.Y*(m_menu_size.Y-1)+imgsize.Y + helptext_h ); core::rect<s32> rect( screensize.X/2 - size.X/2, screensize.Y/2 - size.Y/2, screensize.X/2 + size.X/2, screensize.Y/2 + size.Y/2 ); DesiredRect = rect; recalculateAbsolutePosition(false); v2s32 basepos = getBasePos(); m_draw_spec.clear(); for(u16 i=0; i<m_init_draw_spec.size(); i++) { DrawSpec &s = m_init_draw_spec[i]; if(s.type == "list") { m_draw_spec.push_back(ListDrawSpec(s.name, s.subname, basepos + v2s32(spacing.X*s.pos.X, spacing.Y*s.pos.Y), s.geom)); } } /* m_draw_spec.clear(); m_draw_spec.push_back(ListDrawSpec("main", basepos + v2s32(spacing.X*0, spacing.Y*3), v2s32(8, 4))); m_draw_spec.push_back(ListDrawSpec("craft", basepos + v2s32(spacing.X*3, spacing.Y*0), v2s32(3, 3))); m_draw_spec.push_back(ListDrawSpec("craftresult", basepos + v2s32(spacing.X*7, spacing.Y*1), v2s32(1, 1))); */ // Add children { core::rect<s32> rect(0, 0, size.X-padding.X*2, helptext_h); rect = rect + v2s32(size.X/2 - rect.getWidth()/2, size.Y-rect.getHeight()-15); const wchar_t *text = L"Left click: Move all items, Right click: Move single item"; Environment->addStaticText(text, rect, false, true, this, 256); } } GUIInventoryMenu::ItemSpec GUIInventoryMenu::getItemAtPos(v2s32 p) const { core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y); for(u32 i=0; i<m_draw_spec.size(); i++) { const ListDrawSpec &s = m_draw_spec[i]; for(s32 i=0; i<s.geom.X*s.geom.Y; i++) { s32 x = (i%s.geom.X) * spacing.X; s32 y = (i/s.geom.X) * spacing.Y; v2s32 p0(x,y); core::rect<s32> rect = imgrect + s.pos + p0; if(rect.isPointInside(p)) { return ItemSpec(s.inventoryname, s.listname, i); } } } return ItemSpec("", "", -1); } void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc) { video::IVideoDriver* driver = Environment->getVideoDriver(); // Get font gui::IGUIFont *font = NULL; gui::IGUISkin* skin = Environment->getSkin(); if (skin) font = skin->getFont(); Inventory *inv = m_invmgr->getInventory(m_c, s.inventoryname); assert(inv); InventoryList *ilist = inv->getList(s.listname); core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y); for(s32 i=0; i<s.geom.X*s.geom.Y; i++) { s32 x = (i%s.geom.X) * spacing.X; s32 y = (i/s.geom.X) * spacing.Y; v2s32 p(x,y); core::rect<s32> rect = imgrect + s.pos + p; InventoryItem *item = NULL; if(ilist) item = ilist->getItem(i); if(m_selected_item != NULL && m_selected_item->listname == s.listname && m_selected_item->i == i) { /*s32 border = imgsize.X/12; driver->draw2DRectangle(video::SColor(255,192,192,192), core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*border, rect.LowerRightCorner + v2s32(1,1)*border), NULL); driver->draw2DRectangle(video::SColor(255,0,0,0), core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*((border+1)/2), rect.LowerRightCorner + v2s32(1,1)*((border+1)/2)), NULL);*/ s32 border = 2; driver->draw2DRectangle(video::SColor(255,255,0,0), core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*border, rect.LowerRightCorner + v2s32(1,1)*border), &AbsoluteClippingRect); } if(rect.isPointInside(m_pointer) && m_selected_item) { video::SColor bgcolor(255,192,192,192); driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect); } else { video::SColor bgcolor(255,128,128,128); driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect); } if(item) { drawInventoryItem(driver, font, item, rect, &AbsoluteClippingRect, tsrc); } } } void GUIInventoryMenu::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); /* Draw items */ for(u32 i=0; i<m_draw_spec.size(); i++) { ListDrawSpec &s = m_draw_spec[i]; drawList(s, m_tsrc); } /* Call base class */ gui::IGUIElement::draw(); } bool GUIInventoryMenu::OnEvent(const SEvent& event) { if(event.EventType==EET_KEY_INPUT_EVENT) { KeyPress kp(event.KeyInput); if (event.KeyInput.PressedDown && (kp == EscapeKey || kp == getKeySetting("keymap_inventory"))) { quitMenu(); return true; } } if(event.EventType==EET_MOUSE_INPUT_EVENT) { char amount = -1; v2s32 p(event.MouseInput.X, event.MouseInput.Y); ItemSpec s = getItemAtPos(p); if(event.MouseInput.Event==EMIE_MOUSE_MOVED) m_pointer = v2s32(event.MouseInput.X, event.MouseInput.Y); else if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) amount = 0; else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN) amount = 1; else if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN) amount = 10; else if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP && m_selected_item && (m_selected_item->listname != s.listname || m_selected_item->i != s.i)) amount = 0; if(amount >= 0) { //infostream<<"Mouse action at p=("<<p.X<<","<<p.Y<<")"<<std::endl; if(s.isValid()) { infostream<<"Mouse action on "<<s.inventoryname <<"/"<<s.listname<<" "<<s.i<<std::endl; if(m_selected_item) { Inventory *inv_from = m_invmgr->getInventory(m_c, m_selected_item->inventoryname); Inventory *inv_to = m_invmgr->getInventory(m_c, s.inventoryname); assert(inv_from); assert(inv_to); InventoryList *list_from = inv_from->getList(m_selected_item->listname); InventoryList *list_to = inv_to->getList(s.listname); if(list_from == NULL) infostream<<"from list doesn't exist"<<std::endl; if(list_to == NULL) infostream<<"to list doesn't exist"<<std::endl; // Indicates whether source slot completely empties bool source_empties = false; if(list_from && list_to && list_from->getItem(m_selected_item->i) != NULL) { infostream<<"Handing IACTION_MOVE to manager"<<std::endl; IMoveAction *a = new IMoveAction(); a->count = amount; a->from_inv = m_selected_item->inventoryname; a->from_list = m_selected_item->listname; a->from_i = m_selected_item->i; a->to_inv = s.inventoryname; a->to_list = s.listname; a->to_i = s.i; //ispec.actions->push_back(a); m_invmgr->inventoryAction(a); if(list_from->getItem(m_selected_item->i)->getCount()<=amount) source_empties = true; } // Remove selection if target was left-clicked or source // slot was emptied if(amount == 0 || source_empties) { delete m_selected_item; m_selected_item = NULL; } } else { /* Select if non-NULL */ Inventory *inv = m_invmgr->getInventory(m_c, s.inventoryname); assert(inv); InventoryList *list = inv->getList(s.listname); if(list->getItem(s.i) != NULL) { m_selected_item = new ItemSpec(s); } } } else { if(m_selected_item) { delete m_selected_item; m_selected_item = NULL; } } } } if(event.EventType==EET_GUI_EVENT) { if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST && isVisible()) { if(!canTakeFocus(event.GUIEvent.Element)) { infostream<<"GUIInventoryMenu: 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 256: // continue setVisible(false); break; case 257: // exit dev->closeDevice(); break; }*/ } } return Parent ? Parent->OnEvent(event) : false; } /* Here is an example traditional set-up sequence for a DrawSpec list: std::string furnace_inv_id = "nodemetadata:0,1,2"; core::array<GUIInventoryMenu::DrawSpec> draw_spec; draw_spec.push_back(GUIInventoryMenu::DrawSpec( "list", furnace_inv_id, "fuel", v2s32(2, 3), v2s32(1, 1))); draw_spec.push_back(GUIInventoryMenu::DrawSpec( "list", furnace_inv_id, "src", v2s32(2, 1), v2s32(1, 1))); draw_spec.push_back(GUIInventoryMenu::DrawSpec( "list", furnace_inv_id, "dst", v2s32(5, 1), v2s32(2, 2))); draw_spec.push_back(GUIInventoryMenu::DrawSpec( "list", "current_player", "main", v2s32(0, 5), v2s32(8, 4))); setDrawSpec(draw_spec); Here is the string for creating the same DrawSpec list (a single line, spread to multiple lines here): GUIInventoryMenu::makeDrawSpecArrayFromString( draw_spec, "nodemetadata:0,1,2", "invsize[8,9;]" "list[current_name;fuel;2,3;1,1;]" "list[current_name;src;2,1;1,1;]" "list[current_name;dst;5,1;2,2;]" "list[current_player;main;0,5;8,4;]"); Returns inventory menu size defined by invsize[]. */ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString( core::array<GUIInventoryMenu::DrawSpec> &draw_spec, const std::string &data, const std::string &current_name) { v2s16 invsize(8,9); Strfnd f(data); while(f.atend() == false) { std::string type = trim(f.next("[")); //infostream<<"type="<<type<<std::endl; if(type == "list") { std::string name = f.next(";"); if(name == "current_name") name = current_name; std::string subname = f.next(";"); s32 pos_x = stoi(f.next(",")); s32 pos_y = stoi(f.next(";")); s32 geom_x = stoi(f.next(",")); s32 geom_y = stoi(f.next(";")); infostream<<"list name="<<name<<", subname="<<subname <<", pos=("<<pos_x<<","<<pos_y<<")" <<", geom=("<<geom_x<<","<<geom_y<<")" <<std::endl; draw_spec.push_back(GUIInventoryMenu::DrawSpec( type, name, subname, v2s32(pos_x,pos_y),v2s32(geom_x,geom_y))); f.next("]"); } else if(type == "invsize") { invsize.X = stoi(f.next(",")); invsize.Y = stoi(f.next(";")); infostream<<"invsize ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl; f.next("]"); } else { // Ignore others std::string ts = f.next("]"); infostream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\"" <<std::endl; } } return invsize; }