tui: responsive/adaptive layout — adapt to terminal size #127

Closed
opened 2026-04-12 22:08:37 +00:00 by claude-desktop · 1 comment
Collaborator

User story

As a user running loom-tui in terminals of varying sizes (from 80x24 to ultra-wide), I want the layout to adapt to available space like the GTK app adapts to window size, so that the UI is usable at any terminal dimension.

Problem

Current layouts use hardcoded values:

  • Gallery grid: columns: 4 hardcoded regardless of terminal width
  • Gallery grid cell height: 10 rows hardcoded regardless of terminal height
  • Sidebar: fixed percentage width (25%) — too wide on small terminals, wastes space on large ones
  • Generate screen: fixed two-column split — preview pane disappears or overlaps on narrow terminals
  • Entity screen: three equal columns — cramped below ~120 cols
  • Settings screen: fixed 30/70 split
  • Overlays: fixed percentage centering (e.g. 60%x60%) — too small on large terminals, overflows on small ones
  • No minimum terminal size enforcement — broken layout below ~60x15

Acceptance criteria

Sidebar

  • Auto-collapse sidebar when terminal width < 100 columns (show only icons or hide completely)
  • Sidebar width adapts: ~20% on wide terminals, ~30% on medium, hidden on narrow
  • Ctrl+B toggle still works manually regardless of auto-collapse
  • Grid columns computed from terminal width: max(1, (main_area.width / 20).min(6))
  • Cell height adapts: taller cells (more image area) when terminal is tall, shorter on cramped terminals
  • Minimum cell size: 15 cols wide, 6 rows tall — below this, fall back to list view
  • List view is the automatic fallback when terminal is too narrow for even 1 grid column with images

Generate screen

  • Two-column layout (params + preview) when width >= 100
  • Single-column layout (params only, preview below or hidden) when width < 100
  • Prompt field height adapts to available space (min 3 lines, expands with terminal height)
  • Parameter fields collapse to single-line when height is limited

Entity screen

  • Three-column layout when width >= 120
  • Two-column layout (list + detail, kind tabs as top row) when width 80-120
  • Single-column layout (list only, detail as overlay on Enter) when width < 80

Settings screen

  • Two-pane layout when width >= 80
  • Single-pane layout (sections as tabs, fields below) when width < 80

Model browser

  • Source tabs + search + results layout adapts similarly to settings

Overlays

  • Overlay size scales with terminal: min 40x10, max 120x40
  • Overlays never overflow the terminal rect
  • centered_rect() clamps to terminal bounds

Minimum viable terminal

  • Enforce minimum 60x15 — show a "terminal too small" message below this
  • Handle Event::Resize to recompute all layouts immediately

Breakpoint system

  • Define breakpoints in a central place (not scattered per-screen):
    pub struct Breakpoints {
        pub compact: bool,  // width < 80
        pub medium: bool,   // 80 <= width < 120
        pub wide: bool,     // width >= 120
        pub short: bool,    // height < 30
    }
    
  • AppCtx or compute_layout() exposes current breakpoints
  • Each screen reads breakpoints to choose its layout variant

Out of scope

  • Font size detection (handled by ratatui-image's Picker)
  • DPI scaling
  • Split pane / window management

References

  • crates/loom-tui/src/components/mod.rscompute_layout(), centered_rect()
  • crates/loom-tui/src/screens/gallery.rscolumns: 4, cell_height: 10
  • crates/loom-tui/src/screens/generate.rs — two-column param layout
  • crates/loom-tui/src/screens/entities.rs — three-column layout
  • crates/loom-tui/src/screens/settings.rs — two-pane layout
  • GTK reference: loom-gtk uses AdwBreakpoint for responsive layout
## User story As a user running loom-tui in terminals of varying sizes (from 80x24 to ultra-wide), I want the layout to adapt to available space like the GTK app adapts to window size, so that the UI is usable at any terminal dimension. ## Problem Current layouts use hardcoded values: - Gallery grid: `columns: 4` hardcoded regardless of terminal width - Gallery grid cell height: 10 rows hardcoded regardless of terminal height - Sidebar: fixed percentage width (25%) — too wide on small terminals, wastes space on large ones - Generate screen: fixed two-column split — preview pane disappears or overlaps on narrow terminals - Entity screen: three equal columns — cramped below ~120 cols - Settings screen: fixed 30/70 split - Overlays: fixed percentage centering (e.g. 60%x60%) — too small on large terminals, overflows on small ones - No minimum terminal size enforcement — broken layout below ~60x15 ## Acceptance criteria ### Sidebar - [ ] Auto-collapse sidebar when terminal width < 100 columns (show only icons or hide completely) - [ ] Sidebar width adapts: ~20% on wide terminals, ~30% on medium, hidden on narrow - [ ] `Ctrl+B` toggle still works manually regardless of auto-collapse ### Gallery grid - [ ] Grid columns computed from terminal width: `max(1, (main_area.width / 20).min(6))` - [ ] Cell height adapts: taller cells (more image area) when terminal is tall, shorter on cramped terminals - [ ] Minimum cell size: 15 cols wide, 6 rows tall — below this, fall back to list view - [ ] List view is the automatic fallback when terminal is too narrow for even 1 grid column with images ### Generate screen - [ ] Two-column layout (params + preview) when width >= 100 - [ ] Single-column layout (params only, preview below or hidden) when width < 100 - [ ] Prompt field height adapts to available space (min 3 lines, expands with terminal height) - [ ] Parameter fields collapse to single-line when height is limited ### Entity screen - [ ] Three-column layout when width >= 120 - [ ] Two-column layout (list + detail, kind tabs as top row) when width 80-120 - [ ] Single-column layout (list only, detail as overlay on Enter) when width < 80 ### Settings screen - [ ] Two-pane layout when width >= 80 - [ ] Single-pane layout (sections as tabs, fields below) when width < 80 ### Model browser - [ ] Source tabs + search + results layout adapts similarly to settings ### Overlays - [ ] Overlay size scales with terminal: min 40x10, max 120x40 - [ ] Overlays never overflow the terminal rect - [ ] `centered_rect()` clamps to terminal bounds ### Minimum viable terminal - [ ] Enforce minimum 60x15 — show a "terminal too small" message below this - [ ] Handle `Event::Resize` to recompute all layouts immediately ### Breakpoint system - [ ] Define breakpoints in a central place (not scattered per-screen): ```rust pub struct Breakpoints { pub compact: bool, // width < 80 pub medium: bool, // 80 <= width < 120 pub wide: bool, // width >= 120 pub short: bool, // height < 30 } ``` - [ ] `AppCtx` or `compute_layout()` exposes current breakpoints - [ ] Each screen reads breakpoints to choose its layout variant ## Out of scope - Font size detection (handled by ratatui-image's Picker) - DPI scaling - Split pane / window management ## References - `crates/loom-tui/src/components/mod.rs` — `compute_layout()`, `centered_rect()` - `crates/loom-tui/src/screens/gallery.rs` — `columns: 4`, `cell_height: 10` - `crates/loom-tui/src/screens/generate.rs` — two-column param layout - `crates/loom-tui/src/screens/entities.rs` — three-column layout - `crates/loom-tui/src/screens/settings.rs` — two-pane layout - GTK reference: `loom-gtk` uses `AdwBreakpoint` for responsive layout
Author
Collaborator

Partial progress (#129 / tui/generate-rewrite-and-nav)

Several acceptance criteria landed as a side effect of the masonry gallery + generate screen rewrite. Updating status:

  • Cell height adapts — masonry computes per-cell height from real image aspect ratio + viewport height (was hardcoded 10 rows). Implementation in crates/loom-tui/src/screens/gallery.rs ensure_masonry_layout().
  • Layout reflows on resize — masonry cache key includes col_width; resize invalidates and re-images.
  • Grid columns still hardcoded to self.columns: 4 — needs max(1, (main_area.width / 20).min(6)) auto-calc.
  • Minimum cell size + automatic list-view fallback still missing.

Generate screen

  • Prompt height adapts — uses Constraint::Percentage(30) / Percentage(20) so prompts grow with terminal height.
  • Two-column layout (params + preview) for wide terminals — not addressed; current layout is single-column stacked.
  • Parameter fields collapse on short terminals — not addressed.

Still to do

Sidebar auto-collapse, entity layout breakpoints, settings/model browser breakpoints, overlay clamping, breakpoint system, minimum-terminal-size enforcement — all unchanged.

The breakpoint system (centralized Breakpoints struct) is still the right next step to consolidate the remaining work.

## Partial progress (#129 / `tui/generate-rewrite-and-nav`) Several acceptance criteria landed as a side effect of the masonry gallery + generate screen rewrite. Updating status: ### Gallery grid - [x] **Cell height adapts** — masonry computes per-cell height from real image aspect ratio + viewport height (was hardcoded 10 rows). Implementation in `crates/loom-tui/src/screens/gallery.rs` `ensure_masonry_layout()`. - [x] **Layout reflows on resize** — masonry cache key includes `col_width`; resize invalidates and re-images. - [ ] Grid columns still hardcoded to `self.columns: 4` — needs `max(1, (main_area.width / 20).min(6))` auto-calc. - [ ] Minimum cell size + automatic list-view fallback still missing. ### Generate screen - [x] **Prompt height adapts** — uses `Constraint::Percentage(30)` / `Percentage(20)` so prompts grow with terminal height. - [ ] Two-column layout (params + preview) for wide terminals — not addressed; current layout is single-column stacked. - [ ] Parameter fields collapse on short terminals — not addressed. ### Still to do Sidebar auto-collapse, entity layout breakpoints, settings/model browser breakpoints, overlay clamping, breakpoint system, minimum-terminal-size enforcement — all unchanged. The breakpoint system (centralized `Breakpoints` struct) is still the right next step to consolidate the remaining work.
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#127
No description provided.