1use crate::color::Color;
14
15#[derive(Clone, Debug)]
17pub struct Cell {
18 pub ch: char,
20 pub fg: Option<Color>,
22 pub bg: Option<Color>,
24 pub visible: bool,
26}
27
28#[derive(Clone, Debug)]
30pub struct Grid {
31 cells: Vec<Vec<Cell>>,
32}
33
34#[derive(Clone, Copy, Debug)]
36pub enum Align {
37 Left,
39 Center,
41 Right,
43}
44
45#[derive(Clone, Copy, Debug)]
47pub struct Padding {
48 pub top: usize,
50 pub bottom: usize,
52 pub left: usize,
54 pub right: usize,
56}
57
58impl Grid {
59 pub fn new(height: usize, width: usize) -> Self {
61 let row = vec![
62 Cell {
63 ch: ' ',
64 fg: None,
65 bg: None,
66 visible: false,
67 };
68 width
69 ];
70 let cells = vec![row; height];
71 Self { cells }
72 }
73
74 pub fn from_char_rows(rows: Vec<Vec<char>>) -> Self {
76 let cells = rows
77 .into_iter()
78 .map(|row| {
79 row.into_iter()
80 .map(|ch| Cell {
81 ch,
82 fg: None,
83 bg: None,
84 visible: ch != ' ',
85 })
86 .collect::<Vec<_>>()
87 })
88 .collect::<Vec<_>>();
89 Self { cells }
90 }
91
92 pub fn height(&self) -> usize {
94 self.cells.len()
95 }
96
97 pub fn width(&self) -> usize {
99 self.cells.first().map(|row| row.len()).unwrap_or(0)
100 }
101
102 pub fn cell_mut(&mut self, row: usize, col: usize) -> Option<&mut Cell> {
104 self.cells.get_mut(row).and_then(|r| r.get_mut(col))
105 }
106
107 pub fn cell(&self, row: usize, col: usize) -> Option<&Cell> {
109 self.cells.get(row).and_then(|r| r.get(col))
110 }
111
112 pub fn rows(&self) -> &[Vec<Cell>] {
114 &self.cells
115 }
116
117 pub fn rows_mut(&mut self) -> &mut [Vec<Cell>] {
119 &mut self.cells
120 }
121
122 pub fn blit(&mut self, other: &Grid, top: usize, left: usize) {
124 for (r, row) in other.cells.iter().enumerate() {
125 let target_r = top + r;
126 if target_r >= self.height() {
127 continue;
128 }
129 for (c, cell) in row.iter().enumerate() {
130 let target_c = left + c;
131 if target_c >= self.width() {
132 continue;
133 }
134 if cell.visible {
135 self.cells[target_r][target_c] = cell.clone();
136 }
137 }
138 }
139 }
140
141 pub fn trim_vertical(&self) -> Self {
143 if self.height() == 0 {
144 return self.clone();
145 }
146
147 let mut top = 0;
148 let mut bottom = self.height();
149
150 while top < bottom && !row_has_visible(&self.cells[top]) {
151 top += 1;
152 }
153
154 while bottom > top && !row_has_visible(&self.cells[bottom - 1]) {
155 bottom -= 1;
156 }
157
158 if top == 0 && bottom == self.height() {
159 return self.clone();
160 }
161
162 Grid {
163 cells: self.cells[top..bottom].to_vec(),
164 }
165 }
166}
167
168fn row_has_visible(row: &[Cell]) -> bool {
169 row.iter().any(|cell| cell.visible)
170}
171
172impl Padding {
173 pub fn uniform(value: usize) -> Self {
175 Self {
176 top: value,
177 bottom: value,
178 left: value,
179 right: value,
180 }
181 }
182}
183
184impl From<usize> for Padding {
185 fn from(value: usize) -> Self {
186 Padding::uniform(value)
187 }
188}
189
190impl From<(usize, usize, usize, usize)> for Padding {
191 fn from(values: (usize, usize, usize, usize)) -> Self {
192 Self {
193 top: values.0,
194 right: values.1,
195 bottom: values.2,
196 left: values.3,
197 }
198 }
199}