393ce3c0ed
lua_app.cpp had grown to 701 lines holding every binding, the module loader and the app lifecycle, so new bindings landed wherever the cursor was. Each Lua table now has its own file under bindings/, and the app is recovered from the lua_State's extra space instead of a file-static, so a second state cannot reach the wrong app. Three tests each redeclared the binding surface, which broke twice this session when a binding changed; test/fake_device.lua is now the single stub. `make test` runs all four suites and pins Lua 5.4, matching the vendored interpreter rather than the 5.2 the tests had silently been using.
77 lines
3.1 KiB
Lua
77 lines
3.1 KiB
Lua
-- Run: lua test/ui_layout.lua
|
|
-- Asserts the rects ui.lua computes, against the shared fake device.
|
|
package.path = "sdcard/lib/?.lua;test/?.lua;" .. package.path
|
|
|
|
local device = require("fake_device").install()
|
|
local ui = require("ui")
|
|
|
|
local function rect(node)
|
|
return string.format("%d,%d %dx%d", node.rect.x, node.rect.y, node.rect.w, node.rect.h)
|
|
end
|
|
|
|
-- Vertical flow: children fill the content width, stack by their own height plus gap.
|
|
local title = ui.text("settings")
|
|
local first = ui.button{label = "one", on_press = function() end}
|
|
local second = ui.button{label = "two", on_press = function() end}
|
|
local screen = ui.screen(ui.box{pad = 12, gap = 8, title, first, second})
|
|
|
|
assert(rect(title) == "12,12 296x8", rect(title))
|
|
-- Button height is text plus its own padding: 8 + 8 + 8 = 24.
|
|
assert(rect(first) == "12,28 296x24", rect(first))
|
|
assert(rect(second) == "12,60 296x24", rect(second))
|
|
|
|
-- Fractions resolve against the parent content box, absolutes stay absolute.
|
|
local half = ui.box{w = 0.5, h = 40}
|
|
local fixed = ui.box{w = 100, h = 40}
|
|
ui.screen(ui.box{pad = 10, half, fixed})
|
|
assert(rect(half) == "10,10 150x40", rect(half))
|
|
assert(rect(fixed) == "10,50 100x40", rect(fixed))
|
|
|
|
-- Horizontal flow with centre alignment on the cross axis of a fixed-height row.
|
|
local tall = ui.box{w = 40, h = 40}
|
|
local short = ui.box{w = 40, h = 10}
|
|
local row = ui.box{row = true, gap = 6, align = "center", h = 40, tall, short}
|
|
ui.screen(ui.box{row})
|
|
assert(rect(tall) == "0,0 40x40", rect(tall))
|
|
assert(rect(short) == "46,15 40x10", rect(short))
|
|
|
|
-- The root always fills the screen, so alignment there spans the whole panel.
|
|
local lone = ui.box{w = 40, h = 40}
|
|
ui.screen(ui.box{align = "center", lone})
|
|
assert(rect(lone) == "140,0 40x40", rect(lone))
|
|
|
|
-- A fraction inside an auto-sized parent is a build-time error, not a silent zero.
|
|
local ok = pcall(function()
|
|
ui.screen(ui.box{ui.box{h = "auto", ui.box{w = 20, h = 0.5}}})
|
|
end)
|
|
assert(not ok, "fraction inside an auto parent must fail loudly")
|
|
|
|
-- Hit testing: deepest interactive component wins over its tappable ancestor.
|
|
local inner = ui.button{label = "inner", on_press = function() end}
|
|
local outer = ui.box{pad = 20, on_press = function() end, inner}
|
|
local nested = ui.screen(outer)
|
|
assert(outer:hit(160, 30) == inner, "inner button should win inside its rect")
|
|
assert(outer:hit(2, 2) == outer, "the container claims its own padding")
|
|
assert(outer:hit(-50, -50) == nil, "outside the tree is a miss")
|
|
|
|
-- Capture: press then release outside cancels; release inside fires once.
|
|
local fired = 0
|
|
local button = ui.button{label = "go", on_press = function() fired = fired + 1 end}
|
|
local app = ui.screen(ui.box{pad = 10, button})
|
|
app:down(100, 20)
|
|
assert(button.pressed, "press must show immediately")
|
|
app:up(300, 470)
|
|
assert(fired == 0, "release outside must cancel")
|
|
|
|
app:down(100, 20)
|
|
app:up(100, 20)
|
|
assert(fired == 1, "release inside must fire once")
|
|
|
|
-- The pressed look is held briefly, then cleared on a later draw.
|
|
assert(button.pressed, "pressed look must outlast the release")
|
|
device.now = device.now + 100
|
|
app:draw()
|
|
assert(not button.pressed, "pressed look must clear after the hold")
|
|
|
|
print("ok")
|