Commit Graph

22 Commits

Author SHA1 Message Date
evan b9f7c9347c refactor(api)!: declare callbacks as classes an app composes
The runtime has always called fields on the table main.lua returns, but
@lua-global declared them as loose functions, so the stubs type-checked
something that does not exist and read as "define a global".

Callbacks are now @lua-app blocks that generate a class: App for the core
contract, TouchHandlers and ButtonHandlers beside the namespaces they belong
to. An app composes what it implements:

  ---@class PaintApp : App, TouchHandlers

Names follow the rest of the surface: onTouchDown rather than on_touch_down,
with the field names the runtime looks up renamed to match. @lua-field carries
the plain fields (home, data) that were prose in a preamble before.
2026-08-05 10:42:01 -04:00
evan 75b3a2c490 refactor(api)!: one namespace per feature, screen split out
Namespaces were shared across features: `settings` was written by core, the
panel and touch, and `input` by touch and buttons. That made "does this
firmware implement the whole feature?" a question no pointer could answer.

Each namespace now belongs to exactly one feature or to core, so a feature is
a provider pointer and the compiler validates completeness:

  gui, node       -> screen, tree, under the screen feature
  settings        -> screen (rotation, theme), sys (timezone),
                     touch (calibration)
  input           -> touch, buttons

Runtime::open() no longer requires a GuiProvider; a firmware without one runs
with no screen/tree globals and reports sys.hasFeature("screen") false.
Rotation is one value again: GuiProvider::setRotation applies and persists, so
an app rotating the panel transiently puts the old value back itself.
2026-08-05 10:26:38 -04:00
evan 445a9b2b8f fix(ui): collect after a rebuild so the heap is in a known state
A build allocates a spec table per node and drops them all at once, so an
app that scans WiFi right after a screen change met whatever the incremental
GC had got around to. Costs a few ms on a screen change; recovers ~24 KB.
2026-08-04 21:30:25 -04:00
evan 4b89b27947 feat(ui): size a grid to the app's box, not the panel
Chrome takes the top of the panel before an app builds anything, and layout
has not run yet when it does, so ui.frame() reports what the mount left it.
2026-08-04 21:15:21 -04:00
evan 25b576a3d9 refactor(gui): drop setFullscreen now that chrome is a Lua node
Fullscreen was the firmware surrendering a strip it clipped apps out of.
The strip is a sibling node now, so an app that wants the panel is chrome
choosing not to build itself.
2026-08-04 20:58:56 -04:00
evan 2fc3abc487 feat(sys): expose canGoBack for the chrome that offers the control 2026-08-04 20:55:16 -04:00
evan 3f26c4ff10 feat(ui): one mounted tree instead of a screen object per build
Chrome and the app now share a tree, so a screen is no longer something an
app constructs and holds: ui.mount() takes the function that builds the
whole thing and ui.rebuild() runs it again. Building a node after layout
is refused rather than silently resetting the arena under the panel.
2026-08-04 20:53:15 -04:00
evan e3153f57c5 feat(runtime): hand the whole app contract to /.lua/main.lua
The firmware knew four paths and called four globals, so the card could
not change its own layout or put anything around an app. It now loads one
file, and the table that file returns owns the rest: start() mounts the
route, home and data name the tree, and every callback is a field on it
rather than a global the app and its chrome would have to share.
2026-08-04 20:51:25 -04:00
evan e85adfa757 feat(settings): persist the theme through the settings binding
The palette lives in Lua, so C++ stores the name only and ui.setTheme()
writes through here before rebuilding and repainting.
2026-08-04 20:44:08 -04:00
evan 291f0f20b5 build: add a format target and one shared editor config
The Lua modules were split between tabs and spaces because nothing pinned a
style; .editorconfig is what lua-language-server reads on save, so the editor
and the tree now agree. clang-format already had a config and left native/
unchanged. Embedded modules regenerate from the reformatted ui.lua.
2026-08-04 13:19:58 -04:00
evan bf286eefa6 feat(ble): expose isInitialized and reclaim memory before radios start
The controller and the WiFi driver each need a large aggregate allocation,
which a live app sitting on garbage can deny - that is why a failed connect
often succeeded on retry. Both bindings now collect before initializing, and
the tree reserves its node and spec capacity so a build does not reallocate
into a tight heap.
2026-08-04 13:10:18 -04:00
evan 3416f54c83 feat(ui): widen cards to a 2/3 column grid and add a disabled role
Two columns portrait and three landscape read better than 3/4 on a 320x480
panel. The new disabled palette role sits between face and muted, for a
control that is present but inactive.
2026-08-04 13:10:05 -04:00
evan 4533c7f61f chore: lsp + format 2026-08-04 10:21:18 -04:00
evan fa35c3c326 chore: clean up random - file 2026-08-04 09:10:54 -04:00
evan 83e04dbb79 fix: make test depend on luac32 2026-08-03 21:45:04 -04:00
evan 6a9b082f97 feat(runtime): embed platform modules as bytecode
ui.lua and hints.lua are compiled to LUA_32BITS bytecode (matching the
firmware's Lua build) and linked into the binary. A new package.searchers
entry checks them as the fallback after the SD card, so a local
/.lua/lib/ui.lua still shadows the packaged one for debugging.

Bytecode is ~40% smaller than source and loads without parsing. A fresh
SD card with no make sdcard now has the platform available.
2026-08-03 21:08:35 -04:00
evan 60ec720cdb fix(ui): drop the border from the screen root
The root fills the whole panel, so a border sent it through the per-pixel
roundRect path on every draw. The panel background is not a card; cards
that want a border set one explicitly.
2026-08-03 20:52:38 -04:00
evan a5af6b5af4 fix(node): only round a box that has a border
A filled box without one is a plain rectangle: rounding it leaves the
surface showing at the corners, which reads as a seam nobody asked for.
2026-08-03 18:28:26 -04:00
evan 2255fe214e feat(ui): let a widget opt out of the pressed style
A custom node that paints its own key highlight does not want the whole
node marked dirty on every press.
2026-08-03 18:24:51 -04:00
evan 40f7a3e4ca feat(ui): add cardSide grid helper
Square-card grids reflow on rotation, and the arithmetic is the same in
every app that draws one.
2026-08-03 18:18:02 -04:00
evan d53f9b77cd feat(runtime): expose canGoBack for firmware chrome
Firmware needs to know whether a back control would go anywhere, and the
history that answers it belongs to the runtime.
2026-08-03 17:53:27 -04:00
evan 95fa512047 initial commit 2026-08-03 17:46:14 -04:00