1use crate::error::PdfError;
6use crate::graphics::Color;
7use crate::page::Page;
8use crate::text::{Font, HeaderStyle, Table, TableOptions};
9
10pub trait PageTables {
12 fn add_simple_table(&mut self, table: &Table, x: f64, y: f64) -> Result<&mut Self, PdfError>;
14
15 fn add_quick_table(
17 &mut self,
18 data: Vec<Vec<String>>,
19 x: f64,
20 y: f64,
21 width: f64,
22 options: Option<TableOptions>,
23 ) -> Result<&mut Self, PdfError>;
24
25 fn add_styled_table(
27 &mut self,
28 headers: Vec<String>,
29 data: Vec<Vec<String>>,
30 x: f64,
31 y: f64,
32 width: f64,
33 style: TableStyle,
34 ) -> Result<&mut Self, PdfError>;
35}
36
37#[derive(Debug, Clone)]
39pub struct TableStyle {
40 pub header_background: Option<Color>,
42 pub header_text_color: Option<Color>,
44 pub font_size: f64,
46}
47
48impl TableStyle {
49 pub fn minimal() -> Self {
51 Self {
52 header_background: None,
53 header_text_color: None,
54 font_size: 10.0,
55 }
56 }
57
58 pub fn simple() -> Self {
60 Self {
61 header_background: None,
62 header_text_color: None,
63 font_size: 10.0,
64 }
65 }
66
67 pub fn professional() -> Self {
69 Self {
70 header_background: Some(Color::gray(0.1)),
71 header_text_color: Some(Color::white()),
72 font_size: 10.0,
73 }
74 }
75
76 pub fn colorful() -> Self {
78 Self {
79 header_background: Some(Color::rgb(0.2, 0.4, 0.8)),
80 header_text_color: Some(Color::white()),
81 font_size: 10.0,
82 }
83 }
84}
85
86impl PageTables for Page {
87 fn add_simple_table(&mut self, table: &Table, x: f64, y: f64) -> Result<&mut Self, PdfError> {
88 let mut table_clone = table.clone();
89 table_clone.set_position(x, y);
90 table_clone.render(self.graphics())?;
91 Ok(self)
92 }
93
94 fn add_quick_table(
95 &mut self,
96 data: Vec<Vec<String>>,
97 x: f64,
98 y: f64,
99 width: f64,
100 options: Option<TableOptions>,
101 ) -> Result<&mut Self, PdfError> {
102 if data.is_empty() {
103 return Ok(self);
104 }
105
106 let num_columns = data[0].len();
107 let mut table = Table::with_equal_columns(num_columns, width);
108
109 if let Some(opts) = options {
110 table.set_options(opts);
111 }
112
113 for row in data {
114 table.add_row(row)?;
115 }
116
117 self.add_simple_table(&table, x, y)
118 }
119
120 fn add_styled_table(
121 &mut self,
122 headers: Vec<String>,
123 data: Vec<Vec<String>>,
124 x: f64,
125 y: f64,
126 width: f64,
127 style: TableStyle,
128 ) -> Result<&mut Self, PdfError> {
129 let num_columns = headers.len();
130 if num_columns == 0 {
131 return Ok(self);
132 }
133
134 let mut table = Table::with_equal_columns(num_columns, width);
136
137 let header_style = if style.header_background.is_some() || style.header_text_color.is_some()
139 {
140 Some(HeaderStyle {
141 background_color: style.header_background.unwrap_or(Color::white()),
142 text_color: style.header_text_color.unwrap_or(Color::black()),
143 font: Font::Helvetica,
144 bold: true,
145 })
146 } else {
147 None
148 };
149
150 let options = TableOptions {
151 font_size: style.font_size,
152 header_style,
153 ..Default::default()
154 };
155
156 table.set_options(options);
157
158 table.add_row(headers)?;
160
161 for row_data in data {
163 table.add_row(row_data)?;
164 }
165
166 self.add_simple_table(&table, x, y)
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173 use crate::page::Page;
174
175 #[test]
176 fn test_page_tables_trait() {
177 let mut page = Page::a4();
178
179 let data = vec![
181 vec!["Name".to_string(), "Age".to_string()],
182 vec!["John".to_string(), "30".to_string()],
183 ];
184
185 let result = page.add_quick_table(data, 50.0, 700.0, 400.0, None);
186 assert!(result.is_ok());
187 }
188
189 #[test]
190 fn test_table_styles() {
191 let minimal = TableStyle::minimal();
192 assert_eq!(minimal.font_size, 10.0);
193
194 let simple = TableStyle::simple();
195 assert_eq!(simple.font_size, 10.0);
196
197 let professional = TableStyle::professional();
198 assert!(professional.header_background.is_some());
199
200 let colorful = TableStyle::colorful();
201 assert!(colorful.header_background.is_some());
202 }
203
204 #[test]
205 fn test_styled_table() {
206 let mut page = Page::a4();
207
208 let headers = vec!["Column 1".to_string(), "Column 2".to_string()];
209 let data = vec![
210 vec!["Data 1".to_string(), "Data 2".to_string()],
211 vec!["Data 3".to_string(), "Data 4".to_string()],
212 ];
213
214 let result = page.add_styled_table(
215 headers,
216 data,
217 50.0,
218 700.0,
219 500.0,
220 TableStyle::professional(),
221 );
222
223 assert!(result.is_ok());
224 }
225
226 #[test]
227 fn test_empty_table() {
228 let mut page = Page::a4();
229
230 let data: Vec<Vec<String>> = vec![];
231 let result = page.add_quick_table(data, 50.0, 700.0, 400.0, None);
232 assert!(result.is_ok());
233 }
234}