Skip to main content

blizz_ui/
layout_panel.rs

1use crate::layout;
2
3/// Compositor-controlled positioning for a component.
4///
5/// The panel IS the position: components render at `(column, row)`,
6/// using at most `width` columns. Components never compute their own
7/// centering — the compositor provides the panel.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub struct LayoutPanel {
10  pub row: u16,
11  pub column: u16,
12  pub width: u16,
13}
14
15impl LayoutPanel {
16  /// Horizontally centered panel for content of `content_width` at `row`.
17  pub fn centered(terminal_width: u16, content_width: u16, row: u16) -> Self {
18    let column = layout::centered_column(terminal_width, content_width);
19    Self {
20      row,
21      column,
22      width: content_width,
23    }
24  }
25
26  /// New panel offset downward by `rows`, keeping column and width.
27  pub fn below(self, rows: u16) -> Self {
28    Self {
29      row: self.row.saturating_add(rows),
30      ..self
31    }
32  }
33}
34
35#[cfg(test)]
36mod tests {
37  use super::*;
38
39  #[test]
40  fn centered_places_panel_at_correct_column() {
41    let panel = LayoutPanel::centered(80, 20, 5);
42    assert_eq!(panel.row, 5);
43    assert_eq!(panel.column, 30);
44    assert_eq!(panel.width, 20);
45  }
46
47  #[test]
48  fn below_offsets_row_preserving_column_and_width() {
49    let panel = LayoutPanel {
50      row: 3,
51      column: 10,
52      width: 40,
53    };
54    let shifted = panel.below(5);
55    assert_eq!(shifted.row, 8);
56    assert_eq!(shifted.column, 10);
57    assert_eq!(shifted.width, 40);
58  }
59
60  #[test]
61  fn below_saturates_at_max() {
62    let panel = LayoutPanel {
63      row: u16::MAX - 1,
64      column: 0,
65      width: 10,
66    };
67    let shifted = panel.below(5);
68    assert_eq!(shifted.row, u16::MAX);
69  }
70}