Implement new API for adding custom footer-buttons
This allows mods to place their own buttons alongside the trash, sort, and settings buttons in the inventory’s footer. The API mimics the custom tab API.
This commit is contained in:
parent
74f8fe64a8
commit
623b14bfe8
3
init.lua
3
init.lua
|
@ -20,7 +20,7 @@ local function lf(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
i3 = {
|
i3 = {
|
||||||
version = 1161,
|
version = 1162,
|
||||||
data = core.deserialize(storage:get_string"data") or {},
|
data = core.deserialize(storage:get_string"data") or {},
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
|
@ -102,6 +102,7 @@ i3 = {
|
||||||
plants = {},
|
plants = {},
|
||||||
modules = {},
|
modules = {},
|
||||||
minitabs = {},
|
minitabs = {},
|
||||||
|
footer_buttons = {},
|
||||||
craft_types = {},
|
craft_types = {},
|
||||||
|
|
||||||
recipe_filters = {},
|
recipe_filters = {},
|
||||||
|
|
85
src/api.lua
85
src/api.lua
|
@ -1,5 +1,6 @@
|
||||||
local http = ...
|
local http = ...
|
||||||
local make_fs, get_inventory_fs = i3.files.gui()
|
local make_fs, get_inventory_fs, confirm_trash_footer_fs, settings_footer_fs = i3.files.gui()
|
||||||
|
local home_footer_fields, confirm_trash_footer_fields, settings_footer_fields = i3.files.fields()
|
||||||
|
|
||||||
IMPORT("sorter", "sort_inventory", "play_sound")
|
IMPORT("sorter", "sort_inventory", "play_sound")
|
||||||
IMPORT("sort", "concat", "copy", "insert", "remove")
|
IMPORT("sort", "concat", "copy", "insert", "remove")
|
||||||
|
@ -257,6 +258,88 @@ function i3.override_tab(name, newdef)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function i3.new_footer_button(name, def)
|
||||||
|
if not true_str(name) then
|
||||||
|
return err "i3.new_footer_button: button name missing"
|
||||||
|
elseif not true_table(def) then
|
||||||
|
return err "i3.new_footer_button: button definition missing"
|
||||||
|
elseif not true_str(def.description) then
|
||||||
|
return err "i3.new_footer_button: description missing"
|
||||||
|
elseif not def.image then
|
||||||
|
return err "i3.new_footer_button: image missing"
|
||||||
|
elseif #i3.footer_buttons == 16 then
|
||||||
|
return err(fmt("i3.new_footer_button: cannot add '%s' button. Limit reached (16).", def.name))
|
||||||
|
end
|
||||||
|
|
||||||
|
def.name = name
|
||||||
|
insert(i3.footer_buttons, def)
|
||||||
|
end
|
||||||
|
|
||||||
|
function i3.remove_footer_button(name)
|
||||||
|
if not true_str(name) then
|
||||||
|
return err "i3.remove_footer_button: tab name missing"
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = #i3.footer_buttons, 2, -1 do
|
||||||
|
local def = i3.footer_buttons[i]
|
||||||
|
if def and name == def.name then
|
||||||
|
remove(i3.footer_buttons, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function i3.override_footer_button(name, newdef)
|
||||||
|
if not true_str(name) then
|
||||||
|
return err "i3.override_footer_button: button name missing"
|
||||||
|
elseif not true_table(newdef) then
|
||||||
|
return err "i3.override_footer_button: button definition missing"
|
||||||
|
elseif not true_str(newdef.description) then
|
||||||
|
return err "i3.override_footer_button: description missing"
|
||||||
|
elseif not true_str(newdef.image) then
|
||||||
|
return err "i3.override_footer_button: image missing"
|
||||||
|
end
|
||||||
|
|
||||||
|
newdef.name = name
|
||||||
|
|
||||||
|
for i, def in ipairs(i3.footer_buttons) do
|
||||||
|
if def.name == name then
|
||||||
|
i3.footer_buttons[i] = newdef
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
i3.new_footer_button("trash", {
|
||||||
|
description = S"Clear inventory",
|
||||||
|
image = "i3_trash.png",
|
||||||
|
formspec = confirm_trash_footer_fs,
|
||||||
|
fields = confirm_trash_footer_fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
i3.new_footer_button("sort", {
|
||||||
|
description = S"Sort inventory",
|
||||||
|
image = "i3_sort.png",
|
||||||
|
fields = function(player, data, fields)
|
||||||
|
sort_inventory(player, data)
|
||||||
|
-- Immediately disable, since nothing is displayed.
|
||||||
|
return false
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
i3.new_footer_button("settings", {
|
||||||
|
description = S"Settings",
|
||||||
|
image = "i3_settings.png",
|
||||||
|
formspec = settings_footer_fs,
|
||||||
|
fields = settings_footer_fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
i3.new_footer_button("home", {
|
||||||
|
description = S"Go home",
|
||||||
|
image = "i3_home.png",
|
||||||
|
fields = home_footer_fields,
|
||||||
|
})
|
||||||
|
|
||||||
i3.register_craft_type("digging", {
|
i3.register_craft_type("digging", {
|
||||||
description = S"Digging",
|
description = S"Digging",
|
||||||
icon = "i3_steelpick.png",
|
icon = "i3_steelpick.png",
|
||||||
|
|
119
src/fields.lua
119
src/fields.lua
|
@ -9,6 +9,7 @@ IMPORT("valid_item", "get_stack", "craft_stack", "clean_name", "check_privs", "s
|
||||||
IMPORT("msg", "is_fav", "pos_to_str", "str_to_pos", "add_hud_waypoint", "play_sound", "reset_data")
|
IMPORT("msg", "is_fav", "pos_to_str", "str_to_pos", "add_hud_waypoint", "play_sound", "reset_data")
|
||||||
IMPORT("search", "sort_inventory", "sort_by_category", "get_recipes", "get_detached_inv", "update_inv_size")
|
IMPORT("search", "sort_inventory", "sort_by_category", "get_recipes", "get_detached_inv", "update_inv_size")
|
||||||
|
|
||||||
|
-- Fields-handler for any tab displaying the inventory & footer (that is, with def.slots true).
|
||||||
local function inv_fields(player, data, fields)
|
local function inv_fields(player, data, fields)
|
||||||
local name = data.player_name
|
local name = data.player_name
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
|
@ -19,6 +20,13 @@ local function inv_fields(player, data, fields)
|
||||||
data.font_size = tonumber(fields.sb_font_size:match"-?%d+$")
|
data.font_size = tonumber(fields.sb_font_size:match"-?%d+$")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local footer = data.footer_button and i3.footer_buttons[data.footer_button]
|
||||||
|
if footer and footer.fields then
|
||||||
|
if not footer.fields(player, data, fields) then
|
||||||
|
data.footer_button = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
for field in pairs(fields) do
|
for field in pairs(fields) do
|
||||||
if sub(field, 1, 4) == "btn_" then
|
if sub(field, 1, 4) == "btn_" then
|
||||||
data.subcat = indexof(i3.categories, sub(field, 5))
|
data.subcat = indexof(i3.categories, sub(field, 5))
|
||||||
|
@ -93,8 +101,7 @@ local function inv_fields(player, data, fields)
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields.quit then
|
if fields.quit then
|
||||||
data.confirm_trash = nil
|
data.footer_button = nil
|
||||||
data.show_settings = nil
|
|
||||||
data.waypoint_see = nil
|
data.waypoint_see = nil
|
||||||
data.bag_rename = nil
|
data.bag_rename = nil
|
||||||
data.goto_page = nil
|
data.goto_page = nil
|
||||||
|
@ -103,58 +110,9 @@ local function inv_fields(player, data, fields)
|
||||||
data.enable_search = nil
|
data.enable_search = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif fields.trash then
|
|
||||||
data.show_settings = nil
|
|
||||||
data.confirm_trash = true
|
|
||||||
|
|
||||||
elseif fields.settings then
|
|
||||||
if not data.show_settings then
|
|
||||||
data.confirm_trash = nil
|
|
||||||
data.show_settings = true
|
|
||||||
else
|
|
||||||
data.show_settings = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif fields.confirm_trash_yes or fields.confirm_trash_no then
|
|
||||||
if fields.confirm_trash_yes then
|
|
||||||
inv:set_list("main", {})
|
|
||||||
inv:set_list("craft", {})
|
|
||||||
end
|
|
||||||
|
|
||||||
data.confirm_trash = nil
|
|
||||||
|
|
||||||
elseif fields.close_settings then
|
|
||||||
data.show_settings = nil
|
|
||||||
|
|
||||||
elseif fields.close_preview then
|
elseif fields.close_preview then
|
||||||
data.waypoint_see = nil
|
data.waypoint_see = nil
|
||||||
|
|
||||||
elseif fields.sort then
|
|
||||||
sort_inventory(player, data)
|
|
||||||
|
|
||||||
elseif (fields.home or fields.set_home) and not check_privs(name, {home = true}) then
|
|
||||||
return msg(name, "'home' privilege missing")
|
|
||||||
|
|
||||||
elseif fields.home then
|
|
||||||
if sethome then
|
|
||||||
if not sethome.go(name) then
|
|
||||||
return msg(name, "No home set")
|
|
||||||
end
|
|
||||||
elseif not data.home then
|
|
||||||
return msg(name, "No home set")
|
|
||||||
else
|
|
||||||
safe_teleport(player, str_to_pos(data.home))
|
|
||||||
end
|
|
||||||
|
|
||||||
msg(name, S"Welcome back home!")
|
|
||||||
|
|
||||||
elseif fields.set_home then
|
|
||||||
if sethome then
|
|
||||||
sethome.set(name, player:get_pos())
|
|
||||||
else
|
|
||||||
data.home = pos_to_str(player:get_pos(), 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif fields.bag_rename then
|
elseif fields.bag_rename then
|
||||||
data.bag_rename = true
|
data.bag_rename = true
|
||||||
|
|
||||||
|
@ -429,6 +387,55 @@ local function rcp_fields(player, data, fields)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Fields input-handler for the Home footer-button.
|
||||||
|
local function home_footer_fields(player, data, fields)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
|
||||||
|
-- Use minetest_game’s sethome API, if available.
|
||||||
|
if sethome then
|
||||||
|
if not sethome.go(name) then
|
||||||
|
msg(name, "No home set")
|
||||||
|
else
|
||||||
|
msg(name, S"Welcome back home!")
|
||||||
|
end
|
||||||
|
-- Otherwise, use i3’s home.
|
||||||
|
elseif not data.home then
|
||||||
|
msg(name, "No home set")
|
||||||
|
elseif name then
|
||||||
|
safe_teleport(player, str_to_pos(data.home))
|
||||||
|
msg(name, S"Welcome back home!")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Immediately disable this footer-dialogue, since nothing is displayed.
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Fields input-handler for the “Confirm trash” footer-dialogue.
|
||||||
|
local function confirm_trash_footer_fields(player, data, fields)
|
||||||
|
local inv = player:get_inventory()
|
||||||
|
if fields.confirm_trash_yes then
|
||||||
|
inv:set_list("main", {})
|
||||||
|
inv:set_list("craft", {})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- In any case, disable this footer-dialogue.
|
||||||
|
return not (fields.confirm_trash_yes or fields.confirm_trash_no)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Fields input-handler for the settings footer-dialogue.
|
||||||
|
local function settings_footer_fields(player, data, fields)
|
||||||
|
if fields.set_home and not check_privs(name, {home = true}) then
|
||||||
|
return msg(name, "'home' privilege missing")
|
||||||
|
elseif fields.set_home then
|
||||||
|
if sethome then
|
||||||
|
sethome.set(player:get_player_name(), player:get_pos())
|
||||||
|
else
|
||||||
|
data.home = pos_to_str(player:get_pos(), 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return not fields.close_settings
|
||||||
|
end
|
||||||
|
|
||||||
core.register_on_player_receive_fields(function(player, formname, fields)
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
|
|
||||||
|
@ -465,6 +472,14 @@ core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
data.itab = tonumber(f:sub(-1))
|
data.itab = tonumber(f:sub(-1))
|
||||||
sort_by_category(data)
|
sort_by_category(data)
|
||||||
break
|
break
|
||||||
|
elseif sub(f, 1, 7) == "footer_" then
|
||||||
|
local footer_name = sub(f, 8)
|
||||||
|
for i, footer in ipairs(i3.footer_buttons) do
|
||||||
|
if footer.name == footer_name then
|
||||||
|
data.footer_button = i
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -484,3 +499,5 @@ core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
|
||||||
return true, set_fs(player)
|
return true, set_fs(player)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
return home_footer_fields, confirm_trash_footer_fields, settings_footer_fields
|
||||||
|
|
42
src/gui.lua
42
src/gui.lua
|
@ -569,14 +569,16 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function show_settings(fs, data, player)
|
-- Get the formspec of the footer “Confirm trash” dialogue.
|
||||||
if data.confirm_trash then
|
local function confirm_trash_footer_fs(player, data, fs)
|
||||||
image(2.8, 10.65, 4.6, 0.7, PNG.bg_goto)
|
image(2.8, 10.65, 4.6, 0.7, PNG.bg_goto)
|
||||||
label(3.02, 11, "Confirm trash?")
|
label(3.02, 11, "Confirm trash?")
|
||||||
image_button(5.07, 10.75, 1, 0.5, "", "confirm_trash_yes", "Yes")
|
image_button(5.07, 10.75, 1, 0.5, "", "confirm_trash_yes", "Yes")
|
||||||
image_button(6.17, 10.75, 1, 0.5, "", "confirm_trash_no", "No")
|
image_button(6.17, 10.75, 1, 0.5, "", "confirm_trash_no", "No")
|
||||||
|
end
|
||||||
|
|
||||||
elseif data.show_settings then
|
-- Get the formspec of the footer settings-dialogue.
|
||||||
|
local function settings_footer_fs(player, data, fs)
|
||||||
fs"container[-0.06,0]"
|
fs"container[-0.06,0]"
|
||||||
image(2.2, 9, 6.1, 2.35, PNG.bg_content)
|
image(2.2, 9, 6.1, 2.35, PNG.bg_content)
|
||||||
|
|
||||||
|
@ -688,25 +690,27 @@ local function show_settings(fs, data, player)
|
||||||
|
|
||||||
fs"container_end[]"
|
fs"container_end[]"
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
|
-- Get the inventory-footer’s formspec.
|
||||||
local function get_footer(fs, data, player)
|
local function get_footer(fs, data, player)
|
||||||
local btn = {
|
-- Render individual footer buttons.
|
||||||
{"trash", ES"Clear inventory"},
|
local starting_x = 3.43 - (.3 * (#i3.footer_buttons - 4)) -- Center the icons
|
||||||
{"sort", ES"Sort inventory"},
|
for i, btn in ipairs(i3.footer_buttons) do
|
||||||
{"settings", ES"Settings"},
|
local btn_name = "footer_" .. btn.name
|
||||||
{"home", ES"Go home"},
|
fs("style[%s;fgimg=%s;fgimg_hovered=%s^\\[brighten^\\[colorize:#fff:100;content_offset=0]",
|
||||||
}
|
btn_name, btn.image, btn.image)
|
||||||
|
image_button(i + starting_x - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "")
|
||||||
for i, v in ipairs(btn) do
|
fs("tooltip[%s;%s;#32333899;#fff]", btn_name, btn.description)
|
||||||
local btn_name, tooltip = unpack(v)
|
end
|
||||||
fs("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]",
|
|
||||||
btn_name, PNG[btn_name], PNG[fmt("%s_hover", btn_name)])
|
-- Render the current-selected button’s formspec, if one is active.
|
||||||
image_button(i + 3.43 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "")
|
footer = i3.footer_buttons[data.footer_button]
|
||||||
fs("tooltip[%s;%s;#32333899;#fff]", btn_name, tooltip)
|
if footer then
|
||||||
|
if footer.formspec then
|
||||||
|
footer.formspec(player, data, fs)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
show_settings(fs, data, player)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_slots(fs, data, player)
|
local function get_slots(fs, data, player)
|
||||||
|
@ -1821,4 +1825,4 @@ local function make_fs(player, data)
|
||||||
return fs
|
return fs
|
||||||
end
|
end
|
||||||
|
|
||||||
return make_fs, get_inventory_fs
|
return make_fs, get_inventory_fs, confirm_trash_footer_fs, settings_footer_fs
|
||||||
|
|
Ŝarĝante…
Reference in New Issue