aboutsummaryrefslogtreecommitdiff
path: root/ch_core/formspecs.lua
diff options
context:
space:
mode:
Diffstat (limited to 'ch_core/formspecs.lua')
-rw-r--r--ch_core/formspecs.lua217
1 files changed, 217 insertions, 0 deletions
diff --git a/ch_core/formspecs.lua b/ch_core/formspecs.lua
new file mode 100644
index 0000000..5659e4c
--- /dev/null
+++ b/ch_core/formspecs.lua
@@ -0,0 +1,217 @@
+ch_core.open_submod("formspecs", {data = true, lib = true})
+
+-- API:
+-- ch_core.show_formspec(player_or_player_name, formname, formspec, formspec_callback, custom_state, options)
+-- local function formspec_callback(custom_state, player, formname, fields)
+
+--[[
+ player_name => {
+ callback = function,
+ custom_state = ...,
+ formname = string,
+ object_id = int,
+ }
+]]
+local formspec_states = {}
+local formspec_states_next_id = 1
+
+local function def_to_string(label, defitem, separator)
+ if defitem == nil then
+ return ""
+ end
+ local t = type(defitem)
+ if t == "string" then
+ return label.."["..defitem.."]"
+ elseif t == "number" or t == "bool" then
+ return label.."["..tostring(defitem).."]"
+ elseif t == "table" then
+ if #defitem == 0 then
+ return label.."[]"
+ else
+ t = {}
+ for i = 1, #defitem do
+ t[i] = tostring(defitem[i])
+ end
+ t[1] = label.."["..t[1]
+ t[#t] = t[#t].."]"
+ return table.concat(t, separator)
+ end
+ else
+ return ""
+ end
+end
+
+local ifthenelse = ch_core.ifthenelse
+
+--[[
+ Sestaví záhlaví formspecu. Dovolené klíče jsou:
+ -- formspec_version
+ -- size
+ -- position
+ -- anchor
+ -- padding
+ -- no_prepend (bool)
+ -- listcolors
+ -- bgcolor
+ -- background
+ -- background9
+ -- set_focus
+ -- auto_background (speciální, vylučuje se s background a background9)
+]]
+function ch_core.formspec_header(def)
+ local result, size_element
+
+ if def.size ~= nil then
+ if type(def.size) ~= "table" then
+ error("def.size must be a table or nil!")
+ end
+ local s = def.size
+ size_element = {"size["..tostring(s[1])}
+ for i = 2, #s - 1, 1 do
+ size_element[i] = tostring(s[i])
+ end
+ size_element[#s] = tostring(s[#s]).."]"
+ size_element = table.concat(size_element, ",")
+ else
+ size_element = ""
+ end
+
+ result = {
+ def_to_string("formspec_version", def.formspec_version, ""), -- 1
+ size_element, -- 2
+ def_to_string("position", def.position, ","), -- 3
+ def_to_string("anchor", def.anchor, ","), -- 4
+ def_to_string("padding", def.padding, ","), -- 5
+ ifthenelse(def.no_prepend == true, "no_prepend[]", ""), -- 6
+ def_to_string("listcolors", def.listcolors, ";"), -- 7
+ def_to_string("bgcolor", def.bgcolor, ";"), -- 8
+ def_to_string("background", def.background, ";"), -- 9
+ def_to_string("background9", def.background9, ";"), -- 10
+ def_to_string("set_focus", def.set_focus, ";"), -- 11
+ }
+ if not def.background and not def.background9 and def.formspec_version ~= nil and def.formspec_version > 1 then
+ if def.auto_background == true then
+ if result[7] == "" then
+ -- colors according to Technic Chests:
+ result[7] = "listcolors[#7b7b7b;#909090;#000000;#6e823c;#ffffff]"
+ end
+ result[10] = "background9[0,0;1,1;ch_core_formspec_bg.png;true;16]"
+ -- result[9] = "background[0,0;"..fsw..","..fsh..";ch_core_formspec_bg.png]"
+ end
+ end
+ return table.concat(result)
+end
+
+--[[
+ Má-li daná postava zobrazen daný formspec, uzavře ho a vrátí true.
+ Jinak vrátí false.
+ Je-li call_callback true, nastavený callback se před uzavřením zavolá
+ s fields = {quit = "true"} a jeho návratová hodnota bude odignorována.
+]]
+function ch_core.close_formspec(player_name_or_player, formname, call_callback)
+ if formname == nil or formname == "" then
+ return false -- formname invalid
+ end
+ local p = ch_core.normalize_player(player_name_or_player)
+ if p.player == nil then
+ return false -- player invalid or not online
+ end
+ local formspec_state = formspec_states[p.player_name]
+ if formspec_state == nil or formspec_state.formname ~= formname then
+ return false -- formspec not open or the formname is different
+ end
+ if call_callback then
+ formspec_state.callback(formspec_state.custom_state, p.player, formname, {quit = "true"})
+ end
+ minetest.close_formspec(p.player_name, formname)
+ if formspec_states[p.player_name] ~= nil and formspec_states[p.player_name].object_id == formspec_state.object_id then
+ formspec_states[p.player_name] = nil
+ end
+ return true
+end
+
+--[[
+ Zobrazí hráči/ce formulář a nastaví callback pro jeho obsluhu.
+ Callback nemusí být zavolán v nestandardních situacích jako
+ v případě odpojení klienta.
+]]
+function ch_core.show_formspec(player_name_or_player, formname, formspec, callback, custom_state, options)
+ local p = ch_core.normalize_player(player_name_or_player)
+ if p.player == nil then return false end -- player invalid or not online
+
+ if formname == nil or formname == "" then
+ -- generate random formname
+ formname = "ch_core:"..minetest.sha1(tostring(bit.bxor(minetest.get_us_time(), math.random(1, 1099511627775))), false)
+ end
+
+ local id = formspec_states_next_id
+ formspec_states_next_id = id + 1
+ formspec_states[p.player_name] = {
+ callback = callback or function(...) return end,
+ custom_state = custom_state,
+ formname = formname,
+ object_id = id,
+ }
+
+ minetest.show_formspec(p.player_name, formname, formspec)
+ return formname
+end
+
+--[[
+ Aktualizuje již zobrazený formspec. Vrátí true v případě úspěchu.
+ formspec_or_function může být buď řetězec, nebo funkce, která bude
+ pro získání řetězce zavolána s parametry: (player_name, formname, custom_state).
+ Pokud nevrátí řetězec, update_formspec skončí a vrátí false.
+]]
+function ch_core.update_formspec(player_name_or_player, formname, formspec_or_function)
+ if formname == nil or formname == "" then
+ return false -- formname invalid
+ end
+ local p = ch_core.normalize_player(player_name_or_player)
+ if p.player == nil then
+ return false -- player invalid or not online
+ end
+ local formspec_state = formspec_states[p.player_name]
+ if formspec_state == nil or formspec_state.formname ~= formname then
+ return false -- formspec not open or the formname is different
+ end
+ local t = type(formspec_or_function)
+ local formspec
+ if t == "string" then
+ formspec = formspec_or_function
+ elseif t == "function" then
+ formspec = formspec_or_function(p.player_name, formname, formspec_state.custom_state)
+ if type(formspec) ~= "string" then
+ return false
+ end
+ else
+ return false -- invalid formspec argument
+ end
+ minetest.show_formspec(p.player_name, formname, formspec)
+ return true
+end
+
+local function on_player_receive_fields(player, formname, fields)
+ local player_name = assert(player:get_player_name())
+ local formspec_state = formspec_states[player_name]
+ if formspec_state == nil then
+ return -- formspec not by ch_core
+ end
+ if formspec_state.formname ~= formname then
+ minetest.log("warning", player_name..": received fields of form "..(formname or "nil").." when "..(formspec_state.formname or "nil").." was expected")
+ formspec_states[player_name] = nil
+ return
+ end
+ local result = formspec_state.callback(formspec_state.custom_state, player, formname, fields, {}) -- custom_state, player, formname, fields
+ if type(result) == "string" then
+ -- string => show as formspec
+ formspec_states[player_name] = formspec_state
+ minetest.show_formspec(player_name, formname, result)
+ elseif fields ~= nil and fields.quit == "true" and formspec_states[player_name] ~= nil and formspec_states[player_name].object_id == formspec_state.object_id then
+ formspec_states[player_name] = nil
+ end
+ return true
+end
+minetest.register_on_player_receive_fields(on_player_receive_fields)
+
+ch_core.close_submod("formspecs")