Files
slate32/test/fake_device.lua
T
evan 2cdb7b3702 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.
2026-08-01 17:03:55 -04:00

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