Add filter-by-category functionality (#171)

- Added API for configuring categories
- Added display for categories above page
- Reduced height of page by 1 row to make room for categories
- Added L/R scroll through when there are more categories than columns
- Added pre-filter methods for categories and uncategorised items
- Added categories for (most) items in the default game


Co-authored-by: Oversword <bionc:oversword.co.uk>
This commit is contained in:
Oversword 2021-04-05 19:07:14 +01:00 committed by GitHub
parent 860371ecf8
commit 6e6383f082
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1069 additions and 18 deletions

@ -14,6 +14,7 @@ read_globals = {
"ItemStack", "datastorage", "ItemStack", "datastorage",
"hb", "hb",
"doors",
} }
files["callbacks.lua"].ignore = { "player", "draw_lite_mode" } files["callbacks.lua"].ignore = { "player", "draw_lite_mode" }

@ -19,6 +19,8 @@ minetest.register_on_joinplayer(function(player)
unified_inventory.active_search_direction[player_name] = "nochange" unified_inventory.active_search_direction[player_name] = "nochange"
unified_inventory.apply_filter(player, "", "nochange") unified_inventory.apply_filter(player, "", "nochange")
unified_inventory.current_searchbox[player_name] = "" unified_inventory.current_searchbox[player_name] = ""
unified_inventory.current_category[player_name] = "all"
unified_inventory.current_category_scroll[player_name] = 0
unified_inventory.alternate[player_name] = 1 unified_inventory.alternate[player_name] = 1
unified_inventory.current_item[player_name] = nil unified_inventory.current_item[player_name] = nil
unified_inventory.current_craft_direction[player_name] = "recipe" unified_inventory.current_craft_direction[player_name] = "recipe"
@ -69,6 +71,41 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
unified_inventory.current_searchbox[player_name] = fields.searchbox unified_inventory.current_searchbox[player_name] = fields.searchbox
end end
local clicked_category
for name, value in pairs(fields) do
local category_name = string.match(name, "^category_(.+)$")
if category_name then
clicked_category = category_name
break
end
end
if clicked_category
and clicked_category ~= unified_inventory.current_category[player_name] then
unified_inventory.current_category[player_name] = clicked_category
unified_inventory.apply_filter(player, unified_inventory.current_searchbox[player_name], "nochange")
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
if fields.next_category then
local scroll = math.min(#unified_inventory.category_list-ui_peruser.pagecols, unified_inventory.current_category_scroll[player_name] + 1)
if scroll ~= unified_inventory.current_category_scroll[player_name] then
unified_inventory.current_category_scroll[player_name] = scroll
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
end
if fields.prev_category then
local scroll = math.max(0, unified_inventory.current_category_scroll[player_name] - 1)
if scroll ~= unified_inventory.current_category_scroll[player_name] then
unified_inventory.current_category_scroll[player_name] = scroll
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
end
for i, def in pairs(unified_inventory.buttons) do for i, def in pairs(unified_inventory.buttons) do
if fields[def.name] then if fields[def.name] then
def.action(player) def.action(player)
@ -126,6 +163,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
clicked_item = unified_inventory.demangle_for_formspec(mangled_item) clicked_item = unified_inventory.demangle_for_formspec(mangled_item)
if string.sub(clicked_item, 1, 6) == "group:" then if string.sub(clicked_item, 1, 6) == "group:" then
-- Change search filter to this group -- Change search filter to this group
unified_inventory.current_category[player_name] = "all"
apply_new_filter(player, clicked_item, new_dir) apply_new_filter(player, clicked_item, new_dir)
return return
end end

149
category.lua Normal file

@ -0,0 +1,149 @@
local S = minetest.get_translator("unified_inventory")
unified_inventory.registered_categories = {}
unified_inventory.registered_category_items = {}
unified_inventory.category_list = {}
local function char_to_sort_index(char_code)
if char_code <= 32 then
-- Command codes, no thanks
return 0
end
if char_code <= 64 then
-- Sorts numbers, and some punctuation, after letters
return char_code
end
if char_code >= 158 then
-- Out of sortable range
return 0
end
if char_code > 122 then
-- Avoids overlap with {, |, } and ~
return char_code - 58
end
if char_code > 96 then
-- Normalises lowercase with uppercase
return char_code - 96
end
return char_code - 64
end
local function string_to_sort_index(str)
local max_chars = 5
local power = 100
local index = 0
for i=1,math.min(#str, max_chars) do
index = index + (char_to_sort_index(string.byte(str, i))/(power^i))
end
return index
end
function update_category_list()
local category_list = {}
table.insert(category_list, {
name = "all",
label = S("All Items"),
symbol = "ui_category_all.png",
index = -2,
})
table.insert(category_list, {
name = "uncategorized",
label = S("Misc. Items"),
symbol = "ui_category_none.png",
index = -1,
})
for category, def in pairs(unified_inventory.registered_categories) do
table.insert(category_list, {
name = category,
label = def.label or category,
symbol = def.symbol,
index = def.index or -- sortby defined order
string_to_sort_index(category) -- or do a rudimentary alphabetical sort
})
end
table.sort(category_list, function (a,b)
return a.index < b.index
end)
unified_inventory.category_list = category_list
end
local function ensure_category_exists(category_name)
if not unified_inventory.registered_categories[category_name] then
unified_inventory.registered_categories[category_name] = {
symbol = "default:stick",
label = category_name
}
end
if not unified_inventory.registered_category_items[category_name] then
unified_inventory.registered_category_items[category_name] = {}
end
end
function unified_inventory.register_category(category_name, config)
ensure_category_exists(category_name)
if config and config.symbol then
unified_inventory.set_category_symbol(category_name, config.symbol)
end
if config and config.label then
unified_inventory.set_category_label(category_name, config.label)
end
if config and config.index then
unified_inventory.set_category_index(category_name, config.index)
end
if config and config.items then
unified_inventory.add_category_items(category_name, config.items)
end
update_category_list()
end
function unified_inventory.set_category_symbol(category_name, symbol)
ensure_category_exists(category_name)
unified_inventory.registered_categories[category_name].symbol = symbol
update_category_list()
end
function unified_inventory.set_category_label(category_name, label)
ensure_category_exists(category_name)
unified_inventory.registered_categories[category_name].label = label
update_category_list()
end
function unified_inventory.set_category_index(category_name, index)
ensure_category_exists(category_name)
unified_inventory.registered_categories[category_name].index = index
update_category_list()
end
function unified_inventory.add_category_item(category_name, item)
ensure_category_exists(category_name)
unified_inventory.registered_category_items[category_name][item] = true
end
function unified_inventory.add_category_items(category_name, items)
for _,item in ipairs(items) do
unified_inventory.add_category_item(category_name, item)
end
end
function unified_inventory.remove_category_item(category_name, item)
unified_inventory.registered_category_items[category_name][item] = nil
end
function unified_inventory.remove_category(category_name)
unified_inventory.registered_categories[category_name] = nil
unified_inventory.registered_category_items[category_name] = nil
update_category_list()
end
function unified_inventory.find_category(item)
-- Returns the first category the item exists in
-- Best for checking if an item has any category at all
for category, items in pairs(unified_inventory.registered_category_items) do
if items[item] then return category end
end
end
function unified_inventory.find_categories(item)
-- Returns all the categories the item exists in
-- Best for listing all categories
local categories = {}
for category, items in pairs(unified_inventory.registered_category_items) do
if items[item] then
table.insert(categories, category)
end
end
return categories
end

704
default-categories.lua Normal file

@ -0,0 +1,704 @@
local S = minetest.get_translator("unified_inventory")
unified_inventory.register_category('plants', {
symbol = "flowers:tulip",
label = S("Plant Life")
})
unified_inventory.register_category('building', {
symbol = "default:brick",
label = S("Building Materials")
})
unified_inventory.register_category('tools', {
symbol = "default:pick_diamond",
label = S("Tools")
})
unified_inventory.register_category('minerals', {
symbol = "default:iron_lump",
label = S("Minerals and Metals")
})
unified_inventory.register_category('environment', {
symbol = "default:dirt_with_grass",
label = S("Environment and Worldgen")
})
unified_inventory.register_category('lighting', {
symbol = "default:torch",
label = S("Lighting")
})
if unified_inventory.automatic_categorization then
minetest.register_on_mods_loaded(function()
-- Add biome nodes to environment category
for _,def in pairs(minetest.registered_biomes) do
local env_nodes = {
def.node_riverbed, def.node_top, def.node_filler, def.node_dust,
}
for i,node in pairs(env_nodes) do
if node then
unified_inventory.add_category_item('environment', node)
end
end
end
-- Add minable ores to minerals and everything else (pockets of stone & sand variations) to environment
for _,item in pairs(minetest.registered_ores) do
if item.ore_type == "scatter" then
local drop = minetest.registered_nodes[item.ore].drop
if drop and drop ~= "" then
unified_inventory.add_category_item('minerals', item.ore)
unified_inventory.add_category_item('minerals', drop)
else
unified_inventory.add_category_item('environment', item.ore)
end
else
unified_inventory.add_category_item('environment', item.ore)
end
end
-- Add items by item definition
for name, def in pairs(minetest.registered_items) do
local group = def.groups or {}
if not group.not_in_creative_inventory then
if group.stair or
group.slab or
group.wall or
group.fence then
unified_inventory.add_category_item('building', name)
elseif group.flora or
group.flower or
group.seed or
group.leaves or
group.sapling or
group.tree then
unified_inventory.add_category_item('plants', name)
elseif def.type == 'tool' then
unified_inventory.add_category_item('tools', name)
elseif def.liquidtype == 'source' then
unified_inventory.add_category_item('environment', name)
elseif def.light_source and def.light_source > 0 then
unified_inventory.add_category_item('lighting', name)
elseif group.door or
minetest.global_exists("doors") and (
doors.registered_doors and doors.registered_doors[name..'_a'] or
doors.registered_trapdoors and doors.registered_trapdoors[name]
) then
unified_inventory.add_category_item('building', name)
end
end
end
end)
end
-- [[
unified_inventory.add_category_items('plants', {
"default:dry_grass_5",
"default:acacia_sapling",
"default:blueberry_bush_sapling",
"default:grass_2",
"default:pine_bush_stem",
"default:leaves",
"default:pine_needles",
"default:cactus",
"default:junglegrass",
"default:pine_sapling",
"default:sapling",
"default:bush_stem",
"default:dry_grass_2",
"default:fern_1",
"default:grass_3",
"default:marram_grass_1",
"default:pine_tree",
"default:dry_grass_3",
"default:dry_shrub",
"default:grass_4",
"default:marram_grass_2",
"default:jungleleaves",
"default:apple",
"default:tree",
"default:aspen_tree",
"default:bush_sapling",
"default:grass_5",
"default:blueberry_bush_leaves_with_berries",
"default:acacia_bush_sapling",
"default:grass_1",
"default:aspen_leaves",
"default:marram_grass_3",
"default:large_cactus_seedling",
"default:junglesapling",
"default:dry_grass_4",
"default:acacia_bush_stem",
"default:papyrus",
"default:pine_bush_needles",
"default:bush_leaves",
"default:fern_3",
"default:aspen_sapling",
"default:acacia_tree",
"default:apple_mark",
"default:acacia_leaves",
"default:jungletree",
"default:dry_grass_1",
"default:acacia_bush_leaves",
"default:emergent_jungle_sapling",
"default:fern_2",
"default:blueberries",
"default:sand_with_kelp",
"default:blueberry_bush_leaves",
"default:pine_bush_sapling",
"farming:cotton",
"farming:cotton_1",
"farming:cotton_2",
"farming:cotton_3",
"farming:cotton_4",
"farming:cotton_5",
"farming:cotton_6",
"farming:cotton_7",
"farming:cotton_8",
"farming:cotton_wild",
"farming:seed_cotton",
"farming:seed_wheat",
"farming:straw",
"farming:wheat",
"farming:wheat_1",
"farming:wheat_2",
"farming:wheat_3",
"farming:wheat_4",
"farming:wheat_5",
"farming:wheat_6",
"farming:wheat_7",
"farming:wheat_8",
"flowers:chrysanthemum_green",
"flowers:dandelion_white",
"flowers:dandelion_yellow",
"flowers:geranium",
"flowers:mushroom_brown",
"flowers:mushroom_red",
"flowers:rose",
"flowers:tulip",
"flowers:tulip_black",
"flowers:viola",
"flowers:waterlily",
"flowers:waterlily_waving",
})
unified_inventory.add_category_items('tools', {
"default:sword_diamond",
"default:axe_diamond",
"default:shovel_diamond",
"default:axe_steel",
"default:shovel_mese",
"default:sword_wood",
"default:pick_bronze",
"default:axe_stone",
"default:sword_stone",
"default:pick_stone",
"default:shovel_stone",
"default:sword_mese",
"default:shovel_bronze",
"default:sword_bronze",
"default:axe_bronze",
"default:shovel_steel",
"default:sword_steel",
"default:axe_mese",
"default:shovel_wood",
"default:pick_mese",
"default:axe_wood",
"default:pick_diamond",
"default:pick_wood",
"default:pick_steel",
"farming:hoe_bronze",
"farming:hoe_diamond",
"farming:hoe_mese",
"farming:hoe_steel",
"farming:hoe_stone",
"farming:hoe_wood",
"fire:flint_and_steel",
"map:mapping_kit",
"screwdriver:screwdriver",
"fireflies:bug_net",
"bucket:bucket_empty",
"binoculars:binoculars",
"default:skeleton_key",
})
unified_inventory.add_category_items('minerals', {
"default:stone_with_copper",
"default:stone_with_gold",
"default:stone_with_iron",
"default:copper_ingot",
"default:copper_lump",
"default:gold_lump",
"default:diamondblock",
"default:stone_with_diamond",
"default:stone_with_mese",
"default:steel_ingot",
"default:gold_ingot",
"default:iron_lump",
"default:tinblock",
"default:tin_lump",
"default:stone_with_tin",
"default:mese_crystal",
"default:diamond",
"default:bronze_ingot",
"default:mese",
"default:mese_crystal_fragment",
"default:copperblock",
"default:stone_with_coal",
"default:steelblock",
"default:tin_ingot",
"default:coalblock",
"default:coal_lump",
"default:bronzeblock",
"default:goldblock",
"stairs:slab_bronzeblock",
"stairs:slab_copperblock",
"stairs:slab_steelblock",
"stairs:slab_tinblock",
"stairs:stair_bronzeblock",
"stairs:stair_copperblock",
"stairs:stair_inner_bronzeblock",
"stairs:stair_inner_copperblock",
"stairs:stair_inner_steelblock",
"stairs:stair_inner_tinblock",
"stairs:stair_outer_bronzeblock",
"stairs:stair_outer_copperblock",
"stairs:stair_outer_steelblock",
"stairs:stair_outer_tinblock",
"stairs:stair_steelblock",
"stairs:stair_tinblock",
})
unified_inventory.add_category_items('building', {
"default:fence_rail_aspen_wood",
"default:fence_rail_acacia_wood",
"default:fence_junglewood",
"default:fence_rail_junglewood",
"default:fence_aspen_wood",
"default:fence_pine_wood",
"default:fence_rail_wood",
"default:fence_rail_pine_wood",
"default:fence_acacia_wood",
"default:junglewood",
"default:acacia_wood",
"default:aspen_wood",
"default:fence_wood",
"default:pine_wood",
"default:silver_sandstone",
"default:desert_sandstone",
"default:sandstone_block",
"default:desert_sandstone_brick",
"default:stone_block",
"default:stonebrick",
"default:obsidian_glass",
"default:desert_sandstone_block",
"default:silver_sandstone_brick",
"default:brick",
"default:obsidianbrick",
"default:sandstonebrick",
"default:sandstone",
"default:desert_stone_block",
"default:silver_sandstone_block",
"default:wood",
"default:obsidian_block",
"default:glass",
"default:clay_brick",
"default:desert_stonebrick",
"default:desert_cobble",
"default:cobble",
"default:mossycobble",
"doors:door_glass",
"doors:door_glass_a",
"doors:door_glass_b",
"doors:door_glass_c",
"doors:door_glass_d",
"doors:door_obsidian_glass",
"doors:door_obsidian_glass_a",
"doors:door_obsidian_glass_b",
"doors:door_obsidian_glass_c",
"doors:door_obsidian_glass_d",
"doors:door_steel",
"doors:door_steel_a",
"doors:door_steel_b",
"doors:door_steel_c",
"doors:door_steel_d",
"doors:door_wood",
"doors:door_wood_a",
"doors:door_wood_b",
"doors:door_wood_c",
"doors:door_wood_d",
"doors:gate_acacia_wood_closed",
"doors:gate_acacia_wood_open",
"doors:gate_aspen_wood_closed",
"doors:gate_aspen_wood_open",
"doors:gate_junglewood_closed",
"doors:gate_junglewood_open",
"doors:gate_pine_wood_closed",
"doors:gate_pine_wood_open",
"doors:gate_wood_closed",
"doors:gate_wood_open",
"doors:hidden",
"doors:trapdoor",
"doors:trapdoor_open",
"doors:trapdoor_steel",
"doors:trapdoor_steel_open",
"stairs:slab_bronzeblock",
"stairs:slab_copperblock",
"stairs:slab_steelblock",
"stairs:slab_tinblock",
"stairs:stair_bronzeblock",
"stairs:stair_copperblock",
"stairs:stair_inner_bronzeblock",
"stairs:stair_inner_copperblock",
"stairs:stair_inner_steelblock",
"stairs:stair_inner_tinblock",
"stairs:stair_outer_bronzeblock",
"stairs:stair_outer_copperblock",
"stairs:stair_outer_steelblock",
"stairs:stair_outer_tinblock",
"stairs:stair_steelblock",
"stairs:stair_tinblock",
"stairs:slab_acacia_wood",
"stairs:slab_aspen_wood",
"stairs:slab_brick",
"stairs:slab_cobble",
"stairs:slab_desert_cobble",
"stairs:slab_desert_sandstone",
"stairs:slab_desert_sandstone_block",
"stairs:slab_desert_sandstone_brick",
"stairs:slab_desert_stone",
"stairs:slab_desert_stone_block",
"stairs:slab_desert_stonebrick",
"stairs:slab_glass",
"stairs:slab_goldblock",
"stairs:slab_ice",
"stairs:slab_junglewood",
"stairs:slab_mossycobble",
"stairs:slab_obsidian",
"stairs:slab_obsidian_block",
"stairs:slab_obsidian_glass",
"stairs:slab_obsidianbrick",
"stairs:slab_pine_wood",
"stairs:slab_sandstone",
"stairs:slab_sandstone_block",
"stairs:slab_sandstonebrick",
"stairs:slab_silver_sandstone",
"stairs:slab_silver_sandstone_block",
"stairs:slab_silver_sandstone_brick",
"stairs:slab_snowblock",
"stairs:slab_stone",
"stairs:slab_stone_block",
"stairs:slab_stonebrick",
"stairs:slab_straw",
"stairs:slab_wood",
"stairs:stair_acacia_wood",
"stairs:stair_aspen_wood",
"stairs:stair_brick",
"stairs:stair_cobble",
"stairs:stair_desert_cobble",
"stairs:stair_desert_sandstone",
"stairs:stair_desert_sandstone_block",
"stairs:stair_desert_sandstone_brick",
"stairs:stair_desert_stone",
"stairs:stair_desert_stone_block",
"stairs:stair_desert_stonebrick",
"stairs:stair_glass",
"stairs:stair_goldblock",
"stairs:stair_ice",
"stairs:stair_inner_acacia_wood",
"stairs:stair_inner_aspen_wood",
"stairs:stair_inner_brick",
"stairs:stair_inner_cobble",
"stairs:stair_inner_desert_cobble",
"stairs:stair_inner_desert_sandstone",
"stairs:stair_inner_desert_sandstone_block",
"stairs:stair_inner_desert_sandstone_brick",
"stairs:stair_inner_desert_stone",
"stairs:stair_inner_desert_stone_block",
"stairs:stair_inner_desert_stonebrick",
"stairs:stair_inner_glass",
"stairs:stair_inner_goldblock",
"stairs:stair_inner_ice",
"stairs:stair_inner_junglewood",
"stairs:stair_inner_mossycobble",
"stairs:stair_inner_obsidian",
"stairs:stair_inner_obsidian_block",
"stairs:stair_inner_obsidian_glass",
"stairs:stair_inner_obsidianbrick",
"stairs:stair_inner_pine_wood",
"stairs:stair_inner_sandstone",
"stairs:stair_inner_sandstone_block",
"stairs:stair_inner_sandstonebrick",
"stairs:stair_inner_silver_sandstone",
"stairs:stair_inner_silver_sandstone_block",
"stairs:stair_inner_silver_sandstone_brick",
"stairs:stair_inner_snowblock",
"stairs:stair_inner_stone",
"stairs:stair_inner_stone_block",
"stairs:stair_inner_stonebrick",
"stairs:stair_inner_straw",
"stairs:stair_inner_wood",
"stairs:stair_junglewood",
"stairs:stair_mossycobble",
"stairs:stair_obsidian",
"stairs:stair_obsidian_block",
"stairs:stair_obsidian_glass",
"stairs:stair_obsidianbrick",
"stairs:stair_outer_acacia_wood",
"stairs:stair_outer_aspen_wood",
"stairs:stair_outer_brick",
"stairs:stair_outer_cobble",
"stairs:stair_outer_desert_cobble",
"stairs:stair_outer_desert_sandstone",
"stairs:stair_outer_desert_sandstone_block",
"stairs:stair_outer_desert_sandstone_brick",
"stairs:stair_outer_desert_stone",
"stairs:stair_outer_desert_stone_block",
"stairs:stair_outer_desert_stonebrick",
"stairs:stair_outer_glass",
"stairs:stair_outer_goldblock",
"stairs:stair_outer_ice",
"stairs:stair_outer_junglewood",
"stairs:stair_outer_mossycobble",
"stairs:stair_outer_obsidian",
"stairs:stair_outer_obsidian_block",
"stairs:stair_outer_obsidian_glass",
"stairs:stair_outer_obsidianbrick",
"stairs:stair_outer_pine_wood",
"stairs:stair_outer_sandstone",
"stairs:stair_outer_sandstone_block",
"stairs:stair_outer_sandstonebrick",
"stairs:stair_outer_silver_sandstone",
"stairs:stair_outer_silver_sandstone_block",
"stairs:stair_outer_silver_sandstone_brick",
"stairs:stair_outer_snowblock",
"stairs:stair_outer_stone",
"stairs:stair_outer_stone_block",
"stairs:stair_outer_stonebrick",
"stairs:stair_outer_straw",
"stairs:stair_outer_wood",
"stairs:stair_pine_wood",
"stairs:stair_sandstone",
"stairs:stair_sandstone_block",
"stairs:stair_sandstonebrick",
"stairs:stair_silver_sandstone",
"stairs:stair_silver_sandstone_block",
"stairs:stair_silver_sandstone_brick",
"stairs:stair_snowblock",
"stairs:stair_stone",
"stairs:stair_stone_block",
"stairs:stair_stonebrick",
"stairs:stair_straw",
"stairs:stair_wood",
"xpanes:bar",
"xpanes:bar_flat",
"xpanes:door_steel_bar",
"xpanes:door_steel_bar_a",
"xpanes:door_steel_bar_b",
"xpanes:door_steel_bar_c",
"xpanes:door_steel_bar_d",
"xpanes:obsidian_pane",
"xpanes:obsidian_pane_flat",
"xpanes:pane",
"xpanes:pane_flat",
"xpanes:trapdoor_steel_bar",
"xpanes:trapdoor_steel_bar_open",
"walls:cobble",
"walls:desertcobble",
"walls:mossycobble",
})
unified_inventory.add_category_items('environment', {
"air",
"default:cave_ice",
"default:dirt_with_rainforest_litter",
"default:gravel",
"default:dry_dirt_with_dry_grass",
"default:permafrost",
"default:desert_stone",
"default:ice",
"default:dry_dirt",
"default:obsidian",
"default:sand",
"default:river_water_source",
"default:dirt_with_snow",
"default:dirt_with_grass",
"default:water_flowing",
"default:dirt",
"default:desert_sand",
"default:permafrost_with_moss",
"default:dirt_with_coniferous_litter",
"default:water_source",
"default:dirt_with_dry_grass",
"default:river_water_flowing",
"default:stone",
"default:snow",
"default:lava_flowing",
"default:lava_source",
"default:permafrost_with_stones",
"default:dirt_with_grass_footsteps",
"default:silver_sand",
"default:snowblock",
"default:clay",
"farming:desert_sand_soil",
"farming:desert_sand_soil_wet",
"farming:dry_soil",
"farming:dry_soil_wet",
"farming:soil",
"farming:soil_wet",
})
unified_inventory.add_category_items('lighting', {
"default:mese_post_light_junglewood",
"default:torch_ceiling",
"default:meselamp",
"default:torch",
"default:mese_post_light_acacia_wood",
"default:mese_post_light",
"default:torch_wall",
"default:mese_post_light_pine_wood",
"default:mese_post_light_aspen_wood"
})
--]]
--[[ UNCATEGORISED
"farming:string",
"beds:bed_bottom",
"beds:bed_top",
"beds:fancy_bed_bottom",
"beds:fancy_bed_top",
"boats:boat",
"bones:bones",
"bucket:bucket_lava",
"bucket:bucket_river_water",
"bucket:bucket_water",
"butterflies:butterfly_red",
"butterflies:butterfly_violet",
"butterflies:butterfly_white",
"butterflies:hidden_butterfly_red",
"butterflies:hidden_butterfly_violet",
"butterflies:hidden_butterfly_white",
"carts:brakerail",
"carts:cart",
"carts:powerrail",
"carts:rail",
"default:book",
"default:book_written",
"default:bookshelf",
"default:chest",
"default:chest_locked",
"default:chest_locked_open",
"default:chest_open",
"default:clay_lump",
"default:cloud",
"default:coral_brown",
"default:coral_cyan",
"default:coral_green",
"default:coral_orange",
"default:coral_pink",
"default:coral_skeleton",
"default:flint",
"default:furnace",
"default:furnace_active",
"default:key",
"default:ladder_steel",
"default:ladder_wood",
"default:obsidian_shard",
"default:paper",
"default:sign_wall_steel",
"default:sign_wall_wood",
"default:stick",
"fire:basic_flame",
"fire:permanent_flame",
"fireflies:firefly",
"fireflies:firefly_bottle",
"fireflies:hidden_firefly",
"ignore",
"unknown",
"tnt:boom",
"tnt:gunpowder",
"tnt:gunpowder_burning",
"tnt:tnt",
"tnt:tnt_burning",
"tnt:tnt_stick",
"vessels:drinking_glass",
"vessels:glass_bottle",
"vessels:glass_fragments",
"vessels:shelf",
"vessels:steel_bottle",
"dye:black",
"dye:blue",
"dye:brown",
"dye:cyan",
"dye:dark_green",
"dye:dark_grey",
"dye:green",
"dye:grey",
"dye:magenta",
"dye:orange",
"dye:pink",
"dye:red",
"dye:violet",
"dye:white",
"dye:yellow",
"wool:black",
"wool:blue",
"wool:brown",
"wool:cyan",
"wool:dark_green",
"wool:dark_grey",
"wool:green",
"wool:grey",
"wool:magenta",
"wool:orange",
"wool:pink",
"wool:red",
"wool:violet",
"wool:white",
"wool:yellow",
"unified_inventory:bag_large",
"unified_inventory:bag_medium",
"unified_inventory:bag_small",
--]]
--[[ LIST UNCATEGORIZED AFTER LOAD
minetest.register_on_mods_loaded(function()
minetest.after(1, function ( )
local l = {}
for name,_ in pairs(minetest.registered_items) do
if not unified_inventory.find_category(name) then
-- minetest.log("error", minetest.serialize(minetest.registered_items[name]))
table.insert(l, name)
end
end
table.sort(l)
minetest.log(table.concat(l, '",'.."\n"..'"'))
end)
end)
--]]

@ -101,3 +101,72 @@ Register a non-standard craft recipe:
-- ^ Same as `minetest.register_recipe` -- ^ Same as `minetest.register_recipe`
}) })
Categories
----------
Register a new category:
The config table (second argument) is optional, and all its members are optional
See the unified_inventory.set_category_* functions for more details on the members of the config table
unified_inventory.register_category("category_name", {
symbol = "mod_name:item_name" or "texture.png",
label = "Human Readable Label",
index = 5,
items = {
"mod_name:item_name",
"another_mod:different_item"
}
})
Add / override the symbol for a category:
The category does not need to exist first
The symbol can be an item name or a texture image
If unset this will default to "default:stick"
unified_inventory.set_category_symbol("category_name", "mod_name:item_name" or "texture.png")
Add / override the human readable label for a category:
If unset this will default to the category name
unified_inventory.set_category_label("category_name", "Human Readable Label")
Add / override the sorting index of the category:
Must be a number, can also be negative (-5) or fractional (2.345)
This determines the position the category appears in the list of categories
The "all" meta-category has index -2, the "misc"/"uncategorized" meta-category has index -1, use a negative number smaller than these to make a category appear before these in the list
By default categories are sorted alphabetically with an index between 0.0101(AA) and 0.2626(ZZ)
unified_inventory.set_category_index("category_name", 5)
Add a single item to a category:
unified_inventory.add_category_item("category_name", "mod_name:item_name")
Add multiple items to a category:
unified_inventory.add_category_items("category_name", {
"mod_name:item_name",
"another_mod:different_item"
})
Remove an item from a category:
unified_inventory.remove_category_item("category_name", "mod_name:item_name")
Remove a category entirely:
unified_inventory.remove_category("category_name")
Finding existing items in categories:
This will find the first category an item exists in
It should be used for checking if an item is catgorised
Returns "category_name" or nil
unified_inventory.find_category("mod_name:item_name")
This will find all the categories an item exists in
Returns a number indexed table (list) of category names
unified_inventory.find_categories("mod_name:item_name")

@ -10,6 +10,8 @@ unified_inventory = {
alternate = {}, alternate = {},
current_page = {}, current_page = {},
current_searchbox = {}, current_searchbox = {},
current_category = {},
current_category_scroll = {},
current_index = {}, current_index = {},
current_item = {}, current_item = {},
current_craft_direction = {}, current_craft_direction = {},
@ -33,6 +35,9 @@ unified_inventory = {
-- "Lite" mode -- "Lite" mode
lite_mode = minetest.settings:get_bool("unified_inventory_lite"), lite_mode = minetest.settings:get_bool("unified_inventory_lite"),
-- Items automatically added to categories based on item definitions
automatic_categorization = (minetest.settings:get_bool("unified_inventory_automatic_categorization") ~= false),
-- Trash enabled -- Trash enabled
trash_enabled = (minetest.settings:get_bool("unified_inventory_trash") ~= false), trash_enabled = (minetest.settings:get_bool("unified_inventory_trash") ~= false),
imgscale = 1.25, imgscale = 1.25,
@ -52,9 +57,9 @@ ui.style_full = {
formw = 17.75, formw = 17.75,
formh = 12.25, formh = 12.25,
pagecols = 8, pagecols = 8,
pagerows = 10, pagerows = 9,
page_x = 10.75, page_x = 10.75,
page_y = 1.45, page_y = 2.30,
craft_x = 2.8, craft_x = 2.8,
craft_y = 1.15, craft_y = 1.15,
craftresult_x = 7.8, craftresult_x = 7.8,
@ -85,9 +90,9 @@ ui.style_lite = {
formw = 14, formw = 14,
formh = 9.75, formh = 9.75,
pagecols = 4, pagecols = 4,
pagerows = 6, pagerows = 5,
page_x = 10.5, page_x = 10.5,
page_y = 1.25, page_y = 2.15,
craft_x = 2.6, craft_x = 2.6,
craft_y = 0.75, craft_y = 0.75,
craftresult_x = 5.75, craftresult_x = 5.75,
@ -100,9 +105,9 @@ ui.style_lite = {
craft_guide_resultstr_y = 0.35, craft_guide_resultstr_y = 0.35,
give_btn_x = 0.15, give_btn_x = 0.15,
main_button_x = 10.5, main_button_x = 10.5,
main_button_y = 7.9, main_button_y = 8.15,
page_buttons_x = 10.5, page_buttons_x = 10.5,
page_buttons_y = 6.3, page_buttons_y = 6.15,
searchwidth = 1.6, searchwidth = 1.6,
form_header_x = 0.2, form_header_x = 0.2,
form_header_y = 0.2, form_header_y = 0.2,
@ -149,6 +154,8 @@ if sfinv then
end end
dofile(modpath.."/group.lua") dofile(modpath.."/group.lua")
dofile(modpath.."/category.lua")
dofile(modpath.."/default-categories.lua")
dofile(modpath.."/internal.lua") dofile(modpath.."/internal.lua")
dofile(modpath.."/callbacks.lua") dofile(modpath.."/callbacks.lua")
dofile(modpath.."/match_craft.lua") dofile(modpath.."/match_craft.lua")

@ -25,6 +25,20 @@ function ui.get_per_player_formspec(player_name)
return table.copy(draw_lite_mode and ui.style_lite or ui.style_full), draw_lite_mode return table.copy(draw_lite_mode and ui.style_lite or ui.style_full), draw_lite_mode
end end
local function formspec_button(ui_peruser, name, image, offset, pos, scale, label)
local element = 'image_button'
if minetest.registered_items[image] then
element = 'item_image_button'
end
local spc = (1-scale)*ui_peruser.btn_size/2
local size = ui_peruser.btn_size*scale
return string.format("%s[%f,%f;%f,%f;%s;%s;]", element,
(offset.x or offset[1]) + ( ui_peruser.btn_spc * (pos.x or pos[1]) ) + spc,
(offset.y or offset[2]) + ( ui_peruser.btn_spc * (pos.y or pos[2]) ) + spc,
size, size, image, name) ..
string.format("tooltip[%s;%s]", name, F(label or name))
end
function ui.get_formspec(player, page) function ui.get_formspec(player, page)
if not player then if not player then
@ -107,6 +121,48 @@ function ui.get_formspec(player, page)
return table.concat(formspec, "") return table.concat(formspec, "")
end end
-- Category filters
local categories_pos = { ui_peruser.page_x, ui_peruser.page_y-ui_peruser.btn_spc-0.5 }
local categories_scroll_pos = { ui_peruser.page_x, ui_peruser.form_header_y-(draw_lite_mode and 0 or 0.2) }
formspec[n] = string.format("background9[%f,%f;%f,%f;%s;false;3]",
ui_peruser.page_x-0.1, categories_scroll_pos[2],
(ui_peruser.btn_spc * ui_peruser.pagecols) + 0.13, 1.4+(draw_lite_mode and 0 or 0.2),
"ui_smallbg_9_sliced.png")
n = n + 1
formspec[n] = string.format("label[%f,%f;%s]", ui_peruser.page_x, ui_peruser.form_header_y+(draw_lite_mode and 0.3 or 0.2), "Category:")
n = n + 1
local scroll_offset = 0
local category_count = #unified_inventory.category_list
if category_count > ui_peruser.pagecols then
scroll_offset = unified_inventory.current_category_scroll[player_name]
end
for index, category in ipairs(unified_inventory.category_list) do
local column = index - scroll_offset
if column > 0 and column <= ui_peruser.pagecols then
local scale = 0.8
if unified_inventory.current_category[player_name] == category.name then
scale = 1
end
formspec[n] = formspec_button(ui_peruser, "category_"..category.name, category.symbol, categories_pos, {column-1, 0}, scale, category.label)
n = n + 1
end
end
if category_count > ui_peruser.pagecols and scroll_offset > 0 then
-- prev
formspec[n] = formspec_button(ui_peruser, "prev_category", "ui_left_icon.png", categories_scroll_pos, {ui_peruser.pagecols - 2, 0}, 0.8, S("Scroll categories left"))
n = n + 1
end
if category_count > ui_peruser.pagecols and category_count - scroll_offset > ui_peruser.pagecols then
-- next
formspec[n] = formspec_button(ui_peruser, "next_category", "ui_right_icon.png", categories_scroll_pos, {ui_peruser.pagecols - 1, 0}, 0.8, S("Scroll categories right"))
n = n + 1
end
-- Search box -- Search box
formspec[n] = "field_close_on_enter[searchbox;false]" formspec[n] = "field_close_on_enter[searchbox;false]"
@ -205,16 +261,16 @@ function ui.get_formspec(player, page)
end end
end end
formspec[n] = string.format("label[%f,%f;%s: %s]", formspec[n] = string.format("label[%f,%f;%s: %s]",
ui_peruser.page_x, ui_peruser.form_header_y, ui_peruser.page_buttons_x + ui_peruser.btn_spc * (draw_lite_mode and 1 or 2),
ui_peruser.page_buttons_y + 0.1 + ui_peruser.btn_spc * 2,
F(S("Page")), S("@1 of @2",page2,pagemax)) F(S("Page")), S("@1 of @2",page2,pagemax))
end end
n= n+1 n= n+1
if ui.activefilter[player_name] ~= "" then if ui.activefilter[player_name] ~= "" then
formspec[n] = string.format("label[%f,%f;%s:]", formspec[n] = string.format("label[%f,%f;%s: %s]",
ui_peruser.page_x, ui_peruser.page_y - 0.65, F(S("Filter"))) ui_peruser.page_x, ui_peruser.page_y - 0.25,
formspec[n+1] = string.format("label[%f,%f;%s]", F(S("Filter")), F(ui.activefilter[player_name]))
ui_peruser.page_x, ui_peruser.page_y - 0.25, F(ui.activefilter[player_name]))
end end
return table.concat(formspec, "") return table.concat(formspec, "")
end end
@ -225,6 +281,13 @@ function ui.set_inventory_formspec(player, page)
end end
end end
local function valid_def(def)
return (not def.groups.not_in_creative_inventory
or def.groups.not_in_creative_inventory == 0)
and def.description
and def.description ~= ""
end
--apply filter to the inventory list (create filtered copy of full one) --apply filter to the inventory list (create filtered copy of full one)
function ui.apply_filter(player, filter, search_dir) function ui.apply_filter(player, filter, search_dir)
if not player then if not player then
@ -256,15 +319,32 @@ function ui.apply_filter(player, filter, search_dir)
end end
end end
ui.filtered_items_list[player_name]={} ui.filtered_items_list[player_name]={}
local category = ui.current_category[player_name] or 'all'
if category == 'all' then
for name, def in pairs(minetest.registered_items) do for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory if valid_def(def)
or def.groups.not_in_creative_inventory == 0)
and def.description
and def.description ~= ""
and ffilter(name, def) then and ffilter(name, def) then
table.insert(ui.filtered_items_list[player_name], name) table.insert(ui.filtered_items_list[player_name], name)
end end
end end
elseif category == 'uncategorized' then
for name, def in pairs(minetest.registered_items) do
if (not ui.find_category(name))
and valid_def(def)
and ffilter(name, def) then
table.insert(ui.filtered_items_list[player_name], name)
end
end
else
for name,exists in pairs(ui.registered_category_items[category]) do
local def = minetest.registered_items[name]
if exists and def
and valid_def(def)
and ffilter(name, def) then
table.insert(ui.filtered_items_list[player_name], name)
end
end
end
table.sort(ui.filtered_items_list[player_name]) table.sort(ui.filtered_items_list[player_name])
ui.filtered_items_list_size[player_name] = #ui.filtered_items_list[player_name] ui.filtered_items_list_size[player_name] = #ui.filtered_items_list[player_name]
ui.current_index[player_name] = 1 ui.current_index[player_name] = 1

@ -9,3 +9,6 @@ unified_inventory_bags (Enable bags) bool true
#If enabled, the trash slot can be used by those without both creative #If enabled, the trash slot can be used by those without both creative
#and the give privilege. #and the give privilege.
unified_inventory_trash (Enable trash) bool true unified_inventory_trash (Enable trash) bool true
unified_inventory_automatic_categorization (Items automatically added to categories) bool true

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B