The main IO loop: owns the terminal, the view stack and every view's timer.
Everything that is impure lives here. Keys arrive as messages from
Atui.Input, ticks from timers, and both are dispatched to views; whatever a
view replies decides the new state. After every event the stack is rendered
into a single frame and compared with the last one — if nothing changed,
nothing is written, so an idle UI is silent on the wire.
Views are stacked, topmost first: the bottom one is the root and each push (a popup) draws over what is below it.
Who gets what
Keys go to the root view first — the place for global keys like quit —
and on to the focused view, which is the topmost one, for every key the
root answers {:pass, state} to.
Ticks are per view: each one asks for its own interval in
Atui.View.tick_interval/1 and gets a timer and a counter of its own, so a
clock ticking every second costs nothing to a view that never ticks.
Events go to the focused view, unless addressed to a particular view with
send_event_to/3, which is how a covered view keeps working. Any message the
runtime does not recognise is delivered as an event, so a Task reply or a
PubSub broadcast reaches the UI without ceremony.
Summary
Functions
Returns a specification to start this module under a supervisor.
Quits the UI as if the root view had returned :halt.
Schedules an event for module, delivered after delay milliseconds.
The most recently rendered screen — the way tests inspect the UI.
Sends an event to the focused view's Atui.View.handle_event/2.
Sends an event to the topmost view of module, wherever it sits in the stack.
Feeds a key to the loop as if it had been typed.
Starts the loop.
The current view stack as a list of modules, topmost first.
The state of the topmost view of module, or nil if it is not mounted.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
Quits the UI as if the root view had returned :halt.
Schedules an event for module, delivered after delay milliseconds.
Call it from inside a view callback, where it addresses the runtime the view
is running in — how a view gives something of its own a timer without owning
a process. Returns a timer reference for Process.cancel_timer/1.
The most recently rendered screen — the way tests inspect the UI.
Sends an event to the focused view's Atui.View.handle_event/2.
Sending the runtime a plain message does the same thing, so anything that can
reach the process — a monitor, a Task, a subscription — can drive the UI.
Sends an event to the topmost view of module, wherever it sits in the stack.
Lets a covered view keep working while a popup has focus. The event is dropped if no such view is mounted.
Feeds a key to the loop as if it had been typed.
Starts the loop.
Options:
:view— the root view module (required):view_opts— passed to the root view'smount/1:headless— do not touch the terminal; render into memory only. Used by tests, which then read frames back withscreen/1.:size— force a viewport size as{cols, rows}instead of asking the terminal:halt—:systemstops the VM when the UI quits (default),:stoponly stops this process
The current view stack as a list of modules, topmost first.
The state of the topmost view of module, or nil if it is not mounted.
A window into a running UI — for tests, and for asking a live application what it thinks it is showing.