Skip to main content

ppt_rs/generator/slide_content/
content.rs

1//! SlideContent struct for complex presentations
2
3use crate::generator::tables::Table;
4use crate::generator::shapes::Shape;
5use crate::generator::images::Image;
6use crate::generator::connectors::Connector;
7use crate::generator::media::{Video, Audio};
8use crate::generator::charts::Chart;
9
10use super::bullet::{BulletStyle, BulletPoint};
11use super::layout::SlideLayout;
12use super::code_block::CodeBlock;
13use super::transition::TransitionType;
14use super::ink_annotations::InkAnnotations;
15
16/// Slide content for more complex presentations
17#[derive(Clone, Debug)]
18pub struct SlideContent {
19    pub title: String,
20    pub content: Vec<String>,
21    /// Rich bullet points with styles and levels
22    pub bullets: Vec<BulletPoint>,
23    /// Default bullet style for this slide
24    pub bullet_style: BulletStyle,
25    pub title_size: Option<u32>,
26    pub content_size: Option<u32>,
27    pub title_bold: bool,
28    pub content_bold: bool,
29    pub title_italic: bool,
30    pub content_italic: bool,
31    pub title_underline: bool,
32    pub content_underline: bool,
33    pub title_color: Option<String>,
34    pub content_color: Option<String>,
35    pub has_table: bool,
36    pub has_chart: bool,
37    pub has_image: bool,
38    pub layout: SlideLayout,
39    pub transition: TransitionType,
40    pub table: Option<Table>,
41    pub shapes: Vec<Shape>,
42    pub images: Vec<Image>,
43    /// Speaker notes for the slide
44    pub notes: Option<String>,
45    /// Connectors between shapes
46    pub connectors: Vec<Connector>,
47    /// Videos embedded in slide
48    pub videos: Vec<Video>,
49    /// Audio files embedded in slide
50    pub audios: Vec<Audio>,
51    /// Charts embedded in slide
52    pub charts: Vec<Chart>,
53    /// Code blocks with syntax highlighting
54    pub code_blocks: Vec<CodeBlock>,
55    /// Ink annotations on the slide
56    pub ink_annotations: Option<InkAnnotations>,
57}
58
59impl SlideContent {
60    pub fn new(title: &str) -> Self {
61        SlideContent {
62            title: title.to_string(),
63            content: Vec::new(),
64            bullets: Vec::new(),
65            bullet_style: BulletStyle::Bullet,
66            title_size: Some(44),
67            content_size: Some(28),
68            title_bold: true,
69            content_bold: false,
70            title_italic: false,
71            content_italic: false,
72            title_underline: false,
73            content_underline: false,
74            title_color: None,
75            content_color: None,
76            has_table: false,
77            has_chart: false,
78            has_image: false,
79            layout: SlideLayout::TitleAndContent,
80            transition: TransitionType::None,
81            table: None,
82            shapes: Vec::new(),
83            images: Vec::new(),
84            notes: None,
85            connectors: Vec::new(),
86            videos: Vec::new(),
87            audios: Vec::new(),
88            charts: Vec::new(),
89            code_blocks: Vec::new(),
90            ink_annotations: None,
91        }
92    }
93
94    /// Set the slide transition
95    pub fn with_transition(mut self, transition: TransitionType) -> Self {
96        self.transition = transition;
97        self
98    }
99    
100    /// Add a bullet point with default style
101    pub fn add_bullet(mut self, text: &str) -> Self {
102        self.content.push(text.to_string());
103        self.bullets.push(BulletPoint::new(text).with_style(self.bullet_style));
104        self
105    }
106    
107    /// Add a bullet point with specific style
108    pub fn add_styled_bullet(mut self, text: &str, style: BulletStyle) -> Self {
109        self.content.push(text.to_string());
110        self.bullets.push(BulletPoint::new(text).with_style(style));
111        self
112    }
113    
114    /// Add a numbered item (shorthand for add_styled_bullet with Number)
115    pub fn add_numbered(mut self, text: &str) -> Self {
116        self.content.push(text.to_string());
117        self.bullets.push(BulletPoint::new(text).with_style(BulletStyle::Number));
118        self
119    }
120    
121    /// Add a lettered item (shorthand for add_styled_bullet with LetterLower)
122    pub fn add_lettered(mut self, text: &str) -> Self {
123        self.content.push(text.to_string());
124        self.bullets.push(BulletPoint::new(text).with_style(BulletStyle::LetterLower));
125        self
126    }
127    
128    /// Add a sub-bullet (indented)
129    pub fn add_sub_bullet(mut self, text: &str) -> Self {
130        self.content.push(format!("  {}", text));
131        self.bullets.push(BulletPoint::new(text).with_level(1).with_style(self.bullet_style));
132        self
133    }
134    
135    /// Set default bullet style for this slide
136    pub fn with_bullet_style(mut self, style: BulletStyle) -> Self {
137        self.bullet_style = style;
138        self
139    }
140
141    pub fn title_size(mut self, size: u32) -> Self {
142        self.title_size = Some(size);
143        self
144    }
145
146    pub fn content_size(mut self, size: u32) -> Self {
147        self.content_size = Some(size);
148        self
149    }
150
151    pub fn title_bold(mut self, bold: bool) -> Self {
152        self.title_bold = bold;
153        self
154    }
155
156    pub fn content_bold(mut self, bold: bool) -> Self {
157        self.content_bold = bold;
158        self
159    }
160
161    pub fn title_italic(mut self, italic: bool) -> Self {
162        self.title_italic = italic;
163        self
164    }
165
166    pub fn content_italic(mut self, italic: bool) -> Self {
167        self.content_italic = italic;
168        self
169    }
170
171    pub fn title_underline(mut self, underline: bool) -> Self {
172        self.title_underline = underline;
173        self
174    }
175
176    pub fn content_underline(mut self, underline: bool) -> Self {
177        self.content_underline = underline;
178        self
179    }
180
181    pub fn title_color(mut self, color: &str) -> Self {
182        self.title_color = Some(color.trim_start_matches('#').to_uppercase());
183        self
184    }
185
186    pub fn content_color(mut self, color: &str) -> Self {
187        self.content_color = Some(color.trim_start_matches('#').to_uppercase());
188        self
189    }
190
191    pub fn with_table(mut self) -> Self {
192        self.has_table = true;
193        self
194    }
195
196    pub fn with_chart(mut self) -> Self {
197        self.has_chart = true;
198        self
199    }
200
201    pub fn with_image(mut self) -> Self {
202        self.has_image = true;
203        self
204    }
205
206    pub fn layout(mut self, layout: SlideLayout) -> Self {
207        self.layout = layout;
208        self
209    }
210
211    pub fn table(mut self, table: Table) -> Self {
212        self.table = Some(table);
213        self.has_table = true;
214        self
215    }
216
217    /// Add a shape to the slide
218    pub fn add_shape(mut self, shape: Shape) -> Self {
219        self.shapes.push(shape);
220        self
221    }
222
223    /// Add multiple shapes to the slide
224    pub fn with_shapes(mut self, shapes: Vec<Shape>) -> Self {
225        self.shapes.extend(shapes);
226        self
227    }
228
229    /// Add an image to the slide
230    pub fn add_image(mut self, image: Image) -> Self {
231        self.images.push(image);
232        self.has_image = true;
233        self
234    }
235
236    /// Add multiple images to the slide
237    pub fn with_images(mut self, images: Vec<Image>) -> Self {
238        self.images.extend(images);
239        self.has_image = true;
240        self
241    }
242
243    /// Add speaker notes to the slide
244    pub fn notes(mut self, notes: &str) -> Self {
245        self.notes = Some(notes.to_string());
246        self
247    }
248
249    /// Check if slide has speaker notes
250    pub fn has_notes(&self) -> bool {
251        self.notes.is_some()
252    }
253
254    /// Add a connector to the slide
255    pub fn add_connector(mut self, connector: Connector) -> Self {
256        self.connectors.push(connector);
257        self
258    }
259
260    /// Add multiple connectors to the slide
261    pub fn with_connectors(mut self, connectors: Vec<Connector>) -> Self {
262        self.connectors.extend(connectors);
263        self
264    }
265
266    /// Add a video to the slide
267    pub fn add_video(mut self, video: Video) -> Self {
268        self.videos.push(video);
269        self
270    }
271
272    /// Add multiple videos to the slide
273    pub fn with_videos(mut self, videos: Vec<Video>) -> Self {
274        self.videos.extend(videos);
275        self
276    }
277
278    /// Add an audio file to the slide
279    pub fn add_audio(mut self, audio: Audio) -> Self {
280        self.audios.push(audio);
281        self
282    }
283
284    /// Add multiple audio files to the slide
285    pub fn with_audios(mut self, audios: Vec<Audio>) -> Self {
286        self.audios.extend(audios);
287        self
288    }
289
290    /// Add a chart to the slide
291    pub fn add_chart(mut self, chart: Chart) -> Self {
292        self.charts.push(chart);
293        self.has_chart = true;
294        self
295    }
296
297    /// Add multiple charts to the slide
298    pub fn with_charts(mut self, charts: Vec<Chart>) -> Self {
299        self.charts.extend(charts);
300        self.has_chart = true;
301        self
302    }
303
304    /// Add ink annotations to the slide
305    pub fn with_ink(mut self, ink: InkAnnotations) -> Self {
306        self.ink_annotations = Some(ink);
307        self
308    }
309
310    /// Check if slide has any media
311    pub fn has_media(&self) -> bool {
312        !self.videos.is_empty() || !self.audios.is_empty()
313    }
314
315    /// Check if slide has connectors
316    pub fn has_connectors(&self) -> bool {
317        !self.connectors.is_empty()
318    }
319}
320