Skip to main content

ppt_rs/helpers/
tables.rs

1//! Simplified table creation utilities
2//!
3//! This module provides easy-to-use helpers for creating tables with minimal boilerplate.
4
5use crate::generator::{TableBuilder, TableCell, TableRow};
6
7/// Create a simple table with the specified number of rows and columns
8///
9/// # Example
10/// ```
11/// use ppt_rs::helpers::tables::simple_table;
12///
13/// let table = simple_table(3, 4); // 3 rows, 4 columns with equal widths
14/// ```
15pub fn simple_table(rows: usize, cols: usize) -> TableBuilder {
16    let col_width = 9144000 / cols as u32; // Divide slide width equally
17    let column_widths = vec![col_width; cols];
18    let mut builder = TableBuilder::new(column_widths);
19
20    // Add empty rows
21    for _ in 0..rows {
22        let cells = (0..cols).map(|_| TableCell::new("")).collect();
23        builder = builder.add_row(TableRow::new(cells));
24    }
25
26    builder
27}
28
29/// Create a table with custom column widths (in inches)
30///
31/// # Example
32/// ```
33/// use ppt_rs::helpers::tables::table_with_widths;
34///
35/// let table = table_with_widths(&[2.0, 3.0, 2.5]); // 3 columns with specific widths
36/// ```
37pub fn table_with_widths(widths_inches: &[f64]) -> TableBuilder {
38    let column_widths: Vec<u32> = widths_inches
39        .iter()
40        .map(|w| (w * 914400.0) as u32)
41        .collect();
42    TableBuilder::new(column_widths)
43}
44
45/// Create a table from a 2D array of data
46///
47/// # Example
48/// ```
49/// use ppt_rs::helpers::tables::table_from_data;
50///
51/// let data = vec![
52///     vec!["Name", "Age", "City"],
53///     vec!["Alice", "30", "NYC"],
54///     vec!["Bob", "25", "LA"],
55/// ];
56/// let table = table_from_data(&data, None);
57/// ```
58pub fn table_from_data(data: &[Vec<&str>], column_widths: Option<Vec<f64>>) -> TableBuilder {
59    if data.is_empty() {
60        return simple_table(0, 0);
61    }
62
63    let cols = data[0].len();
64    let widths = if let Some(widths) = column_widths {
65        widths.iter().map(|w| (w * 914400.0) as u32).collect()
66    } else {
67        let col_width = 9144000 / cols as u32;
68        vec![col_width; cols]
69    };
70
71    let mut builder = TableBuilder::new(widths);
72
73    for row_data in data {
74        let cells: Vec<TableCell> = row_data.iter().map(|&text| TableCell::new(text)).collect();
75        builder = builder.add_row(TableRow::new(cells));
76    }
77
78    builder
79}
80
81/// Create a table with a header row
82///
83/// # Example
84/// ```
85/// use ppt_rs::helpers::tables::table_with_header;
86///
87/// let headers = vec!["Name", "Age", "City"];
88/// let table = table_with_header(&headers, 5); // Header + 5 data rows
89/// ```
90pub fn table_with_header(headers: &[&str], data_rows: usize) -> TableBuilder {
91    let cols = headers.len();
92    let col_width = 9144000 / cols as u32;
93    let column_widths = vec![col_width; cols];
94
95    let mut builder = TableBuilder::new(column_widths);
96
97    // Add header row with styling
98    let header_cells: Vec<TableCell> = headers
99        .iter()
100        .map(|&text| {
101            TableCell::new(text)
102                .bold()
103                .background_color("1F4E79")
104                .text_color("FFFFFF")
105                .align_center()
106        })
107        .collect();
108    builder = builder.add_row(TableRow::new(header_cells));
109
110    // Add empty data rows
111    for _ in 0..data_rows {
112        let cells = (0..cols).map(|_| TableCell::new("")).collect();
113        builder = builder.add_row(TableRow::new(cells));
114    }
115
116    builder
117}
118
119/// Quick table builder for common patterns
120pub struct QuickTable {
121    builder: TableBuilder,
122    #[allow(dead_code)]
123    cols: usize,
124}
125
126impl QuickTable {
127    /// Create a new quick table with equal column widths
128    pub fn new(cols: usize) -> Self {
129        let col_width = 9144000 / cols as u32;
130        let column_widths = vec![col_width; cols];
131        Self {
132            builder: TableBuilder::new(column_widths),
133            cols,
134        }
135    }
136
137    /// Create with custom column widths in inches
138    pub fn with_widths(widths_inches: &[f64]) -> Self {
139        let column_widths: Vec<u32> = widths_inches
140            .iter()
141            .map(|w| (w * 914400.0) as u32)
142            .collect();
143        Self {
144            builder: TableBuilder::new(column_widths.clone()),
145            cols: column_widths.len(),
146        }
147    }
148
149    /// Add a header row with automatic styling
150    pub fn header(mut self, headers: &[&str]) -> Self {
151        let cells: Vec<TableCell> = headers
152            .iter()
153            .map(|&text| {
154                TableCell::new(text)
155                    .bold()
156                    .background_color("1F4E79")
157                    .text_color("FFFFFF")
158                    .align_center()
159            })
160            .collect();
161        self.builder = self.builder.add_row(TableRow::new(cells));
162        self
163    }
164
165    /// Add a data row
166    pub fn row(mut self, data: &[&str]) -> Self {
167        let cells: Vec<TableCell> = data.iter().map(|&text| TableCell::new(text)).collect();
168        self.builder = self.builder.add_row(TableRow::new(cells));
169        self
170    }
171
172    /// Add a styled row with custom cell styling
173    pub fn styled_row(mut self, cells: Vec<TableCell>) -> Self {
174        self.builder = self.builder.add_row(TableRow::new(cells));
175        self
176    }
177
178    /// Add multiple rows at once
179    pub fn rows(mut self, data: &[Vec<&str>]) -> Self {
180        for row_data in data {
181            let cells: Vec<TableCell> = row_data.iter().map(|&text| TableCell::new(text)).collect();
182            self.builder = self.builder.add_row(TableRow::new(cells));
183        }
184        self
185    }
186
187    /// Set the table position (in inches)
188    pub fn at(mut self, x: f64, y: f64) -> Self {
189        self.builder = self
190            .builder
191            .position((x * 914400.0) as u32, (y * 914400.0) as u32);
192        self
193    }
194
195    /// Build the final table
196    pub fn build(self) -> crate::generator::Table {
197        self.builder.build()
198    }
199}
200
201/// Helper to create a cell with common styling
202pub fn cell(text: &str) -> TableCell {
203    TableCell::new(text)
204}
205
206/// Helper to create a header cell
207pub fn header_cell(text: &str) -> TableCell {
208    TableCell::new(text)
209        .bold()
210        .background_color("1F4E79")
211        .text_color("FFFFFF")
212        .align_center()
213}
214
215/// Helper to create a highlighted cell
216pub fn highlight_cell(text: &str, color: &str) -> TableCell {
217    TableCell::new(text).background_color(color).bold()
218}
219
220#[cfg(test)]
221mod tests {
222    use super::*;
223
224    #[test]
225    fn test_simple_table() {
226        let _table = simple_table(3, 4);
227        // Table should be created successfully
228    }
229
230    #[test]
231    fn test_table_with_widths() {
232        let _table = table_with_widths(&[2.0, 3.0, 2.5]);
233        // Table should be created with custom widths
234    }
235
236    #[test]
237    fn test_table_from_data() {
238        let data = vec![
239            vec!["Name", "Age", "City"],
240            vec!["Alice", "30", "NYC"],
241            vec!["Bob", "25", "LA"],
242        ];
243        let _table = table_from_data(&data, None);
244        // Table should be created from data
245    }
246
247    #[test]
248    fn test_quick_table() {
249        let _table = QuickTable::new(3)
250            .header(&["Name", "Age", "City"])
251            .row(&["Alice", "30", "NYC"])
252            .row(&["Bob", "25", "LA"])
253            .at(0.5, 1.5)
254            .build();
255        // Table should be built successfully
256    }
257}