mirror of
https://github.com/minetest-mods/i3.git
synced 2025-07-03 09:00:23 +02:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
66b88dec3b | |||
c207db38a0 | |||
c89cbf700f | |||
a1a4535f26 | |||
80b927de1c | |||
482027d09b | |||
ea7140a7bb | |||
84416b130b | |||
b31e7a48ab | |||
7a4f352ce4 |
3
API.md
3
API.md
@ -26,6 +26,7 @@ Custom tabs can be added to the `i3` inventory as follow (example):
|
||||
i3.new_tab("stuff", {
|
||||
description = "Stuff",
|
||||
image = "image.png", -- Optional, add an image next to the tab description
|
||||
slots = true -- Optional, whether the inventory slots are shown or not. Disabled by default.
|
||||
|
||||
--
|
||||
-- The functions below are all optional
|
||||
@ -49,7 +50,7 @@ i3.new_tab("stuff", {
|
||||
-- Do things
|
||||
end
|
||||
|
||||
i3.set_fs(player) -- Update the formspec
|
||||
-- No need to update the formspec, it's automatic
|
||||
end,
|
||||
})
|
||||
```
|
||||
|
4
LICENSE
4
LICENSE
@ -28,10 +28,12 @@ Licenses of media (sounds)
|
||||
|
||||
Lone_Wolf (CC0):
|
||||
i3_tab.ogg
|
||||
i3_craft.ogg
|
||||
i3_click.ogg
|
||||
i3_cannot.ogg
|
||||
|
||||
MadPanCake (CC0):
|
||||
i3_craft.ogg (https://freesound.org/people/MadPanCake/sounds/567849/)
|
||||
|
||||
Licenses of media (textures)
|
||||
----------------------------
|
||||
|
||||
|
3
init.lua
3
init.lua
@ -20,7 +20,7 @@ local function lf(path)
|
||||
end
|
||||
|
||||
i3 = {
|
||||
version = 114,
|
||||
version = 115,
|
||||
data = core.deserialize(storage:get_string"data") or {},
|
||||
|
||||
settings = {
|
||||
@ -113,6 +113,7 @@ i3.files.common()
|
||||
i3.files.api(http)
|
||||
i3.files.compress()
|
||||
i3.files.detached()
|
||||
i3.files.fields()
|
||||
i3.files.groups()
|
||||
i3.files.callbacks(http, storage)
|
||||
|
||||
|
Binary file not shown.
@ -196,7 +196,7 @@ end
|
||||
i3.new_tab("inventory", {
|
||||
description = S"Inventory",
|
||||
formspec = get_inventory_fs,
|
||||
fields = i3.files.fields(),
|
||||
slots = true,
|
||||
})
|
||||
|
||||
function i3.remove_tab(name)
|
||||
@ -204,7 +204,7 @@ function i3.remove_tab(name)
|
||||
return err "i3.remove_tab: tab name missing"
|
||||
end
|
||||
|
||||
for i = #i3.tabs, 1, -1 do
|
||||
for i = #i3.tabs, 2, -1 do
|
||||
local def = i3.tabs[i]
|
||||
if def and name == def.name then
|
||||
remove(i3.tabs, i)
|
||||
@ -447,11 +447,9 @@ end
|
||||
function i3.remove_minitab(name)
|
||||
if not true_str(name) then
|
||||
return err "i3.remove_minitab: name missing"
|
||||
elseif name == "all" then
|
||||
return err "i3.remove_minitab: removing the 'All' tab is not allowed"
|
||||
end
|
||||
|
||||
for i = #i3.minitabs, 1, -1 do
|
||||
for i = #i3.minitabs, 2, -1 do
|
||||
local v = i3.minitabs[i]
|
||||
if v and v.name == name then
|
||||
remove(i3.minitabs, i)
|
||||
|
@ -211,8 +211,6 @@ local function inv_fields(player, data, fields)
|
||||
elseif fields.hide_debug_grid then
|
||||
data.hide_debug_grid = not data.hide_debug_grid
|
||||
end
|
||||
|
||||
return set_fs(player)
|
||||
end
|
||||
|
||||
local function select_item(player, data, fields)
|
||||
@ -465,11 +463,15 @@ core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
|
||||
local tab = i3.tabs[data.tab]
|
||||
|
||||
if tab and tab.fields then
|
||||
return true, tab.fields(player, data, fields)
|
||||
if tab then
|
||||
if tab.slots then
|
||||
inv_fields(player, data, fields)
|
||||
end
|
||||
|
||||
if tab.fields then
|
||||
tab.fields(player, data, fields)
|
||||
end
|
||||
end
|
||||
|
||||
return true, set_fs(player)
|
||||
end)
|
||||
|
||||
return inv_fields
|
||||
|
173
src/gui.lua
173
src/gui.lua
@ -124,33 +124,13 @@ local function get_stack_max(inv, data, is_recipe, rcp)
|
||||
end
|
||||
end
|
||||
|
||||
return max_stacks
|
||||
local missing = {}
|
||||
|
||||
for item, count in pairs(counts_rcp) do
|
||||
missing[item] = max(0, count - (counts_inv[item] or 0))
|
||||
end
|
||||
|
||||
local function get_inv_slots(data, fs)
|
||||
local legacy_inventory = data.legacy_inventory
|
||||
local hotbar_len = data.hotbar_len
|
||||
local inv_x = legacy_inventory and 0.23 or 0.22
|
||||
local inv_y = legacy_inventory and 6.7 or 6.9
|
||||
local spacing = legacy_inventory and 0.25 or 0.1
|
||||
local size = 1
|
||||
|
||||
fs"style_type[box;colors=#77777710,#77777710,#777,#777]"
|
||||
|
||||
for i = 0, hotbar_len - 1 do
|
||||
box(i * size + inv_x + (i * spacing), inv_y, size, size, "")
|
||||
end
|
||||
|
||||
fs("style_type[list;size=%f;spacing=%f]", size, spacing)
|
||||
fs("list[current_player;main;%f,%f;%u,1;]", inv_x, inv_y, hotbar_len)
|
||||
|
||||
fs("style_type[list;size=%f;spacing=%f,%f]", size, spacing, legacy_inventory and 0.15 or spacing)
|
||||
|
||||
fs("list[current_player;main;%f,%f;%u,%u;%u]", inv_x, inv_y + (legacy_inventory and 1.25 or 1.15),
|
||||
hotbar_len, data.inv_size / hotbar_len, hotbar_len)
|
||||
|
||||
fs"style_type[list;size=1;spacing=0.15]"
|
||||
fs"listring[current_player;craft]listring[current_player;main]"
|
||||
return max_stacks, missing
|
||||
end
|
||||
|
||||
local function add_subtitle(fs, name, y, ctn_len, font_size, sep, label)
|
||||
@ -625,7 +605,9 @@ local function show_settings(fs, data)
|
||||
end
|
||||
|
||||
hypertext(2.2, 9.9, 6, 0.6, "home_pos", fmt("<global size=16><center>%s</center>", str))
|
||||
image_button(4.3, 10.4, 1.8, 0.7, "", "set_home", "Set home")
|
||||
fs("style[set_home;padding=20,10,-210,-10;fgimg=%s;fgimg_hovered=%s]", PNG.home_px, PNG.home_px_hover)
|
||||
image_button(4.1, 10.4, 2.2, 0.7, "", "set_home", "")
|
||||
label(4.9, 10.75, "Set home")
|
||||
|
||||
elseif show_style then
|
||||
checkbox(2.6, 9.95, "cb_hide_tabs", "Hide tabs", tostring(data.hide_tabs))
|
||||
@ -688,11 +670,53 @@ local function show_settings(fs, data)
|
||||
end
|
||||
end
|
||||
|
||||
local function get_footer(fs, data)
|
||||
local btn = {
|
||||
{"trash", ES"Clear inventory"},
|
||||
{"sort", ES"Sort inventory"},
|
||||
{"settings", ES"Settings"},
|
||||
{"home", ES"Go home"},
|
||||
}
|
||||
|
||||
for i, v in ipairs(btn) do
|
||||
local btn_name, tooltip = unpack(v)
|
||||
fs("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]",
|
||||
btn_name, PNG[btn_name], PNG[fmt("%s_hover", btn_name)])
|
||||
image_button(i + 3.43 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "")
|
||||
fs("tooltip[%s;%s]", btn_name, tooltip)
|
||||
end
|
||||
|
||||
show_settings(fs, data)
|
||||
end
|
||||
|
||||
local function get_slots(fs, data)
|
||||
local legacy_inventory = data.legacy_inventory
|
||||
local hotbar_len = data.hotbar_len
|
||||
local inv_x = legacy_inventory and 0.23 or 0.22
|
||||
local inv_y = legacy_inventory and 6.7 or 6.9
|
||||
local spacing = legacy_inventory and 0.25 or 0.1
|
||||
local size = 1
|
||||
|
||||
fs"style_type[box;colors=#77777710,#77777710,#777,#777]"
|
||||
|
||||
for i = 0, hotbar_len - 1 do
|
||||
box(i * size + inv_x + (i * spacing), inv_y, size, size, "")
|
||||
end
|
||||
|
||||
fs("style_type[list;size=%f;spacing=%f]", size, spacing)
|
||||
fs("list[current_player;main;%f,%f;%u,1;]", inv_x, inv_y, hotbar_len)
|
||||
|
||||
fs("style_type[list;size=%f;spacing=%f,%f]", size, spacing, legacy_inventory and 0.15 or spacing)
|
||||
|
||||
fs("list[current_player;main;%f,%f;%u,%u;%u]", inv_x, inv_y + (legacy_inventory and 1.25 or 1.15),
|
||||
hotbar_len, data.inv_size / hotbar_len, hotbar_len)
|
||||
|
||||
fs"listring[current_player;craft]listring[current_player;main]"
|
||||
|
||||
get_footer(fs, data)
|
||||
end
|
||||
|
||||
local function get_inventory_fs(player, data, fs)
|
||||
fs"listcolors[#bababa50;#bababa99]"
|
||||
|
||||
get_inv_slots(data, fs)
|
||||
|
||||
local props = player:get_properties()
|
||||
local ctn_len = 5.7
|
||||
local ctn_hgt = data.legacy_inventory and 6.1 or 6.3
|
||||
@ -772,23 +796,6 @@ local function get_inventory_fs(player, data, fs)
|
||||
fs("scroll_container[3.9,0.2;%f,%f;scrbar_inv;vertical]", ctn_len, ctn_hgt)
|
||||
get_container(fs, data, player, yoffset, ctn_len, award_list, awards_unlocked, award_list_nb, bag_size)
|
||||
fs"scroll_container_end[]"
|
||||
|
||||
local btn = {
|
||||
{"trash", ES"Clear inventory"},
|
||||
{"sort", ES"Sort inventory"},
|
||||
{"settings", ES"Settings"},
|
||||
{"home", ES"Go home"},
|
||||
}
|
||||
|
||||
for i, v in ipairs(btn) do
|
||||
local btn_name, tooltip = unpack(v)
|
||||
fs("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]",
|
||||
btn_name, PNG[btn_name], PNG[fmt("%s_hover", btn_name)])
|
||||
image_button(i + 3.43 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "")
|
||||
fs("tooltip[%s;%s]", btn_name, tooltip)
|
||||
end
|
||||
|
||||
show_settings(fs, data)
|
||||
end
|
||||
|
||||
local function get_tooltip(item, info, lang_code)
|
||||
@ -946,7 +953,9 @@ local function get_output_fs(fs, data, rcp, is_recipe, is_usage, shapeless, righ
|
||||
local itemstr = ESC(item:to_string())
|
||||
item_image_button(X + 0.11, Y, BTN_SIZE, BTN_SIZE, itemstr, _name, "")
|
||||
|
||||
if item:get_stack_max() < count then
|
||||
local stackmax = item:get_stack_max()
|
||||
|
||||
if stackmax == 1 and count > 1 then
|
||||
label(X + 1.05, Y + 1, count)
|
||||
end
|
||||
|
||||
@ -1097,7 +1106,9 @@ local function get_grid_fs(fs, data, rcp, is_recipe, is_usage)
|
||||
|
||||
item_image_button(X, Y, btn_size, btn_size, itemstr, btn_name, label)
|
||||
|
||||
if item:get_stack_max() < count then
|
||||
local stackmax = item:get_stack_max()
|
||||
|
||||
if stackmax == 1 and count > 1 then
|
||||
label(X + 0.95, Y + 0.95, count)
|
||||
end
|
||||
end
|
||||
@ -1310,9 +1321,10 @@ local function get_crafting_fs(fs, data, is_recipe, is_usage, max_stacks_rcp, ma
|
||||
fs("scrollbaroptions[min=1;max=%u;smallstep=1]", craft_max)
|
||||
|
||||
scrollbar(x + 0.2, data.yoffset + 1.45, 2.5, 0.35, "horizontal", fmt("scrbar_%s", name), stack_fs)
|
||||
button(x + 0.2, data.yoffset + 1.85, 2.5, 0.7, fmt("craft_%s", name), ES("Craft (×@1)", stack_fs))
|
||||
button(x + 0.2, data.yoffset + 1.9, 2.5, 0.7, fmt("craft_%s", name), ES("Craft (×@1)", stack_fs))
|
||||
|
||||
fs"style_type[label;font_size=16;textcolor=#fff]"
|
||||
fs"style_type[image,button,image_button;noclip=false]"
|
||||
end
|
||||
|
||||
local function get_rcp_extra(fs, data, player, panel, is_recipe, is_usage)
|
||||
@ -1322,15 +1334,15 @@ local function get_rcp_extra(fs, data, player, panel, is_recipe, is_usage)
|
||||
if rn then
|
||||
local rcp_ok = is_recipe and panel.rcp[data.rnum].type == "normal"
|
||||
local usg_ok = is_usage and panel.rcp[data.unum].type == "normal"
|
||||
local max_stacks_rcp, max_stacks_usg = 0, 0
|
||||
local max_stacks_rcp, max_stacks_usg, missing_rcp, missing_usg = 0, 0
|
||||
local inv = player:get_inventory()
|
||||
|
||||
if rcp_ok then
|
||||
max_stacks_rcp = get_stack_max(inv, data, is_recipe, panel.rcp[data.rnum])
|
||||
max_stacks_rcp, missing_rcp = get_stack_max(inv, data, is_recipe, panel.rcp[data.rnum])
|
||||
end
|
||||
|
||||
if usg_ok then
|
||||
max_stacks_usg = get_stack_max(inv, data, is_recipe, panel.rcp[data.unum])
|
||||
max_stacks_usg, missing_usg = get_stack_max(inv, data, is_recipe, panel.rcp[data.unum])
|
||||
end
|
||||
|
||||
if is_recipe and max_stacks_rcp == 0 then
|
||||
@ -1343,6 +1355,23 @@ local function get_rcp_extra(fs, data, player, panel, is_recipe, is_usage)
|
||||
|
||||
if max_stacks_rcp > 0 or max_stacks_usg > 0 then
|
||||
get_crafting_fs(fs, data, is_recipe, is_usage, max_stacks_rcp, max_stacks_usg)
|
||||
|
||||
elseif rcp_ok or usg_ok then
|
||||
local X = data.inv_width + 7.35
|
||||
local Y = data.yoffset + 0.2
|
||||
local missing = is_recipe and missing_rcp or missing_usg
|
||||
local str = ""
|
||||
|
||||
for item, count in pairs(missing) do
|
||||
if count > 0 then
|
||||
local name = is_group(item) and (i3.group_names[item:sub(7)] or item) or
|
||||
get_desc(item, data.lang_code)
|
||||
str = fmt("%s\n%s %s", str, clr("#ff0", count .. '×'), name)
|
||||
end
|
||||
end
|
||||
|
||||
image(X, Y, 0.45, 0.45, PNG.crafting .. "^\\[opacity:100")
|
||||
tooltip(X, Y, 0.45, 0.45, fmt("%s:%s", ES"Missing materials for crafting", str))
|
||||
end
|
||||
|
||||
get_rcp_lbl(fs, data, panel, rn, is_recipe, is_usage)
|
||||
@ -1408,11 +1437,11 @@ local function get_header_items_fs(fs, data)
|
||||
|
||||
if not recipe_filter_set() then
|
||||
for _, v in ipairs(i3.minitabs) do
|
||||
if v.name == "Nodes" then
|
||||
if v.name == "nodes" then
|
||||
insert(cat, {"node", "nodes only"})
|
||||
end
|
||||
|
||||
if v.name == "Items" then
|
||||
if v.name == "items" then
|
||||
insert(cat, {"item", "items only"})
|
||||
end
|
||||
end
|
||||
@ -1497,17 +1526,16 @@ local function get_minitabs(fs, data, player, full_height)
|
||||
local selected = id == data.itab
|
||||
local hover_texture = selected and PNG.tab_small_hover or PNG.tab_small
|
||||
local flip = top and "^[transformFY" or ""
|
||||
local tabname = fmt("itab_%u", id)
|
||||
|
||||
fs([[ style_type[image_button;bgimg=%s%s;bgimg_hovered=%s%s;
|
||||
bgimg_middle=14,0,-14,-14;padding=-14,0,14,14] ]],
|
||||
hover_texture, flip, PNG.tab_small_hover, flip)
|
||||
fs([[ style[%s;bgimg=%s%s;bgimg_hovered=%s%s;noclip=true;font=bold;font_size=16;
|
||||
textcolor=%s;content_offset=0;sound=i3_tab;bgimg_middle=14,0,-14,-14;padding=-14,0,14,14] ]],
|
||||
tabname, hover_texture, flip, PNG.tab_small_hover, flip, selected and "#fff" or "#bbb")
|
||||
|
||||
fs([[ style_type[image_button;noclip=true;font=bold;font_size=16;
|
||||
textcolor=%s;content_offset=0;sound=i3_tab] ]], selected and "#fff" or "#bbb")
|
||||
fs"style_type[image_button:hovered;textcolor=#fff]"
|
||||
fs("style[%s:hovered;textcolor=#fff]", tabname)
|
||||
|
||||
image_button((data.inv_width - 0.65) + (X * (tab_len + 0.1)),
|
||||
top and -tab_hgh or full_height, tab_len, tab_hgh, "", fmt("itab_%u", id), title)
|
||||
top and -tab_hgh or full_height, tab_len, tab_hgh, "", tabname, title)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1656,17 +1684,17 @@ local function get_tabs_fs(fs, player, data, full_height)
|
||||
local middle = btm and "16,0,-16,-16" or "16,16,-16,-16"
|
||||
local padding = btm and "-16,0,16,16" or "-16,-16,16,16"
|
||||
|
||||
fs([[ style_type[image_button;bgimg=%s;bgimg_hovered=%s;bgimg_middle=%s;padding=%s] ]],
|
||||
bgimg, bgimg_hover, middle, padding)
|
||||
local tabname = fmt("tab_%s", def.name)
|
||||
|
||||
fs("style_type[image_button;noclip=true;font_size=16;textcolor=%s;content_offset=0;sound=i3_tab]",
|
||||
selected and "#fff" or "#ddd")
|
||||
fs([[ style[%s;bgimg=%s;bgimg_hovered=%s;bgimg_middle=%s;padding=%s;noclip=true;
|
||||
font=bold;font_size=16;textcolor=%s;content_offset=0;sound=i3_tab] ]],
|
||||
tabname, bgimg, bgimg_hover, middle, padding, selected and "#fff" or "#bbb")
|
||||
|
||||
local X = (data.inv_width / 2) + (c * (tab_len + 0.1)) - ((tab_len + 0.05) * (shift / 2))
|
||||
local Y = btm and full_height or -tab_hgh
|
||||
|
||||
fs"style_type[image_button:hovered;textcolor=#fff]"
|
||||
image_button(X, Y, tab_len, tab_hgh, "", fmt("tab_%s", def.name), ESC(def.description))
|
||||
fs("style[%s:hovered;textcolor=#fff]", tabname)
|
||||
image_button(X, Y, tab_len, tab_hgh, "", tabname, ESC(def.description))
|
||||
|
||||
if true_str(def.image) then
|
||||
local desc = translate(data.lang_code, def.description)
|
||||
@ -1674,6 +1702,7 @@ local function get_tabs_fs(fs, player, data, full_height)
|
||||
|
||||
fs"style_type[image;noclip=true]"
|
||||
image(X + (tab_len / 2) - ((desc_len * 0.1) / 2) - 0.55, Y + 0.05, 0.35, 0.35, def.image)
|
||||
fs"style_type[image;noclip=false]"
|
||||
end
|
||||
|
||||
c++
|
||||
@ -1736,10 +1765,16 @@ local function make_fs(player, data)
|
||||
|
||||
local tab = i3.tabs[data.tab]
|
||||
|
||||
if tab and tab.formspec then
|
||||
if tab then
|
||||
if tab.formspec then
|
||||
tab.formspec(player, data, fs)
|
||||
end
|
||||
|
||||
if tab.slots then
|
||||
get_slots(fs, data)
|
||||
end
|
||||
end
|
||||
|
||||
if data.query_item then
|
||||
get_panels(fs, data, player)
|
||||
else
|
||||
|
@ -118,8 +118,12 @@ core.register_globalstep(function(dt)
|
||||
local data = i3.data[name]
|
||||
if not data then return end
|
||||
|
||||
local has_text = player:hud_get(data.hud.wielditem).text ~= ""
|
||||
|
||||
if not data.wielditem_hud then
|
||||
if has_text then
|
||||
player:hud_change(data.hud.wielditem, "text", "")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
@ -127,7 +131,7 @@ core.register_globalstep(function(dt)
|
||||
local wieldidx = player:get_wield_index()
|
||||
|
||||
if wieldidx == data.old_wieldidx then
|
||||
if data.timer >= i3.settings.wielditem_fade_after then
|
||||
if data.timer >= i3.settings.wielditem_fade_after and has_text then
|
||||
player:hud_change(data.hud.wielditem, "text", "")
|
||||
end
|
||||
return
|
||||
|
@ -54,6 +54,8 @@ local PNG = {
|
||||
node = "i3_node.png",
|
||||
item = "i3_item.png",
|
||||
cube = "i3_cube.png",
|
||||
home_px = "i3_home_px.png",
|
||||
home_px_hover = "i3_home_px_hover.png",
|
||||
|
||||
cancel_hover = "i3_cancel.png^\\[brighten",
|
||||
search_hover = "i3_search.png^\\[brighten",
|
||||
@ -83,6 +85,9 @@ local PNG = {
|
||||
}
|
||||
|
||||
local styles = string.format([[
|
||||
listcolors[#bababa50;#bababa99]
|
||||
|
||||
style_type[list;size=1;spacing=0.15]
|
||||
style_type[field;border=false;bgcolor=transparent]
|
||||
style_type[label,field;font_size=16]
|
||||
style_type[button;border=false;content_offset=0]
|
||||
|
@ -1,16 +1,32 @@
|
||||
local SWITCH
|
||||
|
||||
i3.new_tab("test1", {
|
||||
description = "Test 1 Test 1",
|
||||
image = "i3_heart.png",
|
||||
|
||||
formspec = function(player, data, fs)
|
||||
fs("button", 3, 4, 3, 0.8, "test", "Click here")
|
||||
fs("label", 3, 1, "Just a test")
|
||||
|
||||
|
||||
if SWITCH then
|
||||
fs"label[3,2;Button clicked]"
|
||||
else
|
||||
fs"label[3,2;Lorem Ipsum]"
|
||||
end
|
||||
end,
|
||||
|
||||
fields = function(player, data, fields)
|
||||
if fields.test then
|
||||
SWITCH = true
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
i3.new_tab("test2", {
|
||||
description = "Test 2",
|
||||
image = "i3_mesepick.png",
|
||||
slots = true,
|
||||
|
||||
formspec = function(player, data, fs)
|
||||
fs("label[3,1;Test 2]")
|
||||
|
BIN
textures/i3_home_px.png
Normal file
BIN
textures/i3_home_px.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
BIN
textures/i3_home_px_hover.png
Normal file
BIN
textures/i3_home_px_hover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
Reference in New Issue
Block a user