1use crate::page::PageSize;
2use crate::text::TextBuilder;
3use crate::vector::{Canvas, Color};
4
5#[cfg(feature = "tracing")]
6use tracing::instrument;
7
8#[derive(Clone, Debug, PartialEq)]
9pub struct BorderStyle {
10 pub color: Color,
11 pub width: f64,
12 pub enabled: bool,
13}
14
15impl Default for BorderStyle {
16 fn default() -> Self {
17 Self {
18 color: Color::BLACK,
19 width: 1.0,
20 enabled: true,
21 }
22 }
23}
24
25#[derive(Clone, Debug)]
26pub struct TableCell {
27 pub content: Vec<u8>,
28 pub width: Option<f64>,
29 pub height: Option<f64>,
30 pub background: Option<Color>,
31 pub border: BorderStyle,
32 pub colspan: u32,
33 pub rowspan: u32,
34}
35
36impl Default for TableCell {
37 fn default() -> Self {
38 Self {
39 content: Vec::new(),
40 width: None,
41 height: None,
42 background: None,
43 border: Default::default(),
44 colspan: 1,
45 rowspan: 1,
46 }
47 }
48}
49
50impl TableCell {
51 pub fn text(text: TextBuilder) -> Self {
52 Self {
53 content: text.finish(),
54 ..Default::default()
55 }
56 }
57
58 pub fn canvas(canvas: Canvas) -> Self {
59 Self {
60 content: canvas.finish(),
61 ..Default::default()
62 }
63 }
64
65 pub fn background(mut self, color: Color) -> Self {
66 self.background = Some(color);
67 self
68 }
69
70 pub fn border(mut self, style: BorderStyle) -> Self {
71 self.border = style;
72 self
73 }
74}
75
76#[derive(Clone, Debug, Default)]
77pub struct TableRow {
78 cells: Vec<TableCell>,
79 height: Option<f64>,
80}
81
82impl TableRow {
83 pub fn new() -> Self {
84 Self::default()
85 }
86
87 pub fn cell(mut self, cell: TableCell) -> Self {
88 self.cells.push(cell);
89 self
90 }
91
92 pub fn height(mut self, h: f64) -> Self {
93 self.height = Some(h);
94 self
95 }
96}
97
98#[derive(Clone, Debug)]
99pub struct TableBuilder {
100 rows: Vec<TableRow>,
101 x: f64,
102 y: f64,
103 column_widths: Vec<f64>,
104}
105
106impl TableBuilder {
107 pub fn new(x: f64, y: f64) -> Self {
108 Self {
109 rows: Vec::new(),
110 x,
111 y,
112 column_widths: Vec::new(),
113 }
114 }
115
116 pub fn column_widths(mut self, widths: &[f64]) -> Self {
117 self.column_widths = widths.to_vec();
118 self
119 }
120
121 pub fn row(mut self, row: TableRow) -> Self {
122 self.rows.push(row);
123 self
124 }
125
126 #[cfg_attr(feature = "tracing", instrument)]
127 pub fn finish(self) -> Vec<u8> {
128 let mut canvas = Canvas::new();
129 let mut y = self.y;
130
131 let num_cols = self
132 .rows
133 .iter()
134 .map(|row| row.cells.len())
135 .max()
136 .unwrap_or(0);
137 let col_widths = if !self.column_widths.is_empty() && self.column_widths.len() == num_cols {
138 self.column_widths.clone()
139 } else {
140 let total_width = PageSize::A4.width - 144.0;
141 vec![total_width / num_cols as f64; num_cols]
142 };
143
144 for row in &self.rows {
145 let row_height = row.height.unwrap_or(30.0);
146 let mut x = self.x;
147 for (i, cell) in row.cells.iter().enumerate() {
148 let cell_width = cell.width.unwrap_or(col_widths[i]);
149 if let Some(bg) = cell.background {
150 canvas = canvas.fill_color(bg);
151 canvas = canvas.rect(x, y, cell_width, row_height);
152 canvas = canvas.fill();
153 }
154 if cell.border.enabled {
155 canvas = canvas.stroke_color(cell.border.color);
156 canvas = canvas.line_width(cell.border.width);
157 canvas = canvas.rect(x, y, cell_width, row_height);
158 canvas = canvas.stroke();
159 }
160 x += cell_width;
161 }
162 y -= row_height;
163 }
164 canvas.finish()
165 }
166}