1#[derive(Clone, Debug, Default, PartialEq)]
5pub enum CellAlign {
6 Left,
7 #[default]
8 Center,
9 Right,
10 Justify,
11}
12
13impl CellAlign {
14 pub fn as_str(&self) -> &'static str {
16 match self {
17 CellAlign::Left => "l",
18 CellAlign::Center => "ctr",
19 CellAlign::Right => "r",
20 CellAlign::Justify => "just",
21 }
22 }
23}
24
25#[derive(Clone, Debug, Default, PartialEq)]
27pub enum CellVAlign {
28 Top,
29 #[default]
30 Middle,
31 Bottom,
32}
33
34impl CellVAlign {
35 pub fn as_str(&self) -> &'static str {
37 match self {
38 CellVAlign::Top => "t",
39 CellVAlign::Middle => "ctr",
40 CellVAlign::Bottom => "b",
41 }
42 }
43}
44
45#[derive(Clone, Debug)]
47pub struct TableCell {
48 pub text: String,
49 pub bold: bool,
50 pub italic: bool,
51 pub underline: bool,
52 pub text_color: Option<String>, pub background_color: Option<String>, pub font_size: Option<u32>, pub font_family: Option<String>, pub align: CellAlign, pub valign: CellVAlign, pub wrap_text: bool, }
60
61impl TableCell {
62 pub fn new(text: &str) -> Self {
64 TableCell {
65 text: text.to_string(),
66 bold: false,
67 italic: false,
68 underline: false,
69 text_color: None,
70 background_color: None,
71 font_size: None,
72 font_family: None,
73 align: CellAlign::Center,
74 valign: CellVAlign::Middle,
75 wrap_text: true,
76 }
77 }
78
79 pub fn bold(mut self) -> Self {
81 self.bold = true;
82 self
83 }
84
85 pub fn italic(mut self) -> Self {
87 self.italic = true;
88 self
89 }
90
91 pub fn underline(mut self) -> Self {
93 self.underline = true;
94 self
95 }
96
97 pub fn text_color(mut self, color: &str) -> Self {
99 self.text_color = Some(color.trim_start_matches('#').to_uppercase());
100 self
101 }
102
103 pub fn background_color(mut self, color: &str) -> Self {
105 self.background_color = Some(color.trim_start_matches('#').to_uppercase());
106 self
107 }
108
109 pub fn font_size(mut self, size: u32) -> Self {
111 self.font_size = Some(size);
112 self
113 }
114
115 pub fn font_family(mut self, family: &str) -> Self {
117 self.font_family = Some(family.to_string());
118 self
119 }
120
121 pub fn align(mut self, align: CellAlign) -> Self {
123 self.align = align;
124 self
125 }
126
127 pub fn align_left(mut self) -> Self {
129 self.align = CellAlign::Left;
130 self
131 }
132
133 pub fn align_right(mut self) -> Self {
135 self.align = CellAlign::Right;
136 self
137 }
138
139 pub fn align_center(mut self) -> Self {
141 self.align = CellAlign::Center;
142 self
143 }
144
145 pub fn valign(mut self, valign: CellVAlign) -> Self {
147 self.valign = valign;
148 self
149 }
150
151 pub fn valign_top(mut self) -> Self {
153 self.valign = CellVAlign::Top;
154 self
155 }
156
157 pub fn valign_bottom(mut self) -> Self {
159 self.valign = CellVAlign::Bottom;
160 self
161 }
162
163 pub fn wrap(mut self, wrap: bool) -> Self {
165 self.wrap_text = wrap;
166 self
167 }
168}
169
170#[derive(Clone, Debug)]
172pub struct TableRow {
173 pub cells: Vec<TableCell>,
174 pub height: Option<u32>, }
176
177impl TableRow {
178 pub fn new(cells: Vec<TableCell>) -> Self {
180 TableRow {
181 cells,
182 height: None,
183 }
184 }
185
186 pub fn with_height(mut self, height: u32) -> Self {
188 self.height = Some(height);
189 self
190 }
191}
192
193#[derive(Clone, Debug)]
195pub struct Table {
196 pub rows: Vec<TableRow>,
197 pub column_widths: Vec<u32>, pub x: u32, pub y: u32, }
201
202impl Table {
203 pub fn new(rows: Vec<TableRow>, column_widths: Vec<u32>, x: u32, y: u32) -> Self {
205 Table {
206 rows,
207 column_widths,
208 x,
209 y,
210 }
211 }
212
213 pub fn column_count(&self) -> usize {
215 self.column_widths.len()
216 }
217
218 pub fn row_count(&self) -> usize {
220 self.rows.len()
221 }
222
223 pub fn width(&self) -> u32 {
225 self.column_widths.iter().sum()
226 }
227
228 pub fn height(&self) -> u32 {
230 self.rows
231 .iter()
232 .map(|r| r.height.unwrap_or(400000))
233 .sum()
234 }
235
236 pub fn from_data(data: Vec<Vec<&str>>, column_widths: Vec<u32>, x: u32, y: u32) -> Self {
238 let rows = data
239 .into_iter()
240 .map(|row| {
241 let cells = row
242 .into_iter()
243 .map(|cell| TableCell::new(cell))
244 .collect();
245 TableRow::new(cells)
246 })
247 .collect();
248
249 Table {
250 rows,
251 column_widths,
252 x,
253 y,
254 }
255 }
256}
257
258pub struct TableBuilder {
260 rows: Vec<TableRow>,
261 column_widths: Vec<u32>,
262 x: u32,
263 y: u32,
264}
265
266impl TableBuilder {
267 pub fn new(column_widths: Vec<u32>) -> Self {
269 TableBuilder {
270 rows: Vec::new(),
271 column_widths,
272 x: 0,
273 y: 0,
274 }
275 }
276
277 pub fn position(mut self, x: u32, y: u32) -> Self {
279 self.x = x;
280 self.y = y;
281 self
282 }
283
284 pub fn add_row(mut self, row: TableRow) -> Self {
286 self.rows.push(row);
287 self
288 }
289
290 pub fn add_simple_row(mut self, cells: Vec<&str>) -> Self {
292 let row = TableRow::new(
293 cells
294 .into_iter()
295 .map(|c| TableCell::new(c))
296 .collect(),
297 );
298 self.rows.push(row);
299 self
300 }
301
302 pub fn build(self) -> Table {
304 Table {
305 rows: self.rows,
306 column_widths: self.column_widths,
307 x: self.x,
308 y: self.y,
309 }
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316
317 #[test]
318 fn test_table_cell_builder() {
319 let cell = TableCell::new("Header")
320 .bold()
321 .italic()
322 .underline()
323 .text_color("FF0000")
324 .background_color("0000FF")
325 .font_size(24)
326 .font_family("Arial");
327 assert_eq!(cell.text, "Header");
328 assert!(cell.bold);
329 assert!(cell.italic);
330 assert!(cell.underline);
331 assert_eq!(cell.text_color, Some("FF0000".to_string()));
332 assert_eq!(cell.background_color, Some("0000FF".to_string()));
333 assert_eq!(cell.font_size, Some(24));
334 assert_eq!(cell.font_family, Some("Arial".to_string()));
335 }
336
337 #[test]
338 fn test_table_row() {
339 let cells = vec![TableCell::new("A"), TableCell::new("B")];
340 let row = TableRow::new(cells).with_height(500000);
341 assert_eq!(row.cells.len(), 2);
342 assert_eq!(row.height, Some(500000));
343 }
344
345 #[test]
346 fn test_table_from_data() {
347 let data = vec![
348 vec!["Name", "Age"],
349 vec!["Alice", "30"],
350 vec!["Bob", "25"],
351 ];
352 let table = Table::from_data(data, vec![1000000, 1000000], 0, 0);
353 assert_eq!(table.row_count(), 3);
354 assert_eq!(table.column_count(), 2);
355 }
356
357 #[test]
358 fn test_table_builder() {
359 let table = TableBuilder::new(vec![1000000, 1000000])
360 .position(100000, 200000)
361 .add_simple_row(vec!["Header 1", "Header 2"])
362 .add_simple_row(vec!["Cell 1", "Cell 2"])
363 .build();
364
365 assert_eq!(table.row_count(), 2);
366 assert_eq!(table.column_count(), 2);
367 assert_eq!(table.x, 100000);
368 assert_eq!(table.y, 200000);
369 }
370}