]> git.lizzy.rs Git - worldedit.git/blob - worldedit_gui/init.lua
Use sfinv if possible, fixes #124 with recent minetest versions
[worldedit.git] / worldedit_gui / init.lua
1 worldedit = worldedit or {}
2
3 --[[
4 Example:
5
6     worldedit.register_gui_function("worldedit_gui_hollow_cylinder", {
7         name = "Make Hollow Cylinder",
8         privs = {worldedit=true},
9         get_formspec = function(name) return "some formspec here" end,
10         on_select = function(name) print(name .. " clicked the button!") end,
11     })
12
13 Use `nil` for the `options` parameter to unregister the function associated with the given identifier.
14
15 Use `nil` for the `get_formspec` field to denote that the function does not have its own screen.
16
17 Use `nil` for the `privs` field to denote that no special privileges are required to use the function.
18
19 If the identifier is already registered to another function, it will be replaced by the new one.
20
21 The `on_select` function must not call `worldedit.show_page`
22 ]]
23
24 worldedit.pages = {} --mapping of identifiers to options
25 local identifiers = {} --ordered list of identifiers
26 worldedit.register_gui_function = function(identifier, options)
27         worldedit.pages[identifier] = options
28         table.insert(identifiers, identifier)
29 end
30
31 --[[
32 Example:
33
34     worldedit.register_gui_handler("worldedit_gui_hollow_cylinder", function(name, fields)
35         print(minetest.serialize(fields))
36     end)
37 ]]
38
39 worldedit.register_gui_handler = function(identifier, handler)
40         local enabled = true
41         minetest.register_on_player_receive_fields(function(player, formname, fields)
42                 if not enabled then return false end
43                 enabled = false
44                 minetest.after(0.2, function() enabled = true end)
45                 local name = player:get_player_name()
46
47                 --ensure the player has permission to perform the action
48                 local entry = worldedit.pages[identifier]
49                 if entry and minetest.check_player_privs(name, entry.privs or {}) then
50                         return handler(name, fields)
51                 end
52                 return false
53         end)
54 end
55
56 worldedit.get_formspec_header = function(identifier)
57         local entry = worldedit.pages[identifier] or {}
58         return "button[0,0;2,0.5;worldedit_gui;Back]" ..
59                 string.format("label[2,0;WorldEdit GUI > %s]", entry.name or "")
60 end
61
62 local get_formspec = function(name, identifier)
63         if worldedit.pages[identifier] then
64                 return worldedit.pages[identifier].get_formspec(name)
65         end
66         return worldedit.pages["worldedit_gui"].get_formspec(name) --default to showing main page if an unknown page is given
67 end
68
69 --implement worldedit.show_page(name, page) in different ways depending on the available APIs
70 if rawget(_G, "unified_inventory") then --unified inventory installed
71         local old_func = worldedit.register_gui_function
72         worldedit.register_gui_function = function(identifier, options)
73                 old_func(identifier, options)
74                 unified_inventory.register_page(identifier, {get_formspec=function(player) return {formspec=options.get_formspec(player:get_player_name())} end})
75         end
76
77         unified_inventory.register_button("worldedit_gui", {
78                 type = "image",
79                 image = "inventory_plus_worldedit_gui.png",
80         })
81
82         minetest.register_on_player_receive_fields(function(player, formname, fields)
83                 local name = player:get_player_name()
84                 if fields.worldedit_gui then --main page
85                         worldedit.show_page(name, "worldedit_gui")
86                         return true
87                 elseif fields.worldedit_gui_exit then --return to original page
88                         local player = minetest.get_player_by_name(name)
89                         if player then
90                                 unified_inventory.set_inventory_formspec(player, "craft")
91                         end
92                         return true
93                 end
94                 return false
95         end)
96
97         worldedit.show_page = function(name, page)
98                 local player = minetest.get_player_by_name(name)
99                 if player then
100                         player:set_inventory_formspec(get_formspec(name, page))
101                 end
102         end
103 elseif rawget(_G, "inventory_plus") then --inventory++ installed
104         minetest.register_on_joinplayer(function(player)
105                 local can_worldedit = minetest.check_player_privs(player:get_player_name(), {worldedit=true})
106                 if can_worldedit then
107                         inventory_plus.register_button(player, "worldedit_gui", "WorldEdit")
108                 end
109         end)
110
111         --show the form when the button is pressed and hide it when done
112         local gui_player_formspecs = {}
113         minetest.register_on_player_receive_fields(function(player, formname, fields)
114                 local name = player:get_player_name()
115                 if fields.worldedit_gui then --main page
116                         gui_player_formspecs[name] = player:get_inventory_formspec()
117                         worldedit.show_page(name, "worldedit_gui")
118                         return true
119                 elseif fields.worldedit_gui_exit then --return to original page
120                         if gui_player_formspecs[name] then
121                                 inventory_plus.set_inventory_formspec(player, inventory_plus.get_formspec(player, "main"))
122                         end
123                         return true
124                 end
125                 return false
126         end)
127
128         worldedit.show_page = function(name, page)
129                 local player = minetest.get_player_by_name(name)
130                 if player then
131                         inventory_plus.set_inventory_formspec(player, get_formspec(name, page))
132                 end
133         end
134 elseif rawget(_G, "sfinv") then --sfinv installed (part of minetest_game since 0.4.15)
135         assert(sfinv.enabled)
136         local orig_get = sfinv.pages["sfinv:crafting"].get
137         sfinv.override_page("sfinv:crafting", {
138                 get = function(self, player, context)
139                         local can_worldedit = minetest.check_player_privs(player, {worldedit=true})
140                         local fs = orig_get(self, player, context)
141                         return fs .. (can_worldedit and "image_button[0,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]" or "")
142                 end
143         })
144
145         --show the form when the button is pressed and hide it when done
146         minetest.register_on_player_receive_fields(function(player, formname, fields)
147                 if fields.worldedit_gui then --main page
148                         worldedit.show_page(player:get_player_name(), "worldedit_gui")
149                         return true
150                 elseif fields.worldedit_gui_exit then --return to original page
151                         sfinv.set_page(player, "sfinv:crafting")
152                         return true
153                 end
154                 return false
155         end)
156
157         worldedit.show_page = function(name, page)
158                 local player = minetest.get_player_by_name(name)
159                 if player then
160                         player:set_inventory_formspec(get_formspec(name, page))
161                 end
162         end
163 else --fallback button
164         -- FIXME: this is a huge clusterfuck and the back button is broken
165         local player_formspecs = {}
166
167         local update_main_formspec = function(name)
168                 local formspec = player_formspecs[name]
169                 if not formspec then
170                         return
171                 end
172                 local player = minetest.get_player_by_name(name)
173                 if not player then --this is in case the player signs off while the media is loading
174                         return
175                 end
176                 if (minetest.check_player_privs(name, {creative=true}) or
177                                 minetest.setting_getbool("creative_mode")) and
178                                 creative then --creative is active, add button to modified formspec
179                         local creative_formspec = player:get_inventory_formspec()
180                         local tab_id = tonumber(creative_formspec:match("tabheader%[.-;(%d+)%;"))
181
182                         if tab_id == 1 then
183                                 formspec = creative_formspec ..
184                                         "image_button[0,1;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]"
185                         elseif not tab_id then
186                                 formspec = creative_formspec ..
187                                         "image_button[6,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]"
188                         else
189                                 return
190                         end
191                 else
192                         formspec = formspec .. "image_button[0,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]"
193                 end
194                 player:set_inventory_formspec(formspec)
195         end
196
197         minetest.register_on_joinplayer(function(player)
198                 local name = player:get_player_name()
199                 minetest.after(1, function()
200                         if minetest.get_player_by_name(name) then --ensure the player is still signed in
201                                 player_formspecs[name] = player:get_inventory_formspec()
202                                 minetest.after(0.01, function()
203                                         update_main_formspec(name)
204                                 end)
205                         end
206                 end)
207         end)
208
209         minetest.register_on_leaveplayer(function(player)
210                 player_formspecs[player:get_player_name()] = nil
211         end)
212
213         local gui_player_formspecs = {}
214         minetest.register_on_player_receive_fields(function(player, formname, fields)
215                 local name = player:get_player_name()
216                 if fields.worldedit_gui then --main page
217                         gui_player_formspecs[name] = player:get_inventory_formspec()
218                         worldedit.show_page(name, "worldedit_gui")
219                         return true
220                 elseif fields.worldedit_gui_exit then --return to original page
221                         if gui_player_formspecs[name] then
222                                 player:set_inventory_formspec(gui_player_formspecs[name])
223                         end
224                         return true
225                 else --deal with creative_inventory setting the formspec on every single message
226                         minetest.after(0.01,function()
227                                 update_main_formspec(name)
228                         end)
229                         return false --continue processing in creative inventory
230                 end
231         end)
232
233         worldedit.show_page = function(name, page)
234                 local player = minetest.get_player_by_name(name)
235                 if player then
236                         player:set_inventory_formspec(get_formspec(name, page))
237                 end
238         end
239 end
240
241 worldedit.register_gui_function("worldedit_gui", {
242         name = "WorldEdit GUI",
243         get_formspec = function(name)
244                 --create a form with all the buttons arranged in a grid
245                 local buttons, x, y, index = {}, 0, 1, 0
246                 local width, height = 3, 0.8
247                 local columns = 5
248                 for i, identifier in pairs(identifiers) do
249                         if identifier ~= "worldedit_gui" then
250                                 local entry = worldedit.pages[identifier]
251                                 table.insert(buttons, string.format((entry.get_formspec and "button" or "button_exit") ..
252                                         "[%g,%g;%g,%g;%s;%s]", x, y, width, height, identifier, minetest.formspec_escape(entry.name)))
253
254                                 index, x = index + 1, x + width
255                                 if index == columns then --row is full
256                                         x, y = 0, y + height
257                                         index = 0
258                                 end
259                         end
260                 end
261                 if index == 0 then --empty row
262                         y = y - height
263                 end
264                 return string.format("size[%g,%g]", math.max(columns * width, 5), math.max(y + 0.5, 3)) ..
265                         "button[0,0;2,0.5;worldedit_gui_exit;Back]" ..
266                         "label[2,0;WorldEdit GUI]" ..
267                         table.concat(buttons)
268         end,
269 })
270
271 worldedit.register_gui_handler("worldedit_gui", function(name, fields)
272         for identifier, entry in pairs(worldedit.pages) do --check for WorldEdit GUI main formspec button selection
273                 if fields[identifier] and identifier ~= "worldedit_gui" then
274                         --ensure player has permission to perform action
275                         local has_privs, missing_privs = minetest.check_player_privs(name, entry.privs or {})
276                         if not has_privs then
277                                 worldedit.player_notify(name, "you are not allowed to use this function (missing privileges: " .. table.concat(missing_privs, ", ") .. ")")
278                                 return false
279                         end
280                         if entry.on_select then
281                                 entry.on_select(name)
282                         end
283                         if entry.get_formspec then
284                                 worldedit.show_page(name, identifier)
285                         end
286                         return true
287                 end
288         end
289         return false
290 end)
291
292 dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/functionality.lua")