Skip to main content

ppt_rs/generator/slide_content/
bullet.rs

1//! Bullet point types and formatting
2
3use crate::core::ToXml;
4
5/// Bullet style for lists
6#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]
7pub enum BulletStyle {
8    /// Standard bullet point (•)
9    #[default]
10    Bullet,
11    /// Numbered list (1, 2, 3...)
12    Number,
13    /// Lettered list (a, b, c...)
14    LetterLower,
15    /// Lettered list uppercase (A, B, C...)
16    LetterUpper,
17    /// Roman numerals lowercase (i, ii, iii...)
18    RomanLower,
19    /// Roman numerals uppercase (I, II, III...)
20    RomanUpper,
21    /// Custom bullet character
22    Custom(char),
23    /// No bullet
24    None,
25}
26
27impl BulletStyle {
28    /// Get the OOXML bullet type attribute
29    pub fn to_xml(&self) -> String {
30        match self {
31            BulletStyle::Bullet => r#"<a:buChar char="•"/>"#.to_string(),
32            BulletStyle::Number => r#"<a:buAutoNum type="arabicPeriod"/>"#.to_string(),
33            BulletStyle::LetterLower => r#"<a:buAutoNum type="alphaLcPeriod"/>"#.to_string(),
34            BulletStyle::LetterUpper => r#"<a:buAutoNum type="alphaUcPeriod"/>"#.to_string(),
35            BulletStyle::RomanLower => r#"<a:buAutoNum type="romanLcPeriod"/>"#.to_string(),
36            BulletStyle::RomanUpper => r#"<a:buAutoNum type="romanUcPeriod"/>"#.to_string(),
37            BulletStyle::Custom(ch) => format!(r#"<a:buChar char="{}"/>"#, ch),
38            BulletStyle::None => r#"<a:buNone/>"#.to_string(),
39        }
40    }
41    
42    /// Get the OOXML indent level XML
43    pub fn indent_xml(&self, level: u32) -> String {
44        let indent = 457200 + (level * 457200); // 0.5 inch base + 0.5 inch per level
45        let margin_left = level * 457200;
46        format!(r#"indent="-{}" marL="{}""#, indent, margin_left + indent)
47    }
48}
49
50impl ToXml for BulletStyle {
51    fn to_xml(&self) -> String {
52        BulletStyle::to_xml(self)
53    }
54}
55
56/// Text formatting for bullet points
57#[derive(Clone, Debug, Default)]
58pub struct BulletTextFormat {
59    pub bold: bool,
60    pub italic: bool,
61    pub underline: bool,
62    pub strikethrough: bool,
63    pub subscript: bool,
64    pub superscript: bool,
65    pub color: Option<String>,
66    pub highlight: Option<String>,
67    pub font_size: Option<u32>,
68    pub font_family: Option<String>,
69}
70
71impl BulletTextFormat {
72    pub fn new() -> Self {
73        Self::default()
74    }
75    
76    pub fn bold(mut self) -> Self {
77        self.bold = true;
78        self
79    }
80    
81    pub fn italic(mut self) -> Self {
82        self.italic = true;
83        self
84    }
85    
86    pub fn underline(mut self) -> Self {
87        self.underline = true;
88        self
89    }
90    
91    pub fn strikethrough(mut self) -> Self {
92        self.strikethrough = true;
93        self
94    }
95    
96    pub fn subscript(mut self) -> Self {
97        self.subscript = true;
98        self.superscript = false;
99        self
100    }
101    
102    pub fn superscript(mut self) -> Self {
103        self.superscript = true;
104        self.subscript = false;
105        self
106    }
107    
108    pub fn color(mut self, hex: &str) -> Self {
109        self.color = Some(hex.trim_start_matches('#').to_uppercase());
110        self
111    }
112    
113    pub fn highlight(mut self, hex: &str) -> Self {
114        self.highlight = Some(hex.trim_start_matches('#').to_uppercase());
115        self
116    }
117    
118    pub fn font_size(mut self, size: u32) -> Self {
119        self.font_size = Some(size);
120        self
121    }
122    
123    pub fn font_family(mut self, family: &str) -> Self {
124        self.font_family = Some(family.to_string());
125        self
126    }
127}
128
129/// A bullet point with optional style and formatting
130#[derive(Clone, Debug)]
131pub struct BulletPoint {
132    pub text: String,
133    pub level: u32,
134    pub style: BulletStyle,
135    pub format: Option<BulletTextFormat>,
136}
137
138impl BulletPoint {
139    pub fn new(text: &str) -> Self {
140        BulletPoint {
141            text: text.to_string(),
142            level: 0,
143            style: BulletStyle::Bullet,
144            format: None,
145        }
146    }
147    
148    pub fn with_level(mut self, level: u32) -> Self {
149        self.level = level;
150        self
151    }
152    
153    pub fn with_style(mut self, style: BulletStyle) -> Self {
154        self.style = style;
155        self
156    }
157    
158    pub fn with_format(mut self, format: BulletTextFormat) -> Self {
159        self.format = Some(format);
160        self
161    }
162    
163    pub fn bold(mut self) -> Self {
164        self.format = Some(self.format.unwrap_or_default().bold());
165        self
166    }
167    
168    pub fn italic(mut self) -> Self {
169        self.format = Some(self.format.unwrap_or_default().italic());
170        self
171    }
172    
173    pub fn strikethrough(mut self) -> Self {
174        self.format = Some(self.format.unwrap_or_default().strikethrough());
175        self
176    }
177    
178    pub fn subscript(mut self) -> Self {
179        self.format = Some(self.format.unwrap_or_default().subscript());
180        self
181    }
182    
183    pub fn superscript(mut self) -> Self {
184        self.format = Some(self.format.unwrap_or_default().superscript());
185        self
186    }
187    
188    pub fn highlight(mut self, color: &str) -> Self {
189        self.format = Some(self.format.unwrap_or_default().highlight(color));
190        self
191    }
192    
193    pub fn color(mut self, hex: &str) -> Self {
194        self.format = Some(self.format.unwrap_or_default().color(hex));
195        self
196    }
197    
198    pub fn font_size(mut self, size: u32) -> Self {
199        self.format = Some(self.format.unwrap_or_default().font_size(size));
200        self
201    }
202}
203