2cdb7b3702
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.
108 lines
3.5 KiB
Lua
108 lines
3.5 KiB
Lua
-- Stand-in for the firmware bindings, so host tests exercise the real ui.lua.
|
|
--
|
|
-- One definition of the binding surface: when a binding is added or renamed, this is
|
|
-- the file that changes. Tests mutate the returned table to steer the device, and may
|
|
-- overwrite any stub function outright for a single assertion.
|
|
|
|
local device = {
|
|
-- Text metrics chosen to match the firmware's default GLCD font, since layout
|
|
-- assertions are written in real pixels.
|
|
fontHeight = 8,
|
|
charWidth = 6,
|
|
now = 0,
|
|
rotation = 0,
|
|
theme = "light",
|
|
clockSynced = false,
|
|
timezone = "UTC0",
|
|
raw = nil, -- pending raw touch reading, {x, y} or nil
|
|
networks = {}, -- what wifi.scan() returns
|
|
status = {state = "disconnected", ssid = "", ip = "", rssi = 0},
|
|
painted = {}, -- every drawText call, in order
|
|
calibration = nil, -- last sys.setCalibration()
|
|
connected = nil, -- last wifi.connect()
|
|
exited = false,
|
|
launched = nil,
|
|
saveFails = false, -- make every persisting call report failure
|
|
}
|
|
|
|
local function saved()
|
|
return not device.saveFails
|
|
end
|
|
|
|
function device.install()
|
|
device.painted = {}
|
|
|
|
gui = {
|
|
color = function(r, g, b) return r * 65536 + g * 256 + b end,
|
|
-- Rotation swaps the frame, exactly as TFT_eSPI reports it.
|
|
width = function() return device.rotation % 180 == 0 and 320 or 480 end,
|
|
height = function() return device.rotation % 180 == 0 and 480 or 320 end,
|
|
clear = function() end,
|
|
fillRect = function() end,
|
|
drawRect = function() end,
|
|
fillCircle = function() end,
|
|
drawLine = function() end,
|
|
roundRect = function() end,
|
|
drawText = function(label, x, y)
|
|
device.painted[#device.painted + 1] = {label = label, x = x, y = y}
|
|
end,
|
|
fontHeight = function() return device.fontHeight end,
|
|
textWidth = function(text) return #text * device.charWidth end,
|
|
setRotation = function() end,
|
|
}
|
|
|
|
sys = {
|
|
millis = function() return device.now end,
|
|
exit = function() device.exited = true end,
|
|
launch = function(path) device.launched = path end,
|
|
getRotation = function() return device.rotation end,
|
|
setRotation = function(degrees)
|
|
if degrees % 90 ~= 0 or degrees < 0 or degrees > 270 then return false end
|
|
device.rotation = degrees
|
|
return saved()
|
|
end,
|
|
getTheme = function() return device.theme end,
|
|
setTheme = function(name) device.theme = name return saved() end,
|
|
setCalibration = function(...) device.calibration = {...} return saved() end,
|
|
clockSynced = function() return device.clockSynced end,
|
|
getTimezone = function() return device.timezone end,
|
|
setTimezone = function(tz) device.timezone = tz return saved() end,
|
|
}
|
|
|
|
input = {
|
|
touched = function() return device.raw ~= nil end,
|
|
getTouch = function()
|
|
if not device.raw then return nil end
|
|
return device.raw[1], device.raw[2]
|
|
end,
|
|
getRawTouch = function()
|
|
if not device.raw then return nil end
|
|
return device.raw[1], device.raw[2]
|
|
end,
|
|
}
|
|
|
|
fs = {
|
|
readFile = function() return nil end,
|
|
writeFile = function() return saved() end,
|
|
exists = function() return false end,
|
|
listFiles = function() return {} end,
|
|
listDirs = function() return {} end,
|
|
}
|
|
|
|
wifi = {
|
|
scan = function() return device.networks end,
|
|
status = function() return device.status end,
|
|
connect = function(ssid, password)
|
|
device.connected = {ssid, password}
|
|
return saved()
|
|
end,
|
|
forget = function() device.connected = nil return saved() end,
|
|
}
|
|
|
|
log = {info = function() end}
|
|
|
|
return device
|
|
end
|
|
|
|
return device
|