fix(tui): the grid and the tile bar scroll by the width they are drawn in (improvise-gtn7.1)
Grid: App::cmd_context counted visible_cols from term_width while
draw_content gave the grid term_width minus the 32-column side panel, so
with any panel open the cursor was scrolled past the last drawn column.
viewport::grid_width, reached through App::grid_width, is now the one
answer: draw_content splits on it and the keypress path counts on it.
Tile bar: the scroll measured from the end of the prefix while the draw
began one column later, two once scrolled (the left arrow), so the
selected tile could be dropped. tiles_left(start) is now where both the
scroll (first_tile) and the draw begin.
The grid defect dates from b5418f2e; it became the launch state when
50e4a372 opened the category panel by default, which is why it read as
a regression. Mixed-width columns still lose the cursor with no panel
open: improvise-gtn7.2. Reasoning: context/code/tui.md.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
@@ -220,6 +220,45 @@ belong in `advertised()` keyed by step, which would make them derived like
|
||||
everything else and let the status bar carry them correctly instead of being
|
||||
switched off.
|
||||
|
||||
### The grid's width is one answer, and a scroll is measured where it is drawn
|
||||
|
||||
Two parts of the TUI scroll horizontally, and both lost their cursor for the
|
||||
same reason: **the code that chose the scroll offset measured a different width
|
||||
from the code that drew it** (improvise-gtn7.1).
|
||||
|
||||
- **The grid.** `App::cmd_context` counts `visible_cols` for the keypress path,
|
||||
and `GridWidget` counts again from the `Rect` it is handed. The keypress path
|
||||
counted from `term_width`, while `draw_content` gave the grid `term_width`
|
||||
minus the 32-column side panel. So with any of the three panels open the
|
||||
cursor was scrolled to a column the widget never drew: it went "behind the
|
||||
panel". Now `viewport::grid_width(term_width, side_panel_open)` is the one
|
||||
answer, reached through `App::grid_width`. `draw_content` splits the content
|
||||
row on it, and `cmd_context` counts on it. `App::side_panel_open` is the one
|
||||
answer to "is a panel open", so a panel that did not count toward the width
|
||||
would not be drawn either, and the two sides still agree.
|
||||
- **The tile bar.** `TileBar` chose its first tile against the width after
|
||||
the prefix, but drew tiles one column later, and two columns later once
|
||||
scrolled, to leave room for `◀`. When the selected tile fitted within those
|
||||
one or two columns, the scroll stopped too early and the draw loop dropped the
|
||||
tile. `tiles_left(start)` is now where both the scroll (`first_tile`) and the
|
||||
draw begin.
|
||||
|
||||
**Why it looked like a regression.** The grid defect dates from `b5418f2e`
|
||||
(2026-04-06), when `compute_visible_cols` replaced a rough estimate and took
|
||||
`term_width`. It was always wrong with a panel open. But until `50e4a372`
|
||||
(2026-09-20) no panel was open at launch. That commit opened the category panel
|
||||
by default, in the shared `ViewState::default()`, and from then on every TUI
|
||||
session started in the broken configuration. The tile bar's offset has been
|
||||
wrong since `4686f470` (2026-04-09), when it first scrolled.
|
||||
|
||||
**What is still wrong: improvise-gtn7.2.** `visible_cols` is a *count*, taken at
|
||||
the *old* offset, and `viewport_effects` applies it at the *new* one. Across
|
||||
columns of mixed width no single count is right, so the cursor can still leave
|
||||
the grid with no panel open. The fix is to measure the new offset against the
|
||||
widths, as `first_tile` does. It is not in this change because
|
||||
`resolve.rs::scrolled_to` mirrors `viewport_effects` over a window counted in
|
||||
columns, and `lockstep.rs` holds the two in agreement.
|
||||
|
||||
### The caches are built here, per frame
|
||||
|
||||
`project::formulas_of`, `category_tree_of`, `view_list_of`, `tile_bar_of`,
|
||||
|
||||
Reference in New Issue
Block a user