Files
slate32/test/settings_calibration.lua
T
evan 4e5796fd51 feat(ui): layout toolkit, Lua launcher and touch press events
Apps describe nesting instead of coordinates: /lib/ui.lua borrows CSS block flow,
the box model and auto sizing, and owns hit testing, press capture and the pressed
repaint. The runtime gains require backed by the SD card, on_touch_down/on_touch_up,
text metrics and rounded gradient fills, so the launcher becomes an ordinary Lua app
and the firmware keeps only a fallback screen for an unreadable card.
2026-07-31 22:27:34 -04:00

87 lines
2.9 KiB
Lua

-- Run: lua test/settings_calibration.lua
-- Stubs the firmware bindings so the settings app loads on a desktop Lua.
package.path = "sdcard/lib/?.lua;" .. package.path
local saved
local rotation = 0
local now = 0
gui = {
color = function() return 0 end,
width = function() return rotation % 180 == 0 and 320 or 480 end,
height = function() return rotation % 180 == 0 and 480 or 320 end,
clear = function() end,
fillRect = function() end,
drawText = function() end,
drawRect = function() end,
drawLine = function() end,
fillRoundRect = function() end,
drawRoundRect = function() end,
fontHeight = function() return 8 end,
textWidth = function(text) return #text * 6 end,
setRotation = function() end,
}
sys = {
millis = function() return now end,
exit = function() end,
setCalibration = function(...) saved = {...} return true end,
getRotation = function() return rotation end,
setRotation = function(degrees) rotation = degrees return true end,
}
input = {getRawTouch = function() return nil end}
log = {info = function() end}
dofile("sdcard/apps/settings/main.lua")
-- Menu rows: pad 12, gap 8, title 8 tall, buttons 24 tall.
local ROTATION_ROW = {x = 100, y = 70}
local CALIBRATE_ROW = {x = 100, y = 38}
local function tap(point)
on_touch_down(point.x, point.y)
on_touch_up(point.x, point.y)
end
-- A perfectly linear panel spanning raw 200..3800 over 320x480 must round-trip
-- to those same extremes from the two inset samples.
local inset, w, h = 30, 320, 480
local function raw(pixel, size) return 200 + (3800 - 200) * pixel / size end
local s1 = {x = raw(inset, w), y = raw(inset, h)}
local s2 = {x = raw(w - inset, w), y = raw(h - inset, h)}
local x0, y0, x1, y1 = computeCalibration(s1, s2, w, h, inset)
assert(math.abs(x0 - 200) <= 1, "x0 " .. x0)
assert(math.abs(y0 - 200) <= 1, "y0 " .. y0)
assert(math.abs(x1 - 3800) <= 1, "x1 " .. x1)
assert(math.abs(y1 - 3800) <= 1, "y1 " .. y1)
-- A flipped panel (raw decreasing with pixel) must yield a descending range.
local s3 = {x = 3800 - raw(inset, w) + 200, y = s1.y}
local s4 = {x = 3800 - raw(w - inset, w) + 200, y = s2.y}
local fx0, _, fx1 = computeCalibration(s3, s4, w, h, inset)
assert(fx0 > fx1, "flipped axis should descend")
-- Rotation cycles through the four quarter turns and wraps back to 0.
setup()
for _, expected in ipairs({90, 180, 270, 0}) do
tap(ROTATION_ROW)
assert(sys.getRotation() == expected, "rotation " .. sys.getRotation())
end
-- Calibration collects one sample per target and saves on the second release.
setup()
tap(CALIBRATE_ROW)
on_tick() -- release after the menu tap arms sampling
input.getRawTouch = function() return s1.x, s1.y end
on_tick()
input.getRawTouch = function() return nil end
on_tick()
input.getRawTouch = function() return s2.x, s2.y end
on_tick()
input.getRawTouch = function() return nil end
on_tick()
assert(saved, "calibration was not saved")
assert(math.abs(saved[1] - 200) <= 1, "saved x0 " .. saved[1])
print("ok")