Add locale template
[minetest_select_item.git] / init.lua
blobdee3728faad0f14153fb678eef5dd38f1e291667
1 select_item = {}
3 local S = minetest.get_translator("select_item")
5 -- Cache for result of item filters
6 local player_filters = {}
7 local player_filter_results = {}
8 local player_compares = {}
9 local player_maxpage = {}
11 local reset_player_info = function(playername)
12 player_filters[playername] = nil
13 player_filter_results[playername] = nil
14 player_compares[playername] = nil
15 player_maxpage[playername] = nil
16 end
18 -- Predefined filters
19 select_item.filters = {}
21 -- Filters out all items not for the Creative Inventory.
22 -- This elimininates all items reserved for internal use.
23 select_item.filters.creative = function(itemstring)
24 local itemdef = minetest.registered_items[itemstring]
25 if itemstring == "air" then
26 return false
27 end
28 if itemdef.description == nil or itemdef.description == "" then
29 return false
30 end
31 if minetest.get_item_group(itemstring, "not_in_creative_inventory") == 1 then
32 return false
33 end
34 return true
35 end
37 -- No filtering
38 select_item.filters.all = function()
39 return true
40 end
42 local check_item = function(itemstring, filter)
43 local itemdef = minetest.registered_items[itemstring]
44 if itemstring == "" or itemstring == "unknown" or itemstring == "ignore" or itemdef == nil then
45 return
46 end
47 if type(filter) == "function" then
48 if filter(itemstring) ~= true then
49 return false
50 end
51 end
53 return true
54 end
56 local get_items = function(filter, compare)
57 local it = {}
58 for itemstring, itemdef in pairs(minetest.registered_items) do
59 if check_item(itemstring, filter) then
60 table.insert(it, {itemstring=itemstring, itemdef=itemdef})
61 end
62 end
63 local internal_compare
64 if not compare then
65 -- Default sorting: Move description-less items and
66 -- items not_in_creative_inventory=1 to the end, then sort by itemstring.
67 internal_compare = function(t1, t2)
68 local t1d = minetest.registered_items[t1.itemstring].description
69 local t2d = minetest.registered_items[t2.itemstring].description
70 local t1g = minetest.get_item_group(t1.itemstring, "not_in_creative_inventory")
71 local t2g = minetest.get_item_group(t2.itemstring, "not_in_creative_inventory")
72 if (t1d == "" and t2d ~= "") then
73 return false
74 elseif (t1d ~= "" and t2d == "") then
75 return true
76 end
77 if (t1g == 1 and t2g == 0) then
78 return false
79 elseif (t1g == 0 and t2g == 1) then
80 return true
81 end
82 return t1.itemstring < t2.itemstring
83 end
84 else
85 internal_compare = function(t1, t2)
86 return compare(t1.itemstring, t2.itemstring)
87 end
88 end
89 table.sort(it, internal_compare)
90 return it
91 end
93 local xsize_norm = 12
94 local ysize_norm = 9
96 -- Opens the item selection dialog for player with the given filter function at page.
97 -- The dialog has unique identifier dialogname.
98 -- Returns: Number of items it displays.
99 local show_dialog_page = function(playername, dialogname, filter, compare, page)
100 local items
101 if player_filters[playername] == nil then
102 player_filters[playername] = filter
103 player_compares[playername] = compare
104 items = get_items(filter, compare)
105 player_filter_results[playername] = items
107 items = player_filter_results[playername]
108 local xsize, ysize, total_pages
109 if #items < xsize_norm * ysize_norm then
110 xsize = xsize_norm
111 ysize = math.ceil(#items / xsize)
112 total_pages = 1
113 else
114 xsize = xsize_norm
115 ysize = ysize_norm
116 total_pages = math.ceil(#items / (xsize * ysize))
118 local bg = ""
119 -- Legacy default formspec background (MT<=0.4.17)
120 if minetest.get_modpath("default") and default.gui_bg then
121 bg = default.gui_bg .. default.gui_bg_img .. default.gui_slots
123 if #items == 0 then
124 local form = "size[6,2]"..
125 bg ..
126 "label[0,0;"..minetest.formspec_escape(S("There are no items to choose from.")).."]"..
127 "button_exit[0,1;2,1;cancel;"..minetest.formspec_escape(S("There are no items to choose from.")).."]"
128 minetest.show_formspec(playername, "select_item:page1", form)
129 return #items
131 local form = "size["..xsize..","..(ysize+1).."]" .. bg
132 local x = 0
133 local y = 0.5
134 if page == nil then page = 1 end
135 local start = 1 + (page-1) * xsize * ysize
136 player_maxpage[playername] = total_pages
137 form = form .. "label[0,0;"..minetest.formspec_escape(S("Select an item:")).."]"
138 for i=start, #items do
139 local itemstring = items[i].itemstring
140 local itemdef = items[i].itemdef
141 local name = "item_"..itemstring
142 form = form .. "item_image_button["..x..","..y..";1,1;"..itemstring..";"..name..";]"
143 if itemdef.description == nil or itemdef.description == "" then
144 form = form .. "tooltip["..name..";"..itemstring.."]"
147 x = x + 1
148 if x >= xsize then
149 x = 0
150 y = y + 1
151 if y >= ysize then
152 break
156 local ynav = (ysize + 0.5)
157 if total_pages > 1 then
158 form = form .. "button[0,"..ynav..";1,1;previous;<]"
159 form = form .. "button[1,"..ynav..";1,1;next;>]"
160 form = form .. "label[2,"..ynav..";"..minetest.formspec_escape(S("Page @1/@2", page, total_pages)).."]"
162 form = form .. "button_exit["..(xsize-2)..","..ynav..";2,1;cancel;"..minetest.formspec_escape(S("Cancel")).."]"
163 minetest.show_formspec(playername, "select_item:page"..page.."%%"..dialogname, form)
164 return #items
167 select_item.show_dialog = function(playername, dialogname, filter, compare)
168 show_dialog_page(playername, dialogname, filter, compare, 1)
171 local callbacks = {}
172 select_item.register_on_select_item = function(callback)
173 table.insert(callbacks, callback)
176 minetest.register_on_player_receive_fields(function(player, formname, fields)
177 local playername = player:get_player_name()
178 if string.sub(formname, 1, 16) == "select_item:page" then
179 -- Parse formname
180 local rest = string.sub(formname, 17, string.len(formname))
181 local split = string.split(rest, "%%", true, 2)
182 local page = tonumber(split[1])
183 local dialogname = split[2]
185 local item
186 for field,_ in pairs(fields) do
187 if string.sub(field, 1, 5) == "item_" then
188 item = string.sub(field, 6, string.len(field))
189 break
192 if item or fields.quit then
193 local close = true
194 for i=1,#callbacks do
195 local ret = callbacks[i](playername, dialogname, item)
196 if ret == false then
197 close = false
200 if close then
201 minetest.close_formspec(playername, formname)
203 reset_player_info(playername)
205 if fields.quit or fields.cancel then
206 reset_player_info(playername)
208 if page ~= nil then
209 if fields.previous and page > 1 then
210 show_dialog_page(player:get_player_name(), dialogname, player_filters[playername], player_compares[playername], page - 1)
211 elseif fields.next then
212 local maxpage = player_maxpage[playername]
213 if maxpage and (page + 1 <= maxpage) then
214 show_dialog_page(playername, dialogname, player_filters[playername], player_compares[playername], page + 1)
216 if not maxpage then
217 minetest.log("warning", "[select_item] Player "..playername.." managed to navigate select_item menu without maxpage set!")
222 end)
224 minetest.register_on_leaveplayer(function(player)
225 reset_player_info(player:get_player_name())
226 end)