Files

217 lines
6.8 KiB
Lua

-- lib/ui.lua — Shared UI helpers for manager & client
-- Usage: local ui = dofile("lib/ui.lua")
--
-- Set ui.draw to the current render target (window/monitor)
-- before calling any drawing functions.
local ui = {}
-------------------------------------------------
-- Drawing target — set this before drawing
-------------------------------------------------
ui.draw = nil
-------------------------------------------------
-- Drawing primitives
-------------------------------------------------
function ui.monWrite(x, y, text, fg, bg)
ui.draw.setCursorPos(x, y)
if fg then ui.draw.setTextColor(fg) end
if bg then ui.draw.setBackgroundColor(bg) end
ui.draw.write(text)
end
function ui.monFill(y, color)
local w, _ = ui.draw.getSize()
ui.draw.setCursorPos(1, y)
ui.draw.setBackgroundColor(color)
ui.draw.write(string.rep(" ", w))
end
function ui.monCenter(y, text, fg, bg)
local w, _ = ui.draw.getSize()
local x = math.floor((w - #text) / 2) + 1
ui.monWrite(x, y, text, fg, bg)
end
function ui.monBar(x, y, width, ratio, barColor, bgColor)
local filled = math.floor(ratio * width)
ui.draw.setCursorPos(x, y)
ui.draw.setBackgroundColor(barColor)
ui.draw.write(string.rep(" ", filled))
ui.draw.setBackgroundColor(bgColor)
ui.draw.write(string.rep(" ", width - filled))
end
function ui.drawButton(x, y, text, fg, bg, padLeft, padRight)
padLeft = padLeft or 1
padRight = padRight or 1
local full = string.rep(" ", padLeft) .. text .. string.rep(" ", padRight)
ui.monWrite(x, y, full, fg, bg)
return x, y, x + #full - 1, y
end
-------------------------------------------------
-- Touch zone management
-------------------------------------------------
--- Append a clickable zone to a pending-zone list.
-- @param zones table — the pending zone array to append to
function ui.addZone(zones, x1, y1, x2, y2, action, data)
table.insert(zones, {
x1 = x1, y1 = y1, x2 = x2, y2 = y2,
action = action, data = data,
})
end
--- Find which zone was hit.
-- @param zones table — the active zone array to search
function ui.hitTest(zones, x, y)
for _, zone in ipairs(zones) do
if x >= zone.x1 and x <= zone.x2 and y >= zone.y1 and y <= zone.y2 then
return zone.action, zone.data
end
end
return nil, nil
end
-------------------------------------------------
-- Monitor setup
-------------------------------------------------
--- Wrap and configure the main inventory monitor.
-- @param side string — preferred peripheral side/name
-- @param excludeSide string — side to skip (e.g. smelter monitor)
-- @return mon, monName or nil, nil
function ui.setupMonitor(side, excludeSide)
local mon = peripheral.wrap(side)
local monName
if mon and mon.setTextScale then
monName = side
else
mon = nil
end
if not mon then
for _, name in ipairs(peripheral.getNames()) do
if peripheral.getType(name) == "monitor" and name ~= excludeSide then
mon = peripheral.wrap(name)
monName = name
break
end
end
end
if not mon then return nil, nil end
mon.setTextScale(0.5)
mon.clear()
return mon, monName
end
--- Wrap and configure the smelter monitor.
-- @param side string — preferred peripheral side/name
-- @param excludeName string — main monitor name to skip
-- @return smelterMon, smelterMonName or nil, nil
function ui.setupSmelterMonitor(side, excludeName)
local smelterMon = peripheral.wrap(side)
local smelterMonName
if smelterMon and smelterMon.setTextScale then
smelterMonName = side
else
smelterMon = nil
end
if not smelterMon then
for _, name in ipairs(peripheral.getNames()) do
if peripheral.getType(name) == "monitor" and name ~= excludeName then
smelterMon = peripheral.wrap(name)
smelterMonName = name
break
end
end
end
if not smelterMon then return nil, nil end
smelterMon.setTextScale(0.5)
smelterMon.clear()
return smelterMon, smelterMonName
end
-------------------------------------------------
-- Item filtering
-------------------------------------------------
--- Filter an item list by search query.
-- @param itemList table — array of { name, total }
-- @param searchQuery string — filter text (case-insensitive, plain match)
-- @return filtered table — matching subset
function ui.getFilteredItems(itemList, searchQuery)
local filtered = {}
for _, item in ipairs(itemList) do
if searchQuery == "" then
table.insert(filtered, item)
else
local lower = item.name:lower():gsub("minecraft:", ""):gsub("_", " ")
if lower:find(searchQuery:lower(), 1, true) then
table.insert(filtered, item)
end
end
end
return filtered
end
-------------------------------------------------
-- Crafting recipe helpers
-------------------------------------------------
--- Count ingredients needed for one craft.
function ui.getRecipeIngredients(recipe)
local ingredients = {}
for _, item in ipairs(recipe.grid) do
if item then
ingredients[item] = (ingredients[item] or 0) + 1
end
end
return ingredients
end
--- Check if a recipe can be crafted with current stock.
-- @param recipe table — recipe with .grid
-- @param getTotal function(itemName) -> number — returns stock count
function ui.canCraftRecipe(recipe, getTotal)
local ingredients = ui.getRecipeIngredients(recipe)
for itemName, needed in pairs(ingredients) do
if (getTotal(itemName) or 0) < needed then return false end
end
return true
end
--- How many batches can be crafted.
-- @param recipe table — recipe with .grid
-- @param getTotal function(itemName) -> number
function ui.maxCraftBatches(recipe, getTotal)
local ingredients = ui.getRecipeIngredients(recipe)
local minBatches = math.huge
for itemName, needed in pairs(ingredients) do
local batches = math.floor((getTotal(itemName) or 0) / needed)
if batches < minBatches then minBatches = batches end
end
if minBatches == math.huge then return 0 end
return minBatches
end
--- Get list of ingredients where stock < needed.
-- @param recipe table — recipe with .grid
-- @param getTotal function(itemName) -> number
function ui.getMissingIngredients(recipe, getTotal)
local ingredients = ui.getRecipeIngredients(recipe)
local missing = {}
for itemName, needed in pairs(ingredients) do
local have = getTotal(itemName) or 0
if have < needed then
table.insert(missing, { name = itemName, have = have, need = needed })
end
end
return missing
end
return ui