Skip to main content

pptx_shapes_and_placeholders/
pptx_shapes_and_placeholders.rs

1//! PowerPoint shapes: a plain autoshape, a text box, a shape with a
2//! placeholder role (title/subtitle), and a shape with a clickable
3//! hyperlink. One slide per feature.
4//!
5//! Run with: `cargo run -p office-toolkit --example pptx_shapes_and_placeholders`
6
7use std::path::{Path, PathBuf};
8
9use office_toolkit::SaveToFile;
10use office_toolkit::drawing::{ShapeProperties, TextBody, TextParagraph, TextRun, Transform2D};
11use office_toolkit::powerpoint::{AutoShape, Placeholder, PlaceholderKind, Shape};
12use office_toolkit::prelude::*;
13
14fn main() -> office_toolkit::Result<()> {
15    let path = output_path("pptx_shapes_and_placeholders.pptx");
16
17    let plain_shape = AutoShape::new(2, "Plain autoshape")
18        .with_properties(
19            ShapeProperties::new().with_transform(
20                Transform2D::new()
21                    .with_offset(838_200, 838_200)
22                    .with_extent(5_000_000, 1_000_000),
23            ),
24        )
25        .with_text_body(
26            TextBody::new()
27                .with_paragraph(TextParagraph::new().with_run(TextRun::text("A plain autoshape."))),
28        );
29
30    let text_box = AutoShape::new(2, "Text box")
31        .with_text_box(true)
32        .with_properties(
33            ShapeProperties::new().with_transform(
34                Transform2D::new()
35                    .with_offset(838_200, 838_200)
36                    .with_extent(5_000_000, 1_000_000),
37            ),
38        )
39        .with_text_body(TextBody::new().with_paragraph(
40            TextParagraph::new().with_run(TextRun::text("A genuine text box (txBox=\"1\").")),
41        ));
42
43    let title = AutoShape::new(2, "Title placeholder")
44        .with_placeholder(Placeholder::new(PlaceholderKind::CenterTitle))
45        .with_properties(
46            ShapeProperties::new().with_transform(
47                Transform2D::new()
48                    .with_offset(838_200, 838_200)
49                    .with_extent(10_515_600, 1_325_563),
50            ),
51        )
52        .with_text_body(
53            TextBody::new()
54                .with_paragraph(TextParagraph::new().with_run(TextRun::text("Title placeholder"))),
55        );
56    let subtitle =
57        AutoShape::new(3, "Subtitle placeholder")
58            .with_placeholder(Placeholder::new(PlaceholderKind::SubTitle).with_index(1))
59            .with_properties(
60                ShapeProperties::new().with_transform(
61                    Transform2D::new()
62                        .with_offset(838_200, 2_400_000)
63                        .with_extent(10_515_600, 800_000),
64                ),
65            )
66            .with_text_body(TextBody::new().with_paragraph(
67                TextParagraph::new().with_run(TextRun::text("Subtitle placeholder")),
68            ));
69
70    let hyperlinked_shape = AutoShape::new(2, "Hyperlinked shape")
71        .with_hyperlink("https://www.rust-lang.org")
72        .with_properties(
73            ShapeProperties::new().with_transform(
74                Transform2D::new()
75                    .with_offset(838_200, 838_200)
76                    .with_extent(5_000_000, 1_000_000),
77            ),
78        )
79        .with_text_body(TextBody::new().with_paragraph(
80            TextParagraph::new().with_run(TextRun::text("Click this shape to open a link.")),
81        ));
82
83    let presentation = Presentation::new()
84        .with_slide(Slide::new().with_shape(Shape::AutoShape(plain_shape)))
85        .with_slide(Slide::new().with_shape(Shape::AutoShape(text_box)))
86        .with_slide(
87            Slide::new()
88                .with_shape(Shape::AutoShape(title))
89                .with_shape(Shape::AutoShape(subtitle)),
90        )
91        .with_slide(Slide::new().with_shape(Shape::AutoShape(hyperlinked_shape)));
92
93    presentation.save_to_file(&path)?;
94    println!("Wrote {}", path.display());
95    Ok(())
96}
97
98/// Every example in this directory writes its output under
99/// `tests-data/output/`, resolved relative to this crate's own manifest so
100/// it works no matter what directory `cargo run` was invoked from.
101fn output_path(filename: &str) -> PathBuf {
102    Path::new(env!("CARGO_MANIFEST_DIR"))
103        .join("../../tests-data/output")
104        .join(filename)
105}