tui: app-level event loop and state machine #16

Closed
opened 2026-04-11 13:01:45 +00:00 by charles · 0 comments
Owner

User story

As a developer adding new screens to loom-tui, I want a unified event loop, a top-level App state machine, and a routing system between screens, so that every screen plugs into the same event and render pipeline without reinventing it.

Acceptance criteria

Event enum

  • loom_tui::event::Event unifies input and async sources:
    • Key(KeyEvent), Mouse(MouseEvent), Paste(String), Resize(u16, u16), FocusGained, FocusLost, Tick, CoreMsg(loom_core::CoreEvent), Quit
  • An EventStream merges crossterm events, a 250 ms tick, and a loom-core broadcast/mpsc subscription into a single Stream<Item = Event>

App state machine

  • App owns a Screen enum (Generate, Gallery, ModelBrowser, Entities, Presets, Settings) and an optional stack of Overlays (help, palette, queue, share, image viewer)
  • App::handle_event(&mut self, event: Event) dispatches in order: overlay stack (top-first), current screen, then global bindings
  • Screens implement a common trait Screen { fn handle(&mut self, ctx: &mut AppCtx, event: &Event); fn render(&mut self, ctx: &AppCtx, frame: &mut Frame, area: Rect); }
  • AppCtx carries Arc<loom_core::PluginBridge>, an mpsc::Sender<AppAction>, the chosen Box<dyn ImageRenderer>, and the loaded AppSettings

Routing

  • Actions like AppAction::Navigate(Screen::Gallery) and AppAction::PushOverlay(Overlay::Help) fire through the shared sender; the main loop applies them before the next render
  • Each screen is lazy-constructed on first navigation and cached for the session

Tests

  • Unit test: navigating between two stub screens updates App::current and preserves scroll state on return
  • Unit test: overlay stack pops on Esc without forwarding the event to the underlying screen

Out of scope

  • Concrete screen implementations (separate tickets)
  • Sidebar & status bar widgets (separate ticket)
  • Command palette (separate ticket)

References

  • Spec §1 "Architecture Overview"
  • Spec §3 "Navigation Model"
## User story As a developer adding new screens to loom-tui, I want a unified event loop, a top-level `App` state machine, and a routing system between screens, so that every screen plugs into the same event and render pipeline without reinventing it. ## Acceptance criteria ### Event enum - [ ] `loom_tui::event::Event` unifies input and async sources: - `Key(KeyEvent)`, `Mouse(MouseEvent)`, `Paste(String)`, `Resize(u16, u16)`, `FocusGained`, `FocusLost`, `Tick`, `CoreMsg(loom_core::CoreEvent)`, `Quit` - [ ] An `EventStream` merges crossterm events, a 250 ms tick, and a `loom-core` broadcast/mpsc subscription into a single `Stream<Item = Event>` ### App state machine - [ ] `App` owns a `Screen` enum (`Generate`, `Gallery`, `ModelBrowser`, `Entities`, `Presets`, `Settings`) and an optional stack of `Overlay`s (help, palette, queue, share, image viewer) - [ ] `App::handle_event(&mut self, event: Event)` dispatches in order: overlay stack (top-first), current screen, then global bindings - [ ] Screens implement a common `trait Screen { fn handle(&mut self, ctx: &mut AppCtx, event: &Event); fn render(&mut self, ctx: &AppCtx, frame: &mut Frame, area: Rect); }` - [ ] `AppCtx` carries `Arc<loom_core::PluginBridge>`, an `mpsc::Sender<AppAction>`, the chosen `Box<dyn ImageRenderer>`, and the loaded `AppSettings` ### Routing - [ ] Actions like `AppAction::Navigate(Screen::Gallery)` and `AppAction::PushOverlay(Overlay::Help)` fire through the shared sender; the main loop applies them before the next render - [ ] Each screen is lazy-constructed on first navigation and cached for the session ### Tests - [ ] Unit test: navigating between two stub screens updates `App::current` and preserves scroll state on return - [ ] Unit test: overlay stack pops on `Esc` without forwarding the event to the underlying screen ## Out of scope - Concrete screen implementations (separate tickets) - Sidebar & status bar widgets (separate ticket) - Command palette (separate ticket) ## References - Spec §1 "Architecture Overview" - Spec §3 "Navigation Model"
charles added this to the loom-tui v0.1.0 milestone 2026-04-11 13:01:45 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/loom#16
No description provided.