Skip to main content

lopdf_table/
style.rs

1//! Styling structures for tables, rows, and cells
2
3use crate::constants::DEFAULT_MARGIN;
4
5/// RGB color representation
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Color {
8    pub r: f32,
9    pub g: f32,
10    pub b: f32,
11}
12
13impl Color {
14    /// Create a new RGB color (values should be 0.0-1.0)
15    pub fn rgb(r: f32, g: f32, b: f32) -> Self {
16        Self {
17            r: r.clamp(0.0, 1.0),
18            g: g.clamp(0.0, 1.0),
19            b: b.clamp(0.0, 1.0),
20        }
21    }
22
23    /// Black color
24    pub fn black() -> Self {
25        Self::rgb(0.0, 0.0, 0.0)
26    }
27
28    /// White color
29    pub fn white() -> Self {
30        Self::rgb(1.0, 1.0, 1.0)
31    }
32
33    /// Gray color
34    pub fn gray(level: f32) -> Self {
35        let l = level.clamp(0.0, 1.0);
36        Self::rgb(l, l, l)
37    }
38
39    /// Light gray
40    pub fn light_gray() -> Self {
41        Self::gray(0.8)
42    }
43}
44
45impl Default for Color {
46    fn default() -> Self {
47        Self::black()
48    }
49}
50
51/// Text alignment options
52#[derive(Debug, Clone, Copy, PartialEq)]
53pub enum Alignment {
54    Left,
55    Center,
56    Right,
57}
58
59impl Default for Alignment {
60    fn default() -> Self {
61        Self::Left
62    }
63}
64
65/// Vertical alignment options
66#[derive(Debug, Clone, Copy, PartialEq)]
67pub enum VerticalAlignment {
68    Top,
69    Middle,
70    Bottom,
71}
72
73impl Default for VerticalAlignment {
74    fn default() -> Self {
75        Self::Middle
76    }
77}
78
79/// Border style options
80#[derive(Debug, Clone, Copy, PartialEq)]
81pub enum BorderStyle {
82    None,
83    Solid,
84    Dashed,
85    Dotted,
86}
87
88impl Default for BorderStyle {
89    fn default() -> Self {
90        Self::Solid
91    }
92}
93
94/// Padding for cells
95#[derive(Debug, Clone, Copy)]
96pub struct Padding {
97    pub top: f32,
98    pub right: f32,
99    pub bottom: f32,
100    pub left: f32,
101}
102
103impl Padding {
104    /// Create uniform padding
105    pub fn uniform(value: f32) -> Self {
106        Self {
107            top: value,
108            right: value,
109            bottom: value,
110            left: value,
111        }
112    }
113
114    /// Create padding with vertical and horizontal values
115    pub fn symmetric(vertical: f32, horizontal: f32) -> Self {
116        Self {
117            top: vertical,
118            bottom: vertical,
119            left: horizontal,
120            right: horizontal,
121        }
122    }
123}
124
125impl Default for Padding {
126    fn default() -> Self {
127        Self::uniform(5.0)
128    }
129}
130
131/// Styling for the entire table
132#[derive(Debug, Clone)]
133pub struct TableStyle {
134    pub border_style: BorderStyle,
135    pub border_width: f32,
136    pub border_color: Color,
137    pub background_color: Option<Color>,
138    pub padding: Padding,
139    /// Default font for the table
140    pub font_name: String,
141    pub default_font_size: f32,
142    /// Page height for pagination (if None, uses standard A4: 842 points)
143    pub page_height: Option<f32>,
144    /// Top margin for pages
145    pub top_margin: f32,
146    /// Bottom margin for pages
147    pub bottom_margin: f32,
148    /// Whether to repeat header rows on new pages
149    pub repeat_headers: bool,
150    /// PDF resource name for an embedded font (e.g., "EF0").
151    /// When set together with `font_metrics` on the Table, text will be
152    /// encoded as glyph IDs and rendered using this font resource.
153    pub embedded_font_resource_name: Option<String>,
154    /// PDF resource name for a bold embedded font (e.g., "EF0B").
155    /// When set and a cell is marked bold, this font resource is used.
156    pub embedded_font_resource_name_bold: Option<String>,
157}
158
159impl Default for TableStyle {
160    fn default() -> Self {
161        Self {
162            border_style: BorderStyle::Solid,
163            border_width: 1.0,
164            border_color: Color::black(),
165            background_color: None,
166            padding: Padding::default(),
167            font_name: "Helvetica".to_string(),
168            default_font_size: 10.0,
169            page_height: None, // Will default to A4 (842 points)
170            top_margin: DEFAULT_MARGIN,
171            bottom_margin: DEFAULT_MARGIN,
172            repeat_headers: true,
173            embedded_font_resource_name: None,
174            embedded_font_resource_name_bold: None,
175        }
176    }
177}
178
179/// Styling for a row
180#[derive(Debug, Clone)]
181pub struct RowStyle {
182    pub background_color: Option<Color>,
183    pub border_top: Option<(BorderStyle, f32, Color)>,
184    pub border_bottom: Option<(BorderStyle, f32, Color)>,
185    pub height: Option<f32>,
186}
187
188impl Default for RowStyle {
189    fn default() -> Self {
190        Self {
191            background_color: None,
192            border_top: None,
193            border_bottom: None,
194            height: None,
195        }
196    }
197}
198
199/// Styling for a cell
200#[derive(Debug, Clone)]
201pub struct CellStyle {
202    pub background_color: Option<Color>,
203    pub text_color: Color,
204    pub font_size: Option<f32>,
205    /// Font name for this cell. If None, inherits from table's font_name.
206    /// Supported fonts: "Helvetica", "Courier", "Times-Roman" (and their bold variants)
207    pub font_name: Option<String>,
208    pub bold: bool,
209    pub italic: bool,
210    pub alignment: Alignment,
211    pub vertical_alignment: VerticalAlignment,
212    pub padding: Option<Padding>,
213    pub border_left: Option<(BorderStyle, f32, Color)>,
214    pub border_right: Option<(BorderStyle, f32, Color)>,
215    pub border_top: Option<(BorderStyle, f32, Color)>,
216    pub border_bottom: Option<(BorderStyle, f32, Color)>,
217    /// Override the embedded font resource name for this cell (e.g., "EF0").
218    /// If None, inherits from the table style's `embedded_font_resource_name`.
219    pub embedded_font_resource_name: Option<String>,
220}
221
222impl Default for CellStyle {
223    fn default() -> Self {
224        Self {
225            background_color: None,
226            text_color: Color::black(),
227            font_size: None,
228            font_name: None,
229            bold: false,
230            italic: false,
231            alignment: Alignment::Left,
232            vertical_alignment: VerticalAlignment::Middle,
233            padding: None,
234            border_left: None,
235            border_right: None,
236            border_top: None,
237            border_bottom: None,
238            embedded_font_resource_name: None,
239        }
240    }
241}
242
243impl CellStyle {
244    /// Create a header cell style (bold, centered)
245    pub fn header() -> Self {
246        Self {
247            bold: true,
248            alignment: Alignment::Center,
249            background_color: Some(Color::light_gray()),
250            ..Default::default()
251        }
252    }
253}