Files
slate32/sdcard/.lua/apps/Paint/main.lua
T
evan 97abf037b8 refactor(lua)!: camelCase handlers, and type the app tables
Follows the submodule: on_touch_down and friends become onTouchDown, the last
snake_case left in the surface now that handlers are table fields rather than
globals.

main.lua declares SlateApp, this card's contract with its apps, and every app
composes what it fills -- PaintApp is SlateApp plus TouchHandlers, Home is
SlateApp alone -- which is also the only static record of the features an app
needs.
2026-08-05 10:42:06 -04:00

74 lines
1.8 KiB
Lua

local ui = require "ui"
-- One node for the whole canvas: every pixel is content, so the app takes the touch
-- callbacks raw rather than asking the tree what was hit. It wants the firmware's noise
-- threshold and no gesture slop -- a three pixel stroke is a stroke, not a mis-tap.
local BRUSH = 2
---@class PaintApp : SlateApp, TouchHandlers
local M = {}
local canvas, area
local lastX, lastY
local function inside(x, y)
return area and x >= area.x and x < area.x + area.w and y >= area.y and y < area.y + area.h
end
function M.init()
log.info "paint ready"
end
function M.node()
-- The painter runs on every repaint, and a repaint is what clearing means here: the
-- tree fills the box with the background before calling it, so this only has to
-- remember where the box landed.
canvas = ui.custom {
w = "fill",
h = "fill",
paint = function(_, x, y, w, h)
area = { x = x, y = y, w = w, h = h }
end,
}
return ui.box {
w = "fill",
h = "fill",
ui.box {
row = true,
pad = 8,
ui.button {
label = "clear",
on_click = function()
lastX = nil
ui.invalidate(canvas)
end,
},
},
canvas,
}
end
function M.onTouchDown(x, y)
if not inside(x, y) then
return
end
lastX, lastY = x, y
screen.fillCircle(x, y, BRUSH, ui.theme.accent)
end
-- Strokes are joined with a line because the poll rate, not the finger, decides the gap:
-- a fast swipe reports points tens of pixels apart and dots alone would look dotted.
function M.onTouchMove(x, y)
if not lastX or not inside(x, y) then
return
end
screen.drawLine(lastX, lastY, x, y, ui.theme.accent)
screen.fillCircle(x, y, BRUSH, ui.theme.accent)
lastX, lastY = x, y
end
function M.onTouchUp()
lastX = nil
end
return M