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
203#[derive(Clone, Debug)]
205pub struct TableRow {
206 pub cells: Vec<TableCell>,
207 pub height: Option<u32>, }
209
210impl TableRow {
211 pub fn new(cells: Vec<TableCell>) -> Self {
213 TableRow {
214 cells,
215 height: None,
216 }
217 }
218
219 pub fn with_height(mut self, height: u32) -> Self {
221 self.height = Some(height);
222 self
223 }
224}
225
226#[derive(Clone, Debug)]
228pub struct Table {
229 pub rows: Vec<TableRow>,
230 pub column_widths: Vec<u32>, pub x: u32, pub y: u32, }
234
235impl Table {
236 pub fn new(rows: Vec<TableRow>, column_widths: Vec<u32>, x: u32, y: u32) -> Self {
238 Table {
239 rows,
240 column_widths,
241 x,
242 y,
243 }
244 }
245
246 pub fn column_count(&self) -> usize {
248 self.column_widths.len()
249 }
250
251 pub fn row_count(&self) -> usize {
253 self.rows.len()
254 }
255
256 pub fn width(&self) -> u32 {
258 self.column_widths.iter().sum()
259 }
260
261 pub fn height(&self) -> u32 {
263 self.rows
264 .iter()
265 .map(|r| r.height.unwrap_or(400000))
266 .sum()
267 }
268
269 pub fn from_data(data: Vec<Vec<&str>>, column_widths: Vec<u32>, x: u32, y: u32) -> Self {
271 let rows = data
272 .into_iter()
273 .map(|row| {
274 let cells = row
275 .into_iter()
276 .map(|cell| TableCell::new(cell))
277 .collect();
278 TableRow::new(cells)
279 })
280 .collect();
281
282 Table {
283 rows,
284 column_widths,
285 x,
286 y,
287 }
288 }
289}
290
291pub struct TableBuilder {
293 rows: Vec<TableRow>,
294 column_widths: Vec<u32>,
295 x: u32,
296 y: u32,
297}
298
299impl TableBuilder {
300 pub fn new(column_widths: Vec<u32>) -> Self {
302 TableBuilder {
303 rows: Vec::new(),
304 column_widths,
305 x: 0,
306 y: 0,
307 }
308 }
309
310 pub fn position(mut self, x: u32, y: u32) -> Self {
312 self.x = x;
313 self.y = y;
314 self
315 }
316
317 pub fn add_row(mut self, row: TableRow) -> Self {
319 self.rows.push(row);
320 self
321 }
322
323 pub fn add_simple_row(mut self, cells: Vec<&str>) -> Self {
325 let row = TableRow::new(
326 cells
327 .into_iter()
328 .map(|c| TableCell::new(c))
329 .collect(),
330 );
331 self.rows.push(row);
332 self
333 }
334
335 pub fn build(self) -> Table {
337 Table {
338 rows: self.rows,
339 column_widths: self.column_widths,
340 x: self.x,
341 y: self.y,
342 }
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349
350 #[test]
351 fn test_table_cell_builder() {
352 let cell = TableCell::new("Header")
353 .bold()
354 .italic()
355 .underline()
356 .text_color("FF0000")
357 .background_color("0000FF")
358 .font_size(24)
359 .font_family("Arial");
360 assert_eq!(cell.text, "Header");
361 assert!(cell.bold);
362 assert!(cell.italic);
363 assert!(cell.underline);
364 assert_eq!(cell.text_color, Some("FF0000".to_string()));
365 assert_eq!(cell.background_color, Some("0000FF".to_string()));
366 assert_eq!(cell.font_size, Some(24));
367 assert_eq!(cell.font_family, Some("Arial".to_string()));
368 }
369
370 #[test]
371 fn test_table_row() {
372 let cells = vec![TableCell::new("A"), TableCell::new("B")];
373 let row = TableRow::new(cells).with_height(500000);
374 assert_eq!(row.cells.len(), 2);
375 assert_eq!(row.height, Some(500000));
376 }
377
378 #[test]
379 fn test_table_from_data() {
380 let data = vec![
381 vec!["Name", "Age"],
382 vec!["Alice", "30"],
383 vec!["Bob", "25"],
384 ];
385 let table = Table::from_data(data, vec![1000000, 1000000], 0, 0);
386 assert_eq!(table.row_count(), 3);
387 assert_eq!(table.column_count(), 2);
388 }
389
390 #[test]
391 fn test_table_builder() {
392 let table = TableBuilder::new(vec![1000000, 1000000])
393 .position(100000, 200000)
394 .add_simple_row(vec!["Header 1", "Header 2"])
395 .add_simple_row(vec!["Cell 1", "Cell 2"])
396 .build();
397
398 assert_eq!(table.row_count(), 2);
399 assert_eq!(table.column_count(), 2);
400 assert_eq!(table.x, 100000);
401 assert_eq!(table.y, 200000);
402 }
403}