1pub use crate::generator::{
22 SlideContent, SlideLayout,
23 Shape, ShapeType, ShapeFill, ShapeLine,
24 Image,
25 Connector, ConnectorType, ArrowType,
26 create_pptx, create_pptx_with_content,
27};
28
29pub use crate::generator::shapes::{
30 GradientFill, GradientDirection, GradientStop,
31};
32
33pub use crate::elements::{Color, RgbColor, Position, Size};
34pub use crate::exc::Result;
35
36#[macro_export]
38macro_rules! pptx {
39 ($title:expr) => {
40 $crate::prelude::QuickPptx::new($title)
41 };
42}
43
44#[macro_export]
46macro_rules! shape {
47 (rect $x:expr, $y:expr, $w:expr, $h:expr) => {
49 $crate::prelude::Shape::new(
50 $crate::prelude::ShapeType::Rectangle,
51 $crate::prelude::inches($x),
52 $crate::prelude::inches($y),
53 $crate::prelude::inches($w),
54 $crate::prelude::inches($h),
55 )
56 };
57 (circle $x:expr, $y:expr, $size:expr) => {
59 $crate::prelude::Shape::new(
60 $crate::prelude::ShapeType::Circle,
61 $crate::prelude::inches($x),
62 $crate::prelude::inches($y),
63 $crate::prelude::inches($size),
64 $crate::prelude::inches($size),
65 )
66 };
67}
68
69pub fn inches(val: f64) -> u32 {
71 (val * 914400.0) as u32
72}
73
74pub fn cm(val: f64) -> u32 {
76 (val * 360000.0) as u32
77}
78
79pub fn pt(val: f64) -> u32 {
81 (val * 12700.0) as u32
82}
83
84pub struct QuickPptx {
86 title: String,
87 slides: Vec<SlideContent>,
88}
89
90impl QuickPptx {
91 pub fn new(title: &str) -> Self {
93 QuickPptx {
94 title: title.to_string(),
95 slides: Vec::new(),
96 }
97 }
98
99 pub fn slide(mut self, title: &str, bullets: &[&str]) -> Self {
101 let mut slide = SlideContent::new(title);
102 for bullet in bullets {
103 slide = slide.add_bullet(*bullet);
104 }
105 self.slides.push(slide);
106 self
107 }
108
109 pub fn title_slide(mut self, title: &str) -> Self {
111 self.slides.push(SlideContent::new(title));
112 self
113 }
114
115 pub fn content_slide(mut self, slide: SlideContent) -> Self {
117 self.slides.push(slide);
118 self
119 }
120
121 pub fn shapes_slide(mut self, title: &str, shapes: Vec<Shape>) -> Self {
123 let slide = SlideContent::new(title).with_shapes(shapes);
124 self.slides.push(slide);
125 self
126 }
127
128 pub fn build(self) -> std::result::Result<Vec<u8>, Box<dyn std::error::Error>> {
130 if self.slides.is_empty() {
131 create_pptx(&self.title, 1)
133 } else {
134 create_pptx_with_content(&self.title, self.slides)
135 }
136 }
137
138 pub fn save(self, path: &str) -> std::result::Result<(), Box<dyn std::error::Error>> {
140 let data = self.build()?;
141 std::fs::write(path, data)?;
142 Ok(())
143 }
144}
145
146
147pub mod shapes {
149 use super::*;
150
151 pub fn rect(x: f64, y: f64, width: f64, height: f64) -> Shape {
153 Shape::new(ShapeType::Rectangle, inches(x), inches(y), inches(width), inches(height))
154 }
155
156 pub fn circle(x: f64, y: f64, diameter: f64) -> Shape {
158 Shape::new(ShapeType::Circle, inches(x), inches(y), inches(diameter), inches(diameter))
159 }
160
161 pub fn rounded_rect(x: f64, y: f64, width: f64, height: f64) -> Shape {
163 Shape::new(ShapeType::RoundedRectangle, inches(x), inches(y), inches(width), inches(height))
164 }
165
166 pub fn text_box(x: f64, y: f64, width: f64, height: f64, text: &str) -> Shape {
168 Shape::new(ShapeType::Rectangle, inches(x), inches(y), inches(width), inches(height))
169 .with_text(text)
170 }
171
172 pub fn colored(shape: Shape, fill: &str, line: Option<&str>) -> Shape {
174 let mut s = shape.with_fill(ShapeFill::new(fill));
175 if let Some(l) = line {
176 s = s.with_line(ShapeLine::new(l, 12700));
177 }
178 s
179 }
180
181 pub fn gradient(shape: Shape, start: &str, end: &str, direction: GradientDirection) -> Shape {
183 shape.with_gradient(GradientFill::linear(start, end, direction))
184 }
185}
186
187pub mod colors {
189 pub const RED: &str = "FF0000";
190 pub const GREEN: &str = "00FF00";
191 pub const BLUE: &str = "0000FF";
192 pub const WHITE: &str = "FFFFFF";
193 pub const BLACK: &str = "000000";
194 pub const GRAY: &str = "808080";
195 pub const LIGHT_GRAY: &str = "D3D3D3";
196 pub const DARK_GRAY: &str = "404040";
197 pub const YELLOW: &str = "FFFF00";
198 pub const ORANGE: &str = "FFA500";
199 pub const PURPLE: &str = "800080";
200 pub const CYAN: &str = "00FFFF";
201 pub const MAGENTA: &str = "FF00FF";
202 pub const NAVY: &str = "000080";
203 pub const TEAL: &str = "008080";
204 pub const OLIVE: &str = "808000";
205
206 pub const CORPORATE_BLUE: &str = "1565C0";
208 pub const CORPORATE_GREEN: &str = "2E7D32";
209 pub const CORPORATE_RED: &str = "C62828";
210 pub const CORPORATE_ORANGE: &str = "EF6C00";
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216
217 #[test]
218 fn test_quick_pptx() {
219 let result = QuickPptx::new("Test")
220 .slide("Slide 1", &["Point 1", "Point 2"])
221 .build();
222 assert!(result.is_ok());
223 }
224
225 #[test]
226 fn test_inches_conversion() {
227 assert_eq!(inches(1.0), 914400);
228 assert_eq!(cm(2.54), 914400); }
230
231 #[test]
232 fn test_shape_builders() {
233 let rect = shapes::rect(1.0, 1.0, 2.0, 1.0);
234 assert_eq!(rect.width, inches(2.0));
235
236 let circle = shapes::circle(1.0, 1.0, 1.0);
237 assert_eq!(circle.width, circle.height);
238 }
239}