Files
valw/docs/superpowers/specs/2026-10-03-valw-phase-6-toolbar-design.md
T

116 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# valw Phase 6: the toolbar (design)
Date: 2026-10-03
Status: approved in brainstorming, pending written-spec review
Builds on: Phases 0–5 (on `main`); vision section 4.6
## 1. Goal
A Cmd+Shift+5-style bar: `valw toolbar` shows a floating bar at the
bottom of the focused output, the user picks a mode (and, if they like, a
timer, the cursor and the preview), and that mode runs as if started from
the command line.
Success: every mode starts from the bar with one click, the options are
remembered, and nothing of the bar or its countdown ends up in a shot.
### Out of scope
- A remembered region drawn on screen and a separate Capture button (the
macOS "select, then capture" flow).
- Save-location choices; screen recording.
## 2. Decisions
| Question | Decision | Why |
|---|---|---|
| Flow | Clicking a mode starts it at once | Simple and fast |
| Options | Timer (None / 5 s / 10 s), Show cursor, Show preview | User choice |
| Rendering | A layer-shell surface drawn with tiny-skia and the editor's bundled font | Floats without niri rules; same stack as the overlay and preview; no new dependency |
| Memory | Last mode and options in `$XDG_STATE_HOME/valw/toolbar.toml` | The config may become a read-only home-manager file |
## 3. Behaviour
### 3.1 The bar
- A layer surface (namespace `valw-toolbar`, overlay layer, exclusive
keyboard) covering niri's focused output. It is transparent except for
the bar, which sits 24 logical px above the bottom edge, horizontally
centred; covering the output is what lets a click beside the bar close
it.
- Contents, left to right: **Screen**, **Window**, **Region**, a
separator, **Zoom**, a separator, **Options ▾**. Labels in English,
13 px, white; background `#1c1c1e` at 90 % opacity with 12 px corner
radius; buttons 32 px tall with 12 px horizontal padding.
- The last used mode is highlighted (a lighter fill); the button under
the pointer is highlighted more lightly.
- Drawn at the output's scale (buffer at physical size, viewporter to
logical size), as the overlay does.
### 3.2 Options
**Options ▾** toggles a small menu above the bar, aligned to the button:
- Timer: None / 5 s / 10 s (one of three)
- Show cursor (check)
- Show preview (check)
Clicks in the menu change the option and keep the menu open. The options
apply only to captures started from the bar; the config is untouched.
### 3.3 Starting a mode
- A click on Screen, Window, Region or Zoom closes the bar (its surface is
destroyed and the destruction flushed) and starts the mode with the
options: Show cursor → `--cursor`; Show preview off → `--no-preview`.
- With a timer, a countdown pill (namespace `valw-countdown`, the same
style, about 64 × 40 px, bottom-centred where the bar was) shows the
seconds left, 5 → 1 (or 10 → 1), redrawn every second, and is destroyed
before the mode starts so it is never captured. Esc during the
countdown cancels (exit 3); the pill has exclusive keyboard focus.
- The chosen mode and options are saved before the mode starts.
### 3.4 Leaving
Esc, a click outside the bar and its menu, or the compositor closing the
surface: nothing is captured, exit code 3 (`Cancelled`), like Esc in
region mode.
### 3.5 Memory
`toolbar.toml` holds `mode` (`screen` | `window` | `region` | `zoom`),
`timer` (0, 5, 10), `cursor` and `preview` (booleans). Without a file the
defaults are: mode `region`, timer 0, `cursor = capture.show_cursor`,
`preview = preview.enabled` from the config. An unreadable or invalid file
logs a warning and uses the defaults; it is overwritten on the next save.
## 4. Structure
| File | Role |
|---|---|
| `src/toolbar/layout.rs` | Pure: button and menu rectangles from the measured label widths; `hit(point) -> Option<Target>` for the bar and the menu |
| `src/toolbar/state.rs` | `ToolbarState` load/save, defaults from the config |
| `src/toolbar/countdown.rs` | The countdown pill and its timing |
| `src/toolbar/mod.rs` | `run(wl, outputs, config) -> Result<Choice>`: the surface, drawing (tiny-skia + `editor::text`), input |
| `src/main.rs` | `Command::Toolbar`; the choice becomes `capture(mode, common)` |
| `src/wayland.rs` | Routing configure/pointer/keyboard/focus events to the toolbar |
## 5. Testing
Unit tests (`cargo nextest`):
- `layout`: buttons in order, non-overlapping, centred; hits on each
button, the separators (none), outside (none); menu rows' hits.
- `state`: defaults from the config, save/load round trip, a broken file
falls back to the defaults, unknown keys are ignored.
- `countdown`: the sequence of numbers for 5 and 10 s, and that 0 means
no countdown.
- `main`: the CLI parses `toolbar`; a choice maps to the right mode and
flags.
Manual checks go to the Phase 6 section of `docs/test-checklist.md`.
## 6. Definition of done
`cargo clippy -- -D warnings`, `cargo fmt --check`, `cargo nextest run`
and `nix flake check` pass; the checklist section is written.