Add max-rows
Scrolling left the overlay's height entirely derived — as many rows as fit in 90% of the display — so with enough windows it is always nearly full-height, and there was no way to ask for a compact strip instead. max-rows caps the viewport and scrolls the rest, which makes it the symmetric partner to max-columns; rows are also the natural unit when tiles are a fixed size, where a height in ppt would flip the row count about as the tile size changes. Measured on a 1280x1440 display with 14 tiles at 18ppt: uncapped gives a 981px surface showing 3 of 4 rows, max-rows = 2 gives 657px, and 1 gives 333px — each a row's pitch apart. The test I wrote for it was wrong before the code was: four tiles make a 2x2 grid under the ceil(sqrt(n)) rule, not the 4x1 I had assumed.
This commit is contained in:
+4
-1
@@ -53,7 +53,9 @@ config:
|
||||
|
||||
tile-width = 18ppt # how big a thumbnail is
|
||||
tile-height = 20ppt # defaults to the display's aspect
|
||||
max-columns = 4 # rows beyond the screen scroll
|
||||
max-columns = 4
|
||||
max-rows = 3 # default: as many as the display fits;
|
||||
# rows beyond that scroll
|
||||
|
||||
font = monospace # also --font
|
||||
font-size = 13.3
|
||||
@@ -159,6 +161,7 @@ impl Args {
|
||||
tile_w: tile_w.max(1),
|
||||
tile_h: tile_h.max(1),
|
||||
max_cols: cfg.max_columns.unwrap_or(base.max_cols).max(1),
|
||||
max_rows: cfg.max_rows.map(|r| r.max(1)).or(base.max_rows),
|
||||
labels: self.labels.or(cfg.labels).unwrap_or(base.labels),
|
||||
font: self
|
||||
.font
|
||||
|
||||
+5
-3
@@ -88,6 +88,7 @@ pub struct Config {
|
||||
pub tile_width: Option<Length>,
|
||||
pub tile_height: Option<Length>,
|
||||
pub max_columns: Option<i32>,
|
||||
pub max_rows: Option<i32>,
|
||||
pub font: Option<String>,
|
||||
pub font_size: Option<f32>,
|
||||
pub labels: Option<bool>,
|
||||
@@ -140,9 +141,8 @@ impl Config {
|
||||
"border-width" => self.border_width = Some(Length::parse(value)?),
|
||||
"tile-width" => self.tile_width = Some(Length::parse(value)?),
|
||||
"tile-height" => self.tile_height = Some(Length::parse(value)?),
|
||||
"max-columns" => {
|
||||
self.max_columns = Some(number(value)?);
|
||||
}
|
||||
"max-columns" => self.max_columns = Some(number(value)?),
|
||||
"max-rows" => self.max_rows = Some(number(value)?),
|
||||
"font" => self.font = Some(value.to_string()),
|
||||
"font-size" => self.font_size = Some(number(value)?),
|
||||
"labels" => self.labels = Some(boolean(value)?),
|
||||
@@ -230,6 +230,7 @@ border-width = 2px
|
||||
|
||||
tile-width = 18ppt
|
||||
max-columns = 4
|
||||
max-rows = 3
|
||||
|
||||
live = current
|
||||
fps = 30
|
||||
@@ -242,6 +243,7 @@ labels = no
|
||||
assert_eq!(cfg.border_width, Some(Length::Px(2)));
|
||||
assert_eq!(cfg.tile_width, Some(Length::Ppt(18.0)));
|
||||
assert_eq!(cfg.max_columns, Some(4));
|
||||
assert_eq!(cfg.max_rows, Some(3));
|
||||
assert_eq!(cfg.fps, Some(30));
|
||||
assert_eq!(cfg.labels, Some(false));
|
||||
assert!(cfg.live.is_some());
|
||||
|
||||
+26
-1
@@ -25,6 +25,9 @@ pub struct Theme {
|
||||
/// Margin between the grid and the window edge.
|
||||
pub margin: i32,
|
||||
pub max_cols: i32,
|
||||
/// Cap on rows shown at once. Without it the viewport is as tall as the
|
||||
/// display allows; with it the grid stays compact and scrolls sooner.
|
||||
pub max_rows: Option<i32>,
|
||||
/// Gap between a thumbnail and its label (rasi `element { spacing }`).
|
||||
pub spacing: i32,
|
||||
/// Label font family, resolved against the system's fonts. The default is
|
||||
@@ -53,6 +56,7 @@ impl Default for Theme {
|
||||
gap: 15,
|
||||
margin: 12,
|
||||
max_cols: 4,
|
||||
max_rows: None,
|
||||
spacing: 10,
|
||||
font: crate::text::SYSTEM_MONO.to_string(),
|
||||
font_px: 13.3,
|
||||
@@ -111,7 +115,8 @@ impl Layout {
|
||||
let fit_cols = ((room_w + t.gap) / (elem_w + t.gap)).max(1);
|
||||
cols = cols.clamp(1, t.max_cols.min(fit_cols)).max(1);
|
||||
let rows = (n + cols - 1) / cols;
|
||||
let visible_rows = ((room_h + t.gap) / (elem_h + t.gap)).clamp(1, rows.max(1));
|
||||
let fits = (room_h + t.gap) / (elem_h + t.gap);
|
||||
let visible_rows = fits.min(t.max_rows.unwrap_or(fits)).clamp(1, rows.max(1));
|
||||
|
||||
Self {
|
||||
cols,
|
||||
@@ -472,6 +477,26 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_rows_keeps_the_grid_compact() {
|
||||
let mut t = Theme::default();
|
||||
let full = Layout::new(&t, 30, (1280, 1440));
|
||||
t.max_rows = Some(2);
|
||||
let capped = Layout::new(&t, 30, (1280, 1440));
|
||||
assert!(
|
||||
capped.visible_rows == 2 && full.visible_rows > 2,
|
||||
"{capped:?}"
|
||||
);
|
||||
assert!(capped.height < full.height, "a shorter overlay");
|
||||
assert!(capped.scrollable());
|
||||
// The cap cannot invent rows: four tiles make a 2x2 grid, and a cap of
|
||||
// five leaves it alone.
|
||||
t.max_rows = Some(5);
|
||||
let few = Layout::new(&t, 4, (1280, 1440));
|
||||
assert_eq!((few.cols, few.rows, few.visible_rows), (2, 2, 2), "{few:?}");
|
||||
assert!(!few.scrollable());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn revealing_moves_the_viewport_as_little_as_possible() {
|
||||
let t = Theme::default();
|
||||
|
||||
Reference in New Issue
Block a user