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, pub row_span: u32,
60 pub col_span: u32,
61 pub v_merge: bool,
62 pub h_merge: bool,
63}
64
65impl TableCell {
66 pub fn new(text: &str) -> Self {
68 TableCell {
69 text: text.to_string(),
70 bold: false,
71 italic: false,
72 underline: false,
73 text_color: None,
74 background_color: None,
75 font_size: None,
76 font_family: None,
77 align: CellAlign::Center,
78 valign: CellVAlign::Middle,
79 wrap_text: true,
80 row_span: 1,
81 col_span: 1,
82 v_merge: false,
83 h_merge: false,
84 }
85 }
86
87 pub fn bold(mut self) -> Self {
89 self.bold = true;
90 self
91 }
92
93 pub fn italic(mut self) -> Self {
95 self.italic = true;
96 self
97 }
98
99 pub fn underline(mut self) -> Self {
101 self.underline = true;
102 self
103 }
104
105
106 pub fn text_color(mut self, color: &str) -> Self {
108 self.text_color = Some(color.trim_start_matches('#').to_uppercase());
109 self
110 }
111
112 pub fn background_color(mut self, color: &str) -> Self {
114 self.background_color = Some(color.trim_start_matches('#').to_uppercase());
115 self
116 }
117
118 pub fn font_size(mut self, size: u32) -> Self {
120 self.font_size = Some(size);
121 self
122 }
123
124 pub fn font_family(mut self, family: &str) -> Self {
126 self.font_family = Some(family.to_string());
127 self
128 }
129
130 pub fn align(mut self, align: CellAlign) -> Self {
132 self.align = align;
133 self
134 }
135
136 pub fn align_left(mut self) -> Self {
138 self.align = CellAlign::Left;
139 self
140 }
141
142 pub fn align_right(mut self) -> Self {
144 self.align = CellAlign::Right;
145 self
146 }
147
148 pub fn align_center(mut self) -> Self {
150 self.align = CellAlign::Center;
151 self
152 }
153
154 pub fn valign(mut self, valign: CellVAlign) -> Self {
156 self.valign = valign;
157 self
158 }
159
160 pub fn valign_top(mut self) -> Self {
162 self.valign = CellVAlign::Top;
163 self
164 }
165
166 pub fn valign_bottom(mut self) -> Self {
168 self.valign = CellVAlign::Bottom;
169 self
170 }
171
172 pub fn wrap(mut self, wrap: bool) -> Self {
174 self.wrap_text = wrap;
175 self
176 }
177
178 pub fn with_row_span(mut self, span: u32) -> Self {
180 self.row_span = span;
181 self
182 }
183
184 pub fn with_col_span(mut self, span: u32) -> Self {
186 self.col_span = span;
187 self
188 }
189
190 pub fn with_v_merge(mut self) -> Self {
192 self.v_merge = true;
193 self
194 }
195
196 pub fn with_h_merge(mut self) -> Self {
198 self.h_merge = true;
199 self
200 }
201
202 pub fn grid_span(mut self, span: u32) -> Self {
204 self.col_span = span;
205 self
206 }
207
208 pub fn row_span(mut self, span: u32) -> Self {
210 self.row_span = span;
211 self
212 }
213
214 pub fn h_merge(mut self) -> Self {
216 self.h_merge = true;
217 self
218 }
219
220 pub fn v_merge(mut self) -> Self {
222 self.v_merge = true;
223 self
224 }
225}
226
227#[derive(Clone, Debug)]
229pub struct TableRow {
230 pub cells: Vec<TableCell>,
231 pub height: Option<u32>, }
233
234impl TableRow {
235 pub fn new(cells: Vec<TableCell>) -> Self {
237 TableRow {
238 cells,
239 height: None,
240 }
241 }
242
243 pub fn with_height(mut self, height: u32) -> Self {
245 self.height = Some(height);
246 self
247 }
248}
249
250#[derive(Clone, Debug)]
252pub struct Table {
253 pub rows: Vec<TableRow>,
254 pub column_widths: Vec<u32>, pub x: u32, pub y: u32, }
258
259impl Table {
260 pub fn new(rows: Vec<TableRow>, column_widths: Vec<u32>, x: u32, y: u32) -> Self {
262 Table {
263 rows,
264 column_widths,
265 x,
266 y,
267 }
268 }
269
270 pub fn column_count(&self) -> usize {
272 self.column_widths.len()
273 }
274
275 pub fn row_count(&self) -> usize {
277 self.rows.len()
278 }
279
280 pub fn width(&self) -> u32 {
282 self.column_widths.iter().sum()
283 }
284
285 pub fn height(&self) -> u32 {
287 self.rows
288 .iter()
289 .map(|r| r.height.unwrap_or(400000))
290 .sum()
291 }
292
293 pub fn from_data(data: Vec<Vec<&str>>, column_widths: Vec<u32>, x: u32, y: u32) -> Self {
295 let rows = data
296 .into_iter()
297 .map(|row| {
298 let cells = row
299 .into_iter()
300 .map(TableCell::new)
301 .collect();
302 TableRow::new(cells)
303 })
304 .collect();
305
306 Table {
307 rows,
308 column_widths,
309 x,
310 y,
311 }
312 }
313}
314
315pub struct TableBuilder {
317 rows: Vec<TableRow>,
318 column_widths: Vec<u32>,
319 x: u32,
320 y: u32,
321}
322
323impl TableBuilder {
324 pub fn new(column_widths: Vec<u32>) -> Self {
326 TableBuilder {
327 rows: Vec::new(),
328 column_widths,
329 x: 0,
330 y: 0,
331 }
332 }
333
334 pub fn position(mut self, x: u32, y: u32) -> Self {
336 self.x = x;
337 self.y = y;
338 self
339 }
340
341 pub fn add_row(mut self, row: TableRow) -> Self {
343 self.rows.push(row);
344 self
345 }
346
347 pub fn add_simple_row(mut self, cells: Vec<&str>) -> Self {
349 let row = TableRow::new(
350 cells
351 .into_iter()
352 .map(TableCell::new)
353 .collect(),
354 );
355 self.rows.push(row);
356 self
357 }
358
359 pub fn build(self) -> Table {
361 Table {
362 rows: self.rows,
363 column_widths: self.column_widths,
364 x: self.x,
365 y: self.y,
366 }
367 }
368}
369
370#[cfg(test)]
371mod tests {
372 use super::*;
373
374 #[test]
375 fn test_table_cell_builder() {
376 let cell = TableCell::new("Header")
377 .bold()
378 .italic()
379 .underline()
380 .text_color("FF0000")
381 .background_color("0000FF")
382 .font_size(24)
383 .font_family("Arial");
384 assert_eq!(cell.text, "Header");
385 assert!(cell.bold);
386 assert!(cell.italic);
387 assert!(cell.underline);
388 assert_eq!(cell.text_color, Some("FF0000".to_string()));
389 assert_eq!(cell.background_color, Some("0000FF".to_string()));
390 assert_eq!(cell.font_size, Some(24));
391 assert_eq!(cell.font_family, Some("Arial".to_string()));
392 }
393
394 #[test]
395 fn test_table_row() {
396 let cells = vec![TableCell::new("A"), TableCell::new("B")];
397 let row = TableRow::new(cells).with_height(500000);
398 assert_eq!(row.cells.len(), 2);
399 assert_eq!(row.height, Some(500000));
400 }
401
402 #[test]
403 fn test_table_from_data() {
404 let data = vec![
405 vec!["Name", "Age"],
406 vec!["Alice", "30"],
407 vec!["Bob", "25"],
408 ];
409 let table = Table::from_data(data, vec![1000000, 1000000], 0, 0);
410 assert_eq!(table.row_count(), 3);
411 assert_eq!(table.column_count(), 2);
412 }
413
414 #[test]
415 fn test_table_builder() {
416 let table = TableBuilder::new(vec![1000000, 1000000])
417 .position(100000, 200000)
418 .add_simple_row(vec!["Header 1", "Header 2"])
419 .add_simple_row(vec!["Cell 1", "Cell 2"])
420 .build();
421
422 assert_eq!(table.row_count(), 2);
423 assert_eq!(table.column_count(), 2);
424 assert_eq!(table.x, 100000);
425 assert_eq!(table.y, 200000);
426 }
427}