Change README caption
[minetest_select_item.git] / init.lua
blob33c9e291a679cd2249ee1b0a4650775eaa070d15
1 select_item = {}
3 -- Cache for result of item filters
4 local player_filters = {}
5 local player_filter_results = {}
6 local player_maxpage = {}
8 local reset_player_info = function(playername)
9 player_filters[playername] = nil
10 player_filter_results[playername] = nil
11 player_maxpage[playername] = nil
12 end
14 -- Predefined filters
15 select_item.filters = {}
17 -- Filters out all items not for the Creative Inventory.
18 -- This elimininates all items reserved for internal use.
19 select_item.filters.creative = function(itemstring)
20 local itemdef = minetest.registered_items[itemstring]
21 if itemstring == "air" then
22 return false
23 end
24 if itemdef.description == nil or itemdef.description == "" then
25 return false
26 end
27 if minetest.get_item_group(itemstring, "not_in_creative_inventory") == 1 then
28 return false
29 end
30 return true
31 end
33 -- No filtering
34 select_item.filters.all = function()
35 return true
36 end
38 local check_item = function(itemstring, filter)
39 local itemdef = minetest.registered_items[itemstring]
40 if itemstring == "" or itemstring == "unknown" or itemstring == "ignore" or itemdef == nil then
41 return
42 end
43 if type(filter) == "function" then
44 if filter(itemstring) ~= true then
45 return false
46 end
47 end
49 return true
50 end
52 local get_items = function(filter)
53 local it = {}
54 for itemstring, itemdef in pairs(minetest.registered_items) do
55 if check_item(itemstring, filter) then
56 table.insert(it, {itemstring=itemstring, itemdef=itemdef})
57 end
58 end
59 -- Sort alphabetically by itemstring
60 local compare = function(t1, t2)
61 return t1.itemstring < t2.itemstring
62 end
63 table.sort(it, compare)
64 return it
65 end
67 local xsize_norm = 12
68 local ysize_norm = 9
70 -- Opens the item selection dialog for player with the given filter function at page.
71 -- The dialog has unique identifier dialogname.
72 -- Returns: Number of items it displays.
73 local show_dialog_page = function(playername, dialogname, filter, page)
74 local items
75 if player_filters[playername] == nil then
76 player_filters[playername] = filter
77 items = get_items(filter)
78 player_filter_results[playername] = items
79 end
80 items = player_filter_results[playername]
81 local xsize, ysize, total_pages
82 if #items < xsize_norm * ysize_norm then
83 xsize = xsize_norm
84 ysize = math.ceil(#items / xsize)
85 total_pages = 1
86 else
87 xsize = xsize_norm
88 ysize = ysize_norm
89 total_pages = math.ceil(#items / (xsize * ysize))
90 end
91 local bg = ""
92 if minetest.get_modpath("default") then
93 bg = default.gui_bg .. default.gui_bg_img .. default.gui_slots
94 end
95 if #items == 0 then
96 local form = "size[6,2]"..
97 bg ..
98 "label[0,0;There are no items to choose from.]"..
99 "button_exit[0,1;2,1;cancel;OK]"
100 minetest.show_formspec(playername, "select_item:page1", form)
101 return #items
103 local form = "size["..xsize..","..(ysize+1).."]" .. bg
104 local x = 0
105 local y = 0.5
106 if page == nil then page = 1 end
107 local start = 1 + (page-1) * xsize * ysize
108 player_maxpage[playername] = total_pages
109 form = form .. "label[0,0;Select an item:]"
110 for i=start, #items do
111 local itemstring = items[i].itemstring
112 local itemdef = items[i].itemdef
113 local name = "item_"..itemstring
114 form = form .. "item_image_button["..x..","..y..";1,1;"..itemstring..";"..name..";]"
115 if itemdef.description == nil or itemdef.description == "" then
116 form = form .. "tooltip["..name..";"..itemstring.."]"
119 x = x + 1
120 if x >= xsize then
121 x = 0
122 y = y + 1
123 if y >= ysize then
124 break
128 local ynav = (ysize + 0.5)
129 if total_pages > 1 then
130 form = form .. "button[0,"..ynav..";1,1;previous;<]"
131 form = form .. "button[1,"..ynav..";1,1;next;>]"
132 form = form .. "label[2,"..ynav..";"..minetest.formspec_escape(string.format("Page %d/%d", page, total_pages)).."]"
134 form = form .. "button_exit["..(xsize-2)..","..ynav..";2,1;cancel;Cancel]"
135 minetest.show_formspec(playername, "select_item:page"..page.."%%"..dialogname, form)
136 return #items
139 select_item.show_dialog = function(playername, dialogname, filter)
140 show_dialog_page(playername, dialogname, filter, 1)
143 local callbacks = {}
144 select_item.register_on_select_item = function(callback)
145 table.insert(callbacks, callback)
148 minetest.register_on_player_receive_fields(function(player, formname, fields)
149 local playername = player:get_player_name()
150 if string.sub(formname, 1, 16) == "select_item:page" then
151 -- Parse formname
152 local rest = string.sub(formname, 17, string.len(formname))
153 local split = string.split(rest, "%%", true, 2)
154 local page = tonumber(split[1])
155 local dialogname = split[2]
157 local item
158 for field,_ in pairs(fields) do
159 if string.sub(field, 1, 5) == "item_" then
160 item = string.sub(field, 6, string.len(field))
161 break
164 if item or fields.quit then
165 local close = true
166 for i=1,#callbacks do
167 local ret = callbacks[i](playername, dialogname, item)
168 if ret == false then
169 close = false
172 if close then
173 minetest.close_formspec(playername, formname)
175 reset_player_info(playername)
177 if fields.quit or fields.cancel then
178 reset_player_info(playername)
180 if page ~= nil then
181 if fields.previous and page > 1 then
182 show_dialog_page(player:get_player_name(), dialogname, player_filters[playername], page - 1)
183 elseif fields.next then
184 local maxpage = player_maxpage[playername]
185 if maxpage and (page + 1 <= maxpage) then
186 show_dialog_page(playername, dialogname, player_filters[playername], page + 1)
188 if not maxpage then
189 minetest.log("warning", "[select_item] Player "..playername.." managed to navigate select_item menu without maxpage set!")
194 end)
196 minetest.register_on_leaveplayer(function(player)
197 reset_player_info(player:get_player_name())
198 end)