ppt_rs/generator/text/
format.rs

1//! Text formatting options
2
3/// Text formatting options
4#[derive(Clone, Debug, Default)]
5pub struct TextFormat {
6    pub bold: bool,
7    pub italic: bool,
8    pub underline: bool,
9    pub color: Option<String>,      // RGB hex color (e.g., "FF0000" for red)
10    pub font_size: Option<u32>,     // in points
11    pub font_family: Option<String>, // Font family name (e.g., "Arial")
12}
13
14impl TextFormat {
15    /// Create a new text format with default settings
16    pub fn new() -> Self {
17        Self::default()
18    }
19
20    /// Set bold formatting
21    pub fn bold(mut self) -> Self {
22        self.bold = true;
23        self
24    }
25
26    /// Set italic formatting
27    pub fn italic(mut self) -> Self {
28        self.italic = true;
29        self
30    }
31
32    /// Set underline formatting
33    pub fn underline(mut self) -> Self {
34        self.underline = true;
35        self
36    }
37
38    /// Set text color (RGB hex format)
39    pub fn color(mut self, hex_color: &str) -> Self {
40        self.color = Some(hex_color.trim_start_matches('#').to_uppercase());
41        self
42    }
43
44    /// Set font size in points
45    pub fn font_size(mut self, size: u32) -> Self {
46        self.font_size = Some(size);
47        self
48    }
49
50    /// Set font family
51    pub fn font_family(mut self, family: &str) -> Self {
52        self.font_family = Some(family.to_string());
53        self
54    }
55
56    /// Generate XML attributes for text formatting
57    pub fn to_xml_attrs(&self) -> String {
58        let mut attrs = String::new();
59
60        if self.bold {
61            attrs.push_str(" b=\"1\"");
62        }
63
64        if self.italic {
65            attrs.push_str(" i=\"1\"");
66        }
67
68        if self.underline {
69            attrs.push_str(" u=\"sng\"");
70        }
71
72        if let Some(size) = self.font_size {
73            attrs.push_str(&format!(" sz=\"{}\"", size * 100));
74        }
75
76        attrs
77    }
78}
79
80/// Formatted text with styling
81#[derive(Clone, Debug)]
82pub struct FormattedText {
83    pub text: String,
84    pub format: TextFormat,
85}
86
87impl FormattedText {
88    /// Create new formatted text
89    pub fn new(text: &str) -> Self {
90        FormattedText {
91            text: text.to_string(),
92            format: TextFormat::default(),
93        }
94    }
95
96    /// Apply formatting
97    pub fn with_format(mut self, format: TextFormat) -> Self {
98        self.format = format;
99        self
100    }
101
102    /// Builder method for bold
103    pub fn bold(mut self) -> Self {
104        self.format = self.format.bold();
105        self
106    }
107
108    /// Builder method for italic
109    pub fn italic(mut self) -> Self {
110        self.format = self.format.italic();
111        self
112    }
113
114    /// Builder method for underline
115    pub fn underline(mut self) -> Self {
116        self.format = self.format.underline();
117        self
118    }
119
120    /// Builder method for color
121    pub fn color(mut self, hex_color: &str) -> Self {
122        self.format = self.format.color(hex_color);
123        self
124    }
125
126    /// Builder method for font size
127    pub fn font_size(mut self, size: u32) -> Self {
128        self.format = self.format.font_size(size);
129        self
130    }
131}
132
133/// Generate XML color element
134pub fn color_to_xml(hex_color: &str) -> String {
135    let clean_color = hex_color.trim_start_matches('#').to_uppercase();
136    format!("<a:solidFill><a:srgbClr val=\"{}\"/></a:solidFill>", clean_color)
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    #[test]
144    fn test_text_format_builder() {
145        let format = TextFormat::new()
146            .bold()
147            .italic()
148            .color("FF0000")
149            .font_size(24);
150
151        assert!(format.bold);
152        assert!(format.italic);
153        assert_eq!(format.color, Some("FF0000".to_string()));
154        assert_eq!(format.font_size, Some(24));
155    }
156
157    #[test]
158    fn test_formatted_text_builder() {
159        let text = FormattedText::new("Hello")
160            .bold()
161            .italic()
162            .color("0000FF");
163
164        assert_eq!(text.text, "Hello");
165        assert!(text.format.bold);
166        assert!(text.format.italic);
167        assert_eq!(text.format.color, Some("0000FF".to_string()));
168    }
169
170    #[test]
171    fn test_format_to_xml_attrs() {
172        let format = TextFormat::new().bold().italic().font_size(24);
173        let attrs = format.to_xml_attrs();
174        assert!(attrs.contains("b=\"1\""));
175        assert!(attrs.contains("i=\"1\""));
176        assert!(attrs.contains("sz=\"2400\""));
177    }
178
179    #[test]
180    fn test_color_to_xml() {
181        let xml = color_to_xml("FF0000");
182        assert!(xml.contains("FF0000"));
183        assert!(xml.contains("srgbClr"));
184    }
185}