feat: timezone setting and main-axis justify in the ui toolkit

The launcher clock read UTC and sat next to the title because the toolkit could only
stack children from the start of an axis. justify adds the CSS main-axis modes that
had a caller -- start, end, center, between -- so a header keeps its title left and
its clock right without any app doing arithmetic.

Timezones are stored as POSIX TZ rules rather than offsets, so newlib applies DST
changeovers and os.date() in Lua reports local time with no binding of its own.
/lib/timezones.lua is only the picker list: a zone missing from it still works if its
rule is written into settings, the same split themes already use.

settings_calibration.lua now finds rows by label. Adding the timezone row shifted
every hardcoded y coordinate in it, which is the failure that had been predicted and
would have silently retargeted taps at the wrong control.
This commit is contained in:
2026-08-01 17:03:55 -04:00
parent 2b0355a148
commit 2cdb7b3702
12 changed files with 165 additions and 18 deletions
+20
View File
@@ -35,6 +35,26 @@ ui.screen(ui.box{row})
assert(rect(tall) == "0,0 40x40", rect(tall))
assert(rect(short) == "46,15 40x10", rect(short))
-- justify distributes the main axis: "between" pushes the last child to the far edge,
-- which is how a header keeps a title left and a clock right without arithmetic.
local left = ui.box{w = 40, h = 10}
local right = ui.box{w = 60, h = 10}
ui.screen(ui.box{pad = 10, ui.box{row = true, justify = "between", left, right}})
assert(rect(left) == "10,10 40x10", rect(left))
assert(rect(right) == "250,10 60x10", rect(right))
-- The other modes shift the whole run rather than spreading it.
local a = ui.box{w = 40, h = 10}
local b = ui.box{w = 60, h = 10}
ui.screen(ui.box{ui.box{row = true, gap = 10, justify = "end", a, b}})
assert(rect(a) == "210,0 40x10", rect(a))
assert(rect(b) == "260,0 60x10", rect(b))
-- One child cannot be spread against anything, so "between" degrades to "start".
local only = ui.box{w = 40, h = 10}
ui.screen(ui.box{ui.box{row = true, justify = "between", only}})
assert(rect(only) == "0,0 40x10", rect(only))
-- 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})