Skip to main content

graphitepdf_kit/
table.rs

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}