Scroll when there are more tiles than fit

Shrinking the grid to fit meant a configured tile-width was quietly
ignored the moment enough windows were open — a setting that silently
does not apply is a bug, not a policy. Tiles are now the size the config
asks for and the extra rows scroll.

The layout became a viewport: it reports how many rows fit, elem/tile/
label take a scroll offset and return nothing for tiles above or below
the fold, and hit-testing follows the offset so a click lands on what is
under the cursor rather than what used to be there. Any keyboard move
goes through select(), which scrolls the least that keeps the selection
visible; PgUp/PgDn jump a screen. A scrollbar appears in the right margin
only when there is something to scroll, so it reads as a hint rather than
furniture.

Tiles scrolled out of sight get a null buffer, which unmaps their
subsurface, and the live clock skips them — a long list no longer spends
readback bandwidth on pixels nobody can see. Re-placing the subsurfaces
happens once per dispatch in the event loop rather than inside the key
handler, so holding an arrow key coalesces.

Shrinking survives for one case only: a tile too large for even a single
row or column, where otherwise nothing could be drawn. The old
shrink-to-fit test was rewritten around that, since its premise (twenty
tiles at full size cannot fit) is now answered by scrolling instead.

Verified against the session: 16 tiles at tile-width = 40ppt gives a 2x8
grid with 2 rows visible; three Downs scroll to row 2 and Enter returns
index 6, matching its own list; 82% of the viewport changes across the
scroll; and the scrollbar thumb measures 634px tall at y=24 unscrolled
and y=658 at scroll 2, both what the geometry predicts.
This commit is contained in:
Milad Alizadeh
2026-08-31 18:20:03 +01:00
parent 487acb8b6a
commit 30c478872a
7 changed files with 355 additions and 147 deletions
+12
View File
@@ -88,6 +88,10 @@ pub struct App {
pub(crate) fps: u32,
pub(crate) scale: i32,
pub(crate) sel: usize,
/// First row of the grid on screen. The rest scroll.
pub(crate) scroll: i32,
/// Set when the viewport moved and the subsurfaces need re-placing.
pub(crate) needs_tiles: bool,
pub(crate) shift: bool,
/// Where the pointer is, and which tile it pressed. Hovering deliberately
@@ -185,6 +189,8 @@ impl App {
fps,
scale,
sel: 0,
scroll: 0,
needs_tiles: false,
shift: false,
hover: None,
pressed: None,
@@ -243,6 +249,12 @@ impl App {
self.stats.pool_bytes >> 20,
self.labels.as_ref().map(|l| l.family()).unwrap_or("none"),
);
if self.layout.scrollable() {
eprintln!(
"wl-pick: {} of {} rows fit; the rest scroll",
self.layout.visible_rows, self.layout.rows
);
}
}
/// What live capture actually did, once the overlay is closing.