bd6de1edfbce9178adccec22fd0aae08c2a0c556
[oweals/minetest_game.git] / mods / sfinv / api.lua
1 sfinv = {
2         pages = {},
3         pages_unordered = {},
4         contexts = {},
5         enabled = true
6 }
7
8 function sfinv.register_page(name, def)
9         assert(name, "Invalid sfinv page. Requires a name")
10         assert(def, "Invalid sfinv page. Requires a def[inition] table")
11         assert(def.get, "Invalid sfinv page. Def requires a get function.")
12         assert(not sfinv.pages[name], "Attempt to register already registered sfinv page " .. dump(name))
13
14         sfinv.pages[name] = def
15         def.name = name
16         table.insert(sfinv.pages_unordered, def)
17 end
18
19 function sfinv.override_page(name, def)
20         assert(name, "Invalid sfinv page override. Requires a name")
21         assert(def, "Invalid sfinv page override. Requires a def[inition] table")
22         local page = sfinv.pages[name]
23         assert(page, "Attempt to override sfinv page " .. dump(name) .. " which does not exist.")
24         for key, value in pairs(def) do
25                 page[key] = value
26         end
27 end
28
29 function sfinv.get_nav_fs(player, context, nav, current_idx)
30         -- Only show tabs if there is more than one page
31         if #nav > 1 then
32                 return "tabheader[0,0;tabs;" .. table.concat(nav, ",") .. ";" .. current_idx .. ";true;false]"
33         else
34                 return ""
35         end
36 end
37
38 local theme_main = "bgcolor[#080808BB;true]" .. default.gui_bg ..
39                 default.gui_bg_img
40
41 local theme_inv = default.gui_slots .. [[
42                 list[current_player;main;0,4.7;8,1;]
43                 list[current_player;main;0,5.85;8,3;8]
44         ]]
45
46 function sfinv.make_formspec(player, context, content, show_inv, size)
47         local tmp = {
48                 size or "size[8,8.6]",
49                 theme_main,
50                 sfinv.get_nav_fs(player, context, context.nav_titles, context.nav_idx),
51                 content
52         }
53         if show_inv then
54                 tmp[#tmp + 1] = theme_inv
55         end
56         return table.concat(tmp, "")
57 end
58
59 function sfinv.get_homepage_name(player)
60         return "sfinv:crafting"
61 end
62
63 function sfinv.get_formspec(player, context)
64         -- Generate navigation tabs
65         local nav = {}
66         local nav_ids = {}
67         local current_idx = 1
68         for i, pdef in pairs(sfinv.pages_unordered) do
69                 if not pdef.is_in_nav or pdef:is_in_nav(player, context) then
70                         nav[#nav + 1] = pdef.title
71                         nav_ids[#nav_ids + 1] = pdef.name
72                         if pdef.name == context.page then
73                                 current_idx = #nav_ids
74                         end
75                 end
76         end
77         context.nav = nav_ids
78         context.nav_titles = nav
79         context.nav_idx = current_idx
80
81         -- Generate formspec
82         local page = sfinv.pages[context.page] or sfinv.pages["404"]
83         if page then
84                 return page:get(player, context)
85         else
86                 local old_page = context.page
87                 context.page = sfinv.get_homepage_name(player)
88                 assert(sfinv.pages[context.page], "[sfinv] Invalid homepage")
89                 minetest.log("warning", "[sfinv] Couldn't find " .. dump(old_page) .. " so using switching to homepage")
90                 return sfinv.get_formspec(player, context)
91         end
92 end
93
94 function sfinv.get_or_create_context(player)
95         local name = player:get_player_name()
96         local context = sfinv.contexts[name]
97         if not context then
98                 context = {
99                         page = sfinv.get_homepage_name(player)
100                 }
101                 sfinv.contexts[name] = context
102         end
103         return context
104 end
105
106 function sfinv.set_context(player, context)
107         sfinv.contexts[player:get_player_name()] = context
108 end
109
110 function sfinv.set_player_inventory_formspec(player, context)
111         local fs = sfinv.get_formspec(player,
112                         context or sfinv.get_or_create_context(player))
113         player:set_inventory_formspec(fs)
114 end
115
116 function sfinv.set_page(player, pagename)
117         local context = sfinv.get_or_create_context(player)
118         local oldpage = sfinv.pages[context.page]
119         if oldpage and oldpage.on_leave then
120                 oldpage:on_leave(player, context)
121         end
122         context.page = pagename
123         local page = sfinv.pages[pagename]
124         if page.on_enter then
125                 page:on_enter(player, context)
126         end
127         sfinv.set_player_inventory_formspec(player, context)
128 end
129
130 minetest.register_on_joinplayer(function(player)
131         if sfinv.enabled then
132                 sfinv.set_player_inventory_formspec(player)
133         end
134 end)
135
136 minetest.register_on_leaveplayer(function(player)
137         sfinv.contexts[player:get_player_name()] = nil
138 end)
139
140 minetest.register_on_player_receive_fields(function(player, formname, fields)
141         if formname ~= "" or not sfinv.enabled then
142                 return false
143         end
144
145         -- Get Context
146         local name = player:get_player_name()
147         local context = sfinv.contexts[name]
148         if not context then
149                 sfinv.set_player_inventory_formspec(player)
150                 return false
151         end
152
153         -- Was a tab selected?
154         if fields.tabs and context.nav then
155                 local tid = tonumber(fields.tabs)
156                 if tid and tid > 0 then
157                         local id = context.nav[tid]
158                         local page = sfinv.pages[id]
159                         if id and page then
160                                 sfinv.set_page(player, id)
161                         end
162                 end
163         else
164                 -- Pass event to page
165                 local page = sfinv.pages[context.page]
166                 if page and page.on_player_receive_fields then
167                         return page:on_player_receive_fields(player, context, fields)
168                 end
169         end
170 end)