ad396d3f01
Boots to a launcher that lists /apps/<name>/main.lua on the SD card and runs the selected app in a vendored Lua 5.4 with gui, input, fs, sys and log bindings. Settings persist as a Lua table in /settings.lua, covering touch calibration and screen rotation, with a settings app to edit both. Rotation is applied after mapping raw touch into the panel's rotation-0 frame, so turning the UI never invalidates a calibration.
106 lines
2.8 KiB
Lua
106 lines
2.8 KiB
Lua
TICK_MS = 50
|
|
|
|
local INSET = 30
|
|
local BLACK, WHITE, RED = gui.color(0, 0, 0), gui.color(255, 255, 255), gui.color(255, 0, 0)
|
|
local ROWS = {"calibrate touch", "rotation", "exit"}
|
|
|
|
local mode = "menu"
|
|
local samples = {}
|
|
local pending = nil
|
|
local armed = false
|
|
local message = nil
|
|
|
|
local function rowY(index)
|
|
return 40 * index
|
|
end
|
|
|
|
local function drawMenu()
|
|
gui.clear(WHITE)
|
|
gui.drawText("settings", 10, 10, BLACK)
|
|
for i, label in ipairs(ROWS) do
|
|
if label == "rotation" then
|
|
label = "rotation: " .. sys.getRotation() .. " deg"
|
|
end
|
|
gui.drawRect(10, rowY(i), gui.width() - 20, 28, BLACK)
|
|
gui.drawText(label, 18, rowY(i) + 6, BLACK)
|
|
end
|
|
if message then gui.drawText(message, 10, rowY(#ROWS + 1) + 10, BLACK) end
|
|
end
|
|
|
|
local function target(n)
|
|
-- Calibration always runs in the rotation-0 frame, so use panel geometry.
|
|
if n == 1 then return INSET, INSET end
|
|
return 320 - INSET, 480 - INSET
|
|
end
|
|
|
|
local function drawTarget(n)
|
|
local x, y = target(n)
|
|
gui.clear(WHITE)
|
|
gui.drawText("tap the cross", 10, 10, BLACK)
|
|
gui.drawLine(x - 12, y, x + 12, y, RED)
|
|
gui.drawLine(x, y - 12, x, y + 12, RED)
|
|
end
|
|
|
|
-- Two inset targets give a raw-per-pixel slope; extrapolate it to the screen edges.
|
|
-- Exposed as a global so test/settings_calibration.lua can exercise it.
|
|
function computeCalibration(s1, s2, w, h, inset)
|
|
local sx = (s2.x - s1.x) / (w - 2 * inset)
|
|
local sy = (s2.y - s1.y) / (h - 2 * inset)
|
|
return math.floor(s1.x - sx * inset), math.floor(s1.y - sy * inset),
|
|
math.floor(s2.x + sx * inset), math.floor(s2.y + sy * inset)
|
|
end
|
|
|
|
local function finish()
|
|
local ok = sys.setCalibration(computeCalibration(samples[1], samples[2], 320, 480, INSET))
|
|
message = ok and "calibration saved" or "save failed"
|
|
mode = "menu"
|
|
gui.setRotation(sys.getRotation() / 90)
|
|
drawMenu()
|
|
end
|
|
|
|
function setup()
|
|
drawMenu()
|
|
end
|
|
|
|
function on_touch(x, y)
|
|
if mode ~= "menu" then return end
|
|
local index = math.floor(y / 40)
|
|
if y < rowY(1) or index > #ROWS then return end
|
|
|
|
if ROWS[index] == "calibrate touch" then
|
|
message = nil
|
|
mode = "calibrate"
|
|
samples = {}
|
|
pending = nil
|
|
armed = false -- the menu tap is still down; wait for release
|
|
gui.setRotation(0)
|
|
drawTarget(1)
|
|
elseif ROWS[index] == "rotation" then
|
|
local ok = sys.setRotation((sys.getRotation() + 90) % 360)
|
|
message = ok and "rotation saved" or "save failed"
|
|
drawMenu()
|
|
elseif ROWS[index] == "exit" then
|
|
sys.exit()
|
|
end
|
|
end
|
|
|
|
function on_tick()
|
|
if mode ~= "calibrate" then return end
|
|
local rx, ry = input.getRawTouch()
|
|
if not armed then
|
|
if not rx then armed = true end
|
|
return
|
|
end
|
|
if rx then
|
|
pending = {x = rx, y = ry}
|
|
elseif pending then
|
|
samples[#samples + 1] = pending
|
|
pending = nil
|
|
if #samples == 1 then
|
|
drawTarget(2)
|
|
else
|
|
finish()
|
|
end
|
|
end
|
|
end
|