local ui = require("ui") local PAD, GAP = 12, 8 local CARD_SIZE = 1 -- one scale across every card, regardless of label length local screen local function card(name, side) return ui.button{ w = side, h = side, justify = "center", on_press = function() sys.launch("/apps/" .. name .. "/main.lua") end, ui.label(name, {size = CARD_SIZE, fit = side - 16}), } end function init() local names = {} for _, name in ipairs(fs.listDirs("/apps")) do if name ~= "Home" then names[#names + 1] = name end end table.sort(names) local side, cols = ui.cardSide(math.max(#names, 1), PAD, GAP) -- Rows are filled before ui.box() sees them: the constructor moves a spec's array part -- into its children, so anything appended afterwards is never laid out. local rows = {} for _, name in ipairs(names) do local row = rows[#rows] if not row or #row >= cols then row = {} rows[#rows + 1] = row end row[#row + 1] = card(name, side) end -- Centred left to right as a unit, still top aligned: the gaps inside the grid are -- fixed, so the leftover width belongs beside the block, not to its last column. local items = {pad = PAD, gap = GAP, w = "fill", align = "center"} local gridW = cols * side + (cols - 1) * GAP for _, row in ipairs(rows) do row.row, row.gap, row.w = true, GAP, gridW items[#items + 1] = ui.box(row) end if #rows == 0 then items[#items + 1] = ui.text("no apps in /apps", {color = ui.theme.muted}) end screen = ui.screen(ui.box(items)) log.info("home ready") end function draw() screen:draw() end function on_touch_down(x, y) screen:down(x, y) end function on_touch_up(x, y) screen:up(x, y) end