pub struct ShapeProperties {
pub transform: Option<Transform2D>,
pub geometry: Option<Geometry>,
pub fill: Option<Fill>,
pub line: Option<Line>,
pub effects: Option<EffectList>,
pub geometry_adjustments: Vec<GeometryAdjustment>,
}Expand description
A shape’s visual properties (<a:spPr>, CT_ShapeProperties): local position/size, geometry,
fill, and line. Everything about how a shape looks, independent of where it is anchored in its
host document (that part is never modeled here — see the crate-level doc comment).
Not modeled: 3D (a:scene3d/a:sp3d) — EG_EffectProperties’s <a:effectLst> choice
(shadow/glow/reflection/soft edge) is modeled, see EffectList, point 10; its sibling
choice <a:effectDag> (an effect graph, letting effects reference each other’s output — a
materially more complex, rarely-authored mechanism) is not. bwMode (black-and-white print
override) is not modeled either — a rarely-used printing hint.
Fields§
§transform: Option<Transform2D><a:xfrm> — position, size, rotation, flipping.
geometry: Option<Geometry>EG_Geometry (<a:prstGeom>/<a:custGeom>) — the shape’s outline.
fill: Option<Fill>EG_FillProperties (<a:noFill>/<a:solidFill>/<a:gradFill>/
<a:pattFill>/<a:blipFill>/<a:grpFill>) — how the shape’s interior is painted.
line: Option<Line><a:ln> — the shape’s outline stroke.
effects: Option<EffectList><a:effectLst> — shadow/glow/reflection/soft-edge effects.
geometry_adjustments: Vec<GeometryAdjustment><a:prstGeom>’s own <a:avLst> (CT_GeomGuideList) — adjustment handle values for a
preset shape (a rounded rectangle’s corner radius, an arrow’s head size.). Only meaningful,
and only ever written, when geometry is Some(Geometry::Preset(_)) — kept as a sibling
field here (rather than inside Geometry::Preset itself) to avoid a breaking change to
that enum’s existing tuple-variant shape, used at dozens of call sites across every host
crate. Empty (the default) omits <a:avLst> entirely for a preset shape — schema- valid,
meaning “use this preset’s own built-in default handles”. Grounded against a real fixture (a
smiley-face preset with an explicit adj guide).
Implementations§
Source§impl ShapeProperties
impl ShapeProperties
Sourcepub fn new() -> ShapeProperties
pub fn new() -> ShapeProperties
Creates an empty set of shape properties (every field unset — a shape that inherits everything from its host’s defaults).
Examples found in repository?
14fn main() -> office_toolkit::Result<()> {
15 let path = output_path("hello_world.pptx");
16
17 let text_box = AutoShape::new(2, "Hello box")
18 .with_properties(
19 ShapeProperties::new().with_transform(
20 Transform2D::new()
21 .with_offset(838_200, 1_365_250)
22 .with_extent(7_772_400, 1_200_150),
23 ),
24 )
25 .with_text_body(
26 TextBody::new()
27 .with_paragraph(TextParagraph::new().with_run(TextRun::text("Hello, world!"))),
28 );
29
30 // `Presentation` and `Slide` both come from `office_toolkit::prelude`.
31 let presentation =
32 Presentation::new().with_slide(Slide::new().with_shape(Shape::AutoShape(text_box)));
33 presentation.save_to_file(&path)?;
34 println!("Wrote {}", path.display());
35
36 // Read the file back to confirm it is a valid .pptx.
37 let reopened = Presentation::open_file(&path)?;
38 println!("Slide count: {}", reopened.slides.len());
39
40 Ok(())
41}More examples
12fn main() -> office_toolkit::Result<()> {
13 let path = output_path("pptx_notes_and_comments.pptx");
14
15 let title = |text: &str| {
16 AutoShape::new(2, "Title")
17 .with_properties(
18 ShapeProperties::new().with_transform(
19 Transform2D::new()
20 .with_offset(838_200, 838_200)
21 .with_extent(8_000_000, 1_000_000),
22 ),
23 )
24 .with_text_body(
25 TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(text))),
26 )
27 };
28
29 let notes_slide = Slide::new()
30 .with_shape(Shape::AutoShape(title("A slide with speaker notes")))
31 .with_notes(
32 TextBody::new().with_paragraph(
33 TextParagraph::new()
34 .with_run(TextRun::text("Remember to mention the Q3 numbers here.")),
35 ),
36 );
37
38 let commented_slide = Slide::new()
39 .with_shape(Shape::AutoShape(title("A slide with reviewer comments")))
40 .with_comment(
41 SlideComment::new(
42 "Reviewer",
43 "RV",
44 "2026-07-21T10:00:00",
45 "This claim needs a source.",
46 )
47 .with_position(1_000_000, 2_000_000),
48 )
49 .with_comment(
50 SlideComment::new(
51 "Editor",
52 "ED",
53 "2026-07-21T11:30:00",
54 "Looks good otherwise.",
55 )
56 .with_position(3_000_000, 2_000_000),
57 );
58
59 let presentation = Presentation::new()
60 .with_slide(notes_slide)
61 .with_slide(commented_slide);
62
63 presentation.save_to_file(&path)?;
64 println!("Wrote {}", path.display());
65 Ok(())
66}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}19fn main() -> office_toolkit::Result<()> {
20 // A custom theme and an embedded font. `Theme`/`ColorScheme`/
21 // `FontScheme` have no `with_*` builders in this crate — only
22 // `office_default()` or plain struct literals.
23 let custom_theme = Theme {
24 name: "Custom Brand".to_string(),
25 colors: ColorScheme {
26 dark1: "1B1B1B".to_string(),
27 light1: "FFFFFF".to_string(),
28 dark2: "0A2540".to_string(),
29 light2: "F5F5F5".to_string(),
30 accent1: "0A2540".to_string(),
31 accent2: "E8622C".to_string(),
32 accent3: "2E86AB".to_string(),
33 accent4: "6FB98F".to_string(),
34 accent5: "F4A259".to_string(),
35 accent6: "8E4585".to_string(),
36 hyperlink: "1155CC".to_string(),
37 followed_hyperlink: "6B3FA0".to_string(),
38 },
39 fonts: FontScheme {
40 major_latin: "Georgia".to_string(),
41 minor_latin: "Verdana".to_string(),
42 },
43 };
44
45 // Placeholder bytes — a real .pptx would carry genuine TrueType/
46 // OpenType font data here.
47 let embedded_font = EmbeddedFont::new("Custom Sans")
48 .with_regular(vec![0u8; 16])
49 .with_bold(vec![0u8; 16]);
50
51 // A slide with no shapes at all renders as a blank page — nothing shows
52 // the custom theme actually took effect. `drawing::Color` has no
53 // scheme-relative variant yet (`<a:schemeClr>` isn't modeled, see that
54 // enum's own doc comment), so this can't reference the theme's accent1
55 // symbolically; it uses the same literal hex values the theme itself
56 // was built from, purely so the slide visibly matches the palette above.
57 let title_shape = AutoShape::new(2, "Title")
58 .with_properties(
59 ShapeProperties::new()
60 .with_transform(
61 Transform2D::new()
62 .with_offset(838_200, 838_200)
63 .with_extent(6_000_000, 1_500_000),
64 )
65 .with_fill(Fill::Solid(Color::Rgb(custom_theme.colors.accent1.clone()))),
66 )
67 .with_text_body(
68 TextBody::new().with_paragraph(
69 TextParagraph::new().with_run(TextRun::text_with_properties(
70 "Custom Brand theme — Georgia / Verdana, accent1 = #0A2540",
71 TextRunProperties::new()
72 .with_font_family(custom_theme.fonts.major_latin.clone())
73 .with_font_size_points(24.0)
74 .with_fill(Fill::Solid(Color::Rgb(custom_theme.colors.light1.clone()))),
75 )),
76 ),
77 );
78
79 let themed_presentation = Presentation::new()
80 .with_theme(custom_theme)
81 .with_embedded_font(embedded_font)
82 .with_slide(Slide::new().with_shape(Shape::AutoShape(title_shape)));
83 let theme_path = output_path("pptx_theme.pptx");
84 themed_presentation.save_to_file(&theme_path)?;
85 println!("Wrote {}", theme_path.display());
86
87 // Document metadata (docProps/core.xml, app.xml, and custom.xml).
88 let properties = DocumentProperties::new()
89 .with_title("Metadata example")
90 .with_author("Example Author")
91 .with_subject("Presentation-level features")
92 .with_custom_property(
93 "ProjectCode",
94 CustomPropertyValue::Text("PPTX-META".to_string()),
95 );
96 // Same reasoning as `title_shape` above: an empty slide would render
97 // blank, so a text shape spells out where the metadata actually lives.
98 let metadata_shape = AutoShape::new(2, "Note")
99 .with_properties(ShapeProperties::new().with_transform(Transform2D::new().with_offset(838_200, 838_200).with_extent(7_000_000, 1_000_000)))
100 .with_text_body(TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(
101 "This presentation's metadata is in File > Info (title, author, subject, and a custom \"ProjectCode\" property) — not on this slide.",
102 ))));
103 let metadata_presentation = Presentation::new()
104 .with_properties(properties)
105 .with_slide(Slide::new().with_shape(Shape::AutoShape(metadata_shape)));
106 let metadata_path = output_path("pptx_metadata.pptx");
107 metadata_presentation.save_to_file(&metadata_path)?;
108 println!("Wrote {}", metadata_path.display());
109
110 Ok(())
111}16fn main() -> office_toolkit::Result<()> {
17 let path = output_path("pptx_grouping_and_connectors.pptx");
18
19 // Every shape below sets an explicit fill (and the connector an
20 // explicit line): with neither a fill/line nor a `<p:style>` theme
21 // reference, a shape has nothing to paint and renders as fully
22 // invisible — the slide then looks blank even though the shapes are
23 // there. `AutoShape`/`Connector` have no `<p:style>` support yet, so an
24 // explicit `Fill`/`Line` is the only way to make a shape actually show.
25 let circle_fill = || Fill::Solid(Color::Rgb("4472C4".to_string()));
26
27 let circle = AutoShape::new(11, "Circle").with_properties(
28 ShapeProperties::new()
29 .with_transform(
30 Transform2D::new()
31 .with_offset(0, 0)
32 .with_extent(1_000_000, 1_000_000),
33 )
34 .with_fill(circle_fill()),
35 );
36 let label = AutoShape::new(12, "Label")
37 .with_properties(
38 ShapeProperties::new()
39 .with_transform(
40 Transform2D::new()
41 .with_offset(1_200_000, 300_000)
42 .with_extent(1_500_000, 400_000),
43 )
44 .with_fill(Fill::Solid(Color::Rgb("E8622C".to_string()))),
45 )
46 .with_text_body(
47 TextBody::new()
48 .with_paragraph(TextParagraph::new().with_run(TextRun::text("Grouped label"))),
49 );
50
51 let group = ShapeGroup::new(2, "Group")
52 .with_transform(
53 (838_200, 838_200),
54 (2_700_000, 1_000_000),
55 (0, 0),
56 (2_700_000, 1_000_000),
57 )
58 .with_shape(Shape::AutoShape(circle))
59 .with_shape(Shape::AutoShape(label));
60
61 let rotated_circle = AutoShape::new(11, "Circle").with_properties(
62 ShapeProperties::new()
63 .with_transform(
64 Transform2D::new()
65 .with_offset(0, 0)
66 .with_extent(1_000_000, 1_000_000),
67 )
68 .with_fill(circle_fill()),
69 );
70 let rotated_group = ShapeGroup::new(2, "Rotated and flipped group")
71 .with_transform(
72 (838_200, 838_200),
73 (1_000_000, 1_000_000),
74 (0, 0),
75 (1_000_000, 1_000_000),
76 )
77 .with_rotation_degrees(45.0)
78 .with_flip_horizontal(true)
79 .with_shape(Shape::AutoShape(rotated_circle));
80
81 let box_a = AutoShape::new(2, "Box A").with_properties(
82 ShapeProperties::new()
83 .with_transform(
84 Transform2D::new()
85 .with_offset(838_200, 838_200)
86 .with_extent(1_000_000, 1_000_000),
87 )
88 .with_fill(Fill::Solid(Color::Rgb("2E86AB".to_string()))),
89 );
90 let box_b = AutoShape::new(3, "Box B").with_properties(
91 ShapeProperties::new()
92 .with_transform(
93 Transform2D::new()
94 .with_offset(3_500_000, 838_200)
95 .with_extent(1_000_000, 1_000_000),
96 )
97 .with_fill(Fill::Solid(Color::Rgb("6FB98F".to_string()))),
98 );
99 // `Connector::new` leaves position/size unset, which the writer then
100 // emits as a zero-size `<a:xfrm>` (off 0,0 / ext 0,0) — a real point
101 // with no length, invisible regardless of line/fill. `stCxn`/`endCxn`
102 // alone don't supply geometry; PowerPoint only recomputes it once you
103 // drag one of the attached shapes. So this also sets an explicit
104 // transform spanning Box A's right edge to Box B's left edge.
105 let connector = Connector::new(4, "Connector")
106 .with_properties(
107 ShapeProperties::new()
108 .with_transform(
109 Transform2D::new()
110 .with_offset(1_838_200, 1_338_200)
111 .with_extent(1_662_000, 0),
112 )
113 .with_line(
114 Line::new()
115 .with_width_emu(25_400)
116 .with_fill(Fill::Solid(Color::Rgb("000000".to_string()))),
117 ),
118 )
119 .with_start_connection(2, 0)
120 .with_end_connection(3, 0);
121
122 let presentation = Presentation::new()
123 .with_slide(Slide::new().with_shape(Shape::Group(group)))
124 .with_slide(Slide::new().with_shape(Shape::Group(rotated_group)))
125 .with_slide(
126 Slide::new()
127 .with_shape(Shape::AutoShape(box_a))
128 .with_shape(Shape::AutoShape(box_b))
129 .with_shape(Shape::Connector(connector)),
130 );
131
132 presentation.save_to_file(&path)?;
133 println!("Wrote {}", path.display());
134 Ok(())
135}19fn main() -> office_toolkit::Result<()> {
20 let path = output_path("pptx_text_formatting.pptx");
21
22 let spacing_shape = AutoShape::new(2, "Spacing")
23 .with_properties(
24 ShapeProperties::new().with_transform(
25 Transform2D::new()
26 .with_offset(838_200, 838_200)
27 .with_extent(6_000_000, 1_500_000),
28 ),
29 )
30 .with_text_body(
31 TextBody::new().with_paragraph(
32 TextParagraph::new()
33 .with_properties(
34 TextParagraphProperties::new()
35 .with_line_spacing(TextSpacing::Percent(150_000))
36 .with_space_before(TextSpacing::Points(1200))
37 .with_indent_emu(457_200)
38 .with_level(1),
39 )
40 .with_run(TextRun::text(
41 "Indented, 150% line spacing, 12pt space before.",
42 )),
43 ),
44 );
45
46 let bullets_shape = AutoShape::new(2, "Bullets")
47 .with_properties(
48 ShapeProperties::new().with_transform(
49 Transform2D::new()
50 .with_offset(838_200, 838_200)
51 .with_extent(6_000_000, 1_800_000),
52 ),
53 )
54 .with_text_body(
55 TextBody::new()
56 .with_paragraph(
57 TextParagraph::new()
58 .with_properties(
59 TextParagraphProperties::new()
60 .with_bullet(BulletKind::Character("\u{2022}".to_string())),
61 )
62 .with_run(TextRun::text("Bulleted item")),
63 )
64 .with_paragraph(
65 TextParagraph::new()
66 .with_properties(TextParagraphProperties::new().with_bullet(
67 BulletKind::AutoNumber {
68 scheme: "arabicPeriod".to_string(),
69 start_at: None,
70 },
71 ))
72 .with_run(TextRun::text("Auto-numbered item")),
73 ),
74 );
75
76 let autofit_shape = AutoShape::new(2, "Autofit")
77 .with_text_box(true)
78 .with_properties(
79 ShapeProperties::new().with_transform(
80 Transform2D::new()
81 .with_offset(838_200, 838_200)
82 .with_extent(4_000_000, 1_000_000),
83 ),
84 )
85 .with_text_body(
86 TextBody::new()
87 .with_properties(
88 TextBodyProperties::new()
89 .with_autofit(TextAutofit::Shape)
90 .with_anchor(TextAnchor::Center)
91 .with_anchor_center(true),
92 )
93 .with_paragraph(TextParagraph::new().with_run(TextRun::text(
94 "This shape resizes to fit its text, centered both ways.",
95 ))),
96 );
97
98 let casing_shape = AutoShape::new(2, "Casing")
99 .with_properties(
100 ShapeProperties::new().with_transform(
101 Transform2D::new()
102 .with_offset(838_200, 838_200)
103 .with_extent(6_000_000, 1_500_000),
104 ),
105 )
106 .with_text_body(
107 TextBody::new().with_paragraph(
108 TextParagraph::new()
109 .with_run(TextRun::text_with_properties(
110 "rendered in all caps, ",
111 TextRunProperties::new().with_text_caps(TextCaps::All),
112 ))
113 .with_run(TextRun::text_with_properties(
114 "widely spaced, ",
115 TextRunProperties::new().with_character_spacing_points(3.0),
116 ))
117 .with_run(TextRun::text_with_properties(
118 "highlighted",
119 TextRunProperties::new().with_highlight(Color::Rgb("FFFF00".to_string())),
120 ))
121 .with_run(TextRun::text_with_properties(
122 "2",
123 TextRunProperties::new().with_baseline_percent(30.0),
124 )),
125 ),
126 );
127
128 let field_shape = AutoShape::new(2, "Field")
129 .with_properties(
130 ShapeProperties::new().with_transform(
131 Transform2D::new()
132 .with_offset(838_200, 838_200)
133 .with_extent(3_000_000, 500_000),
134 ),
135 )
136 .with_text_body(
137 TextBody::new().with_paragraph(
138 TextParagraph::new()
139 .with_run(TextRun::text("Slide "))
140 .with_run(TextRun::field(
141 "{7A9E3F10-4B6C-4D2E-9A1F-8C5D6E7F0123}",
142 Some("slidenum".to_string()),
143 "1",
144 )),
145 ),
146 );
147
148 let presentation = Presentation::new()
149 .with_slide(Slide::new().with_shape(Shape::AutoShape(spacing_shape)))
150 .with_slide(Slide::new().with_shape(Shape::AutoShape(bullets_shape)))
151 .with_slide(Slide::new().with_shape(Shape::AutoShape(autofit_shape)))
152 .with_slide(Slide::new().with_shape(Shape::AutoShape(casing_shape)))
153 .with_slide(Slide::new().with_shape(Shape::AutoShape(field_shape)));
154
155 presentation.save_to_file(&path)?;
156 println!("Wrote {}", path.display());
157 Ok(())
158}Sourcepub fn with_transform(self, transform: Transform2D) -> ShapeProperties
pub fn with_transform(self, transform: Transform2D) -> ShapeProperties
Sets the shape’s position/size/rotation (<a:xfrm>).
Examples found in repository?
14fn main() -> office_toolkit::Result<()> {
15 let path = output_path("hello_world.pptx");
16
17 let text_box = AutoShape::new(2, "Hello box")
18 .with_properties(
19 ShapeProperties::new().with_transform(
20 Transform2D::new()
21 .with_offset(838_200, 1_365_250)
22 .with_extent(7_772_400, 1_200_150),
23 ),
24 )
25 .with_text_body(
26 TextBody::new()
27 .with_paragraph(TextParagraph::new().with_run(TextRun::text("Hello, world!"))),
28 );
29
30 // `Presentation` and `Slide` both come from `office_toolkit::prelude`.
31 let presentation =
32 Presentation::new().with_slide(Slide::new().with_shape(Shape::AutoShape(text_box)));
33 presentation.save_to_file(&path)?;
34 println!("Wrote {}", path.display());
35
36 // Read the file back to confirm it is a valid .pptx.
37 let reopened = Presentation::open_file(&path)?;
38 println!("Slide count: {}", reopened.slides.len());
39
40 Ok(())
41}More examples
12fn main() -> office_toolkit::Result<()> {
13 let path = output_path("pptx_notes_and_comments.pptx");
14
15 let title = |text: &str| {
16 AutoShape::new(2, "Title")
17 .with_properties(
18 ShapeProperties::new().with_transform(
19 Transform2D::new()
20 .with_offset(838_200, 838_200)
21 .with_extent(8_000_000, 1_000_000),
22 ),
23 )
24 .with_text_body(
25 TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(text))),
26 )
27 };
28
29 let notes_slide = Slide::new()
30 .with_shape(Shape::AutoShape(title("A slide with speaker notes")))
31 .with_notes(
32 TextBody::new().with_paragraph(
33 TextParagraph::new()
34 .with_run(TextRun::text("Remember to mention the Q3 numbers here.")),
35 ),
36 );
37
38 let commented_slide = Slide::new()
39 .with_shape(Shape::AutoShape(title("A slide with reviewer comments")))
40 .with_comment(
41 SlideComment::new(
42 "Reviewer",
43 "RV",
44 "2026-07-21T10:00:00",
45 "This claim needs a source.",
46 )
47 .with_position(1_000_000, 2_000_000),
48 )
49 .with_comment(
50 SlideComment::new(
51 "Editor",
52 "ED",
53 "2026-07-21T11:30:00",
54 "Looks good otherwise.",
55 )
56 .with_position(3_000_000, 2_000_000),
57 );
58
59 let presentation = Presentation::new()
60 .with_slide(notes_slide)
61 .with_slide(commented_slide);
62
63 presentation.save_to_file(&path)?;
64 println!("Wrote {}", path.display());
65 Ok(())
66}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}19fn main() -> office_toolkit::Result<()> {
20 // A custom theme and an embedded font. `Theme`/`ColorScheme`/
21 // `FontScheme` have no `with_*` builders in this crate — only
22 // `office_default()` or plain struct literals.
23 let custom_theme = Theme {
24 name: "Custom Brand".to_string(),
25 colors: ColorScheme {
26 dark1: "1B1B1B".to_string(),
27 light1: "FFFFFF".to_string(),
28 dark2: "0A2540".to_string(),
29 light2: "F5F5F5".to_string(),
30 accent1: "0A2540".to_string(),
31 accent2: "E8622C".to_string(),
32 accent3: "2E86AB".to_string(),
33 accent4: "6FB98F".to_string(),
34 accent5: "F4A259".to_string(),
35 accent6: "8E4585".to_string(),
36 hyperlink: "1155CC".to_string(),
37 followed_hyperlink: "6B3FA0".to_string(),
38 },
39 fonts: FontScheme {
40 major_latin: "Georgia".to_string(),
41 minor_latin: "Verdana".to_string(),
42 },
43 };
44
45 // Placeholder bytes — a real .pptx would carry genuine TrueType/
46 // OpenType font data here.
47 let embedded_font = EmbeddedFont::new("Custom Sans")
48 .with_regular(vec![0u8; 16])
49 .with_bold(vec![0u8; 16]);
50
51 // A slide with no shapes at all renders as a blank page — nothing shows
52 // the custom theme actually took effect. `drawing::Color` has no
53 // scheme-relative variant yet (`<a:schemeClr>` isn't modeled, see that
54 // enum's own doc comment), so this can't reference the theme's accent1
55 // symbolically; it uses the same literal hex values the theme itself
56 // was built from, purely so the slide visibly matches the palette above.
57 let title_shape = AutoShape::new(2, "Title")
58 .with_properties(
59 ShapeProperties::new()
60 .with_transform(
61 Transform2D::new()
62 .with_offset(838_200, 838_200)
63 .with_extent(6_000_000, 1_500_000),
64 )
65 .with_fill(Fill::Solid(Color::Rgb(custom_theme.colors.accent1.clone()))),
66 )
67 .with_text_body(
68 TextBody::new().with_paragraph(
69 TextParagraph::new().with_run(TextRun::text_with_properties(
70 "Custom Brand theme — Georgia / Verdana, accent1 = #0A2540",
71 TextRunProperties::new()
72 .with_font_family(custom_theme.fonts.major_latin.clone())
73 .with_font_size_points(24.0)
74 .with_fill(Fill::Solid(Color::Rgb(custom_theme.colors.light1.clone()))),
75 )),
76 ),
77 );
78
79 let themed_presentation = Presentation::new()
80 .with_theme(custom_theme)
81 .with_embedded_font(embedded_font)
82 .with_slide(Slide::new().with_shape(Shape::AutoShape(title_shape)));
83 let theme_path = output_path("pptx_theme.pptx");
84 themed_presentation.save_to_file(&theme_path)?;
85 println!("Wrote {}", theme_path.display());
86
87 // Document metadata (docProps/core.xml, app.xml, and custom.xml).
88 let properties = DocumentProperties::new()
89 .with_title("Metadata example")
90 .with_author("Example Author")
91 .with_subject("Presentation-level features")
92 .with_custom_property(
93 "ProjectCode",
94 CustomPropertyValue::Text("PPTX-META".to_string()),
95 );
96 // Same reasoning as `title_shape` above: an empty slide would render
97 // blank, so a text shape spells out where the metadata actually lives.
98 let metadata_shape = AutoShape::new(2, "Note")
99 .with_properties(ShapeProperties::new().with_transform(Transform2D::new().with_offset(838_200, 838_200).with_extent(7_000_000, 1_000_000)))
100 .with_text_body(TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(
101 "This presentation's metadata is in File > Info (title, author, subject, and a custom \"ProjectCode\" property) — not on this slide.",
102 ))));
103 let metadata_presentation = Presentation::new()
104 .with_properties(properties)
105 .with_slide(Slide::new().with_shape(Shape::AutoShape(metadata_shape)));
106 let metadata_path = output_path("pptx_metadata.pptx");
107 metadata_presentation.save_to_file(&metadata_path)?;
108 println!("Wrote {}", metadata_path.display());
109
110 Ok(())
111}16fn main() -> office_toolkit::Result<()> {
17 let path = output_path("pptx_grouping_and_connectors.pptx");
18
19 // Every shape below sets an explicit fill (and the connector an
20 // explicit line): with neither a fill/line nor a `<p:style>` theme
21 // reference, a shape has nothing to paint and renders as fully
22 // invisible — the slide then looks blank even though the shapes are
23 // there. `AutoShape`/`Connector` have no `<p:style>` support yet, so an
24 // explicit `Fill`/`Line` is the only way to make a shape actually show.
25 let circle_fill = || Fill::Solid(Color::Rgb("4472C4".to_string()));
26
27 let circle = AutoShape::new(11, "Circle").with_properties(
28 ShapeProperties::new()
29 .with_transform(
30 Transform2D::new()
31 .with_offset(0, 0)
32 .with_extent(1_000_000, 1_000_000),
33 )
34 .with_fill(circle_fill()),
35 );
36 let label = AutoShape::new(12, "Label")
37 .with_properties(
38 ShapeProperties::new()
39 .with_transform(
40 Transform2D::new()
41 .with_offset(1_200_000, 300_000)
42 .with_extent(1_500_000, 400_000),
43 )
44 .with_fill(Fill::Solid(Color::Rgb("E8622C".to_string()))),
45 )
46 .with_text_body(
47 TextBody::new()
48 .with_paragraph(TextParagraph::new().with_run(TextRun::text("Grouped label"))),
49 );
50
51 let group = ShapeGroup::new(2, "Group")
52 .with_transform(
53 (838_200, 838_200),
54 (2_700_000, 1_000_000),
55 (0, 0),
56 (2_700_000, 1_000_000),
57 )
58 .with_shape(Shape::AutoShape(circle))
59 .with_shape(Shape::AutoShape(label));
60
61 let rotated_circle = AutoShape::new(11, "Circle").with_properties(
62 ShapeProperties::new()
63 .with_transform(
64 Transform2D::new()
65 .with_offset(0, 0)
66 .with_extent(1_000_000, 1_000_000),
67 )
68 .with_fill(circle_fill()),
69 );
70 let rotated_group = ShapeGroup::new(2, "Rotated and flipped group")
71 .with_transform(
72 (838_200, 838_200),
73 (1_000_000, 1_000_000),
74 (0, 0),
75 (1_000_000, 1_000_000),
76 )
77 .with_rotation_degrees(45.0)
78 .with_flip_horizontal(true)
79 .with_shape(Shape::AutoShape(rotated_circle));
80
81 let box_a = AutoShape::new(2, "Box A").with_properties(
82 ShapeProperties::new()
83 .with_transform(
84 Transform2D::new()
85 .with_offset(838_200, 838_200)
86 .with_extent(1_000_000, 1_000_000),
87 )
88 .with_fill(Fill::Solid(Color::Rgb("2E86AB".to_string()))),
89 );
90 let box_b = AutoShape::new(3, "Box B").with_properties(
91 ShapeProperties::new()
92 .with_transform(
93 Transform2D::new()
94 .with_offset(3_500_000, 838_200)
95 .with_extent(1_000_000, 1_000_000),
96 )
97 .with_fill(Fill::Solid(Color::Rgb("6FB98F".to_string()))),
98 );
99 // `Connector::new` leaves position/size unset, which the writer then
100 // emits as a zero-size `<a:xfrm>` (off 0,0 / ext 0,0) — a real point
101 // with no length, invisible regardless of line/fill. `stCxn`/`endCxn`
102 // alone don't supply geometry; PowerPoint only recomputes it once you
103 // drag one of the attached shapes. So this also sets an explicit
104 // transform spanning Box A's right edge to Box B's left edge.
105 let connector = Connector::new(4, "Connector")
106 .with_properties(
107 ShapeProperties::new()
108 .with_transform(
109 Transform2D::new()
110 .with_offset(1_838_200, 1_338_200)
111 .with_extent(1_662_000, 0),
112 )
113 .with_line(
114 Line::new()
115 .with_width_emu(25_400)
116 .with_fill(Fill::Solid(Color::Rgb("000000".to_string()))),
117 ),
118 )
119 .with_start_connection(2, 0)
120 .with_end_connection(3, 0);
121
122 let presentation = Presentation::new()
123 .with_slide(Slide::new().with_shape(Shape::Group(group)))
124 .with_slide(Slide::new().with_shape(Shape::Group(rotated_group)))
125 .with_slide(
126 Slide::new()
127 .with_shape(Shape::AutoShape(box_a))
128 .with_shape(Shape::AutoShape(box_b))
129 .with_shape(Shape::Connector(connector)),
130 );
131
132 presentation.save_to_file(&path)?;
133 println!("Wrote {}", path.display());
134 Ok(())
135}19fn main() -> office_toolkit::Result<()> {
20 let path = output_path("pptx_text_formatting.pptx");
21
22 let spacing_shape = AutoShape::new(2, "Spacing")
23 .with_properties(
24 ShapeProperties::new().with_transform(
25 Transform2D::new()
26 .with_offset(838_200, 838_200)
27 .with_extent(6_000_000, 1_500_000),
28 ),
29 )
30 .with_text_body(
31 TextBody::new().with_paragraph(
32 TextParagraph::new()
33 .with_properties(
34 TextParagraphProperties::new()
35 .with_line_spacing(TextSpacing::Percent(150_000))
36 .with_space_before(TextSpacing::Points(1200))
37 .with_indent_emu(457_200)
38 .with_level(1),
39 )
40 .with_run(TextRun::text(
41 "Indented, 150% line spacing, 12pt space before.",
42 )),
43 ),
44 );
45
46 let bullets_shape = AutoShape::new(2, "Bullets")
47 .with_properties(
48 ShapeProperties::new().with_transform(
49 Transform2D::new()
50 .with_offset(838_200, 838_200)
51 .with_extent(6_000_000, 1_800_000),
52 ),
53 )
54 .with_text_body(
55 TextBody::new()
56 .with_paragraph(
57 TextParagraph::new()
58 .with_properties(
59 TextParagraphProperties::new()
60 .with_bullet(BulletKind::Character("\u{2022}".to_string())),
61 )
62 .with_run(TextRun::text("Bulleted item")),
63 )
64 .with_paragraph(
65 TextParagraph::new()
66 .with_properties(TextParagraphProperties::new().with_bullet(
67 BulletKind::AutoNumber {
68 scheme: "arabicPeriod".to_string(),
69 start_at: None,
70 },
71 ))
72 .with_run(TextRun::text("Auto-numbered item")),
73 ),
74 );
75
76 let autofit_shape = AutoShape::new(2, "Autofit")
77 .with_text_box(true)
78 .with_properties(
79 ShapeProperties::new().with_transform(
80 Transform2D::new()
81 .with_offset(838_200, 838_200)
82 .with_extent(4_000_000, 1_000_000),
83 ),
84 )
85 .with_text_body(
86 TextBody::new()
87 .with_properties(
88 TextBodyProperties::new()
89 .with_autofit(TextAutofit::Shape)
90 .with_anchor(TextAnchor::Center)
91 .with_anchor_center(true),
92 )
93 .with_paragraph(TextParagraph::new().with_run(TextRun::text(
94 "This shape resizes to fit its text, centered both ways.",
95 ))),
96 );
97
98 let casing_shape = AutoShape::new(2, "Casing")
99 .with_properties(
100 ShapeProperties::new().with_transform(
101 Transform2D::new()
102 .with_offset(838_200, 838_200)
103 .with_extent(6_000_000, 1_500_000),
104 ),
105 )
106 .with_text_body(
107 TextBody::new().with_paragraph(
108 TextParagraph::new()
109 .with_run(TextRun::text_with_properties(
110 "rendered in all caps, ",
111 TextRunProperties::new().with_text_caps(TextCaps::All),
112 ))
113 .with_run(TextRun::text_with_properties(
114 "widely spaced, ",
115 TextRunProperties::new().with_character_spacing_points(3.0),
116 ))
117 .with_run(TextRun::text_with_properties(
118 "highlighted",
119 TextRunProperties::new().with_highlight(Color::Rgb("FFFF00".to_string())),
120 ))
121 .with_run(TextRun::text_with_properties(
122 "2",
123 TextRunProperties::new().with_baseline_percent(30.0),
124 )),
125 ),
126 );
127
128 let field_shape = AutoShape::new(2, "Field")
129 .with_properties(
130 ShapeProperties::new().with_transform(
131 Transform2D::new()
132 .with_offset(838_200, 838_200)
133 .with_extent(3_000_000, 500_000),
134 ),
135 )
136 .with_text_body(
137 TextBody::new().with_paragraph(
138 TextParagraph::new()
139 .with_run(TextRun::text("Slide "))
140 .with_run(TextRun::field(
141 "{7A9E3F10-4B6C-4D2E-9A1F-8C5D6E7F0123}",
142 Some("slidenum".to_string()),
143 "1",
144 )),
145 ),
146 );
147
148 let presentation = Presentation::new()
149 .with_slide(Slide::new().with_shape(Shape::AutoShape(spacing_shape)))
150 .with_slide(Slide::new().with_shape(Shape::AutoShape(bullets_shape)))
151 .with_slide(Slide::new().with_shape(Shape::AutoShape(autofit_shape)))
152 .with_slide(Slide::new().with_shape(Shape::AutoShape(casing_shape)))
153 .with_slide(Slide::new().with_shape(Shape::AutoShape(field_shape)));
154
155 presentation.save_to_file(&path)?;
156 println!("Wrote {}", path.display());
157 Ok(())
158}Sourcepub fn with_geometry(self, geometry: Geometry) -> ShapeProperties
pub fn with_geometry(self, geometry: Geometry) -> ShapeProperties
Sets the shape’s outline (EG_Geometry).
Sourcepub fn with_fill(self, fill: Fill) -> ShapeProperties
pub fn with_fill(self, fill: Fill) -> ShapeProperties
Sets the shape’s interior fill (EG_FillProperties).
Examples found in repository?
19fn main() -> office_toolkit::Result<()> {
20 // A custom theme and an embedded font. `Theme`/`ColorScheme`/
21 // `FontScheme` have no `with_*` builders in this crate — only
22 // `office_default()` or plain struct literals.
23 let custom_theme = Theme {
24 name: "Custom Brand".to_string(),
25 colors: ColorScheme {
26 dark1: "1B1B1B".to_string(),
27 light1: "FFFFFF".to_string(),
28 dark2: "0A2540".to_string(),
29 light2: "F5F5F5".to_string(),
30 accent1: "0A2540".to_string(),
31 accent2: "E8622C".to_string(),
32 accent3: "2E86AB".to_string(),
33 accent4: "6FB98F".to_string(),
34 accent5: "F4A259".to_string(),
35 accent6: "8E4585".to_string(),
36 hyperlink: "1155CC".to_string(),
37 followed_hyperlink: "6B3FA0".to_string(),
38 },
39 fonts: FontScheme {
40 major_latin: "Georgia".to_string(),
41 minor_latin: "Verdana".to_string(),
42 },
43 };
44
45 // Placeholder bytes — a real .pptx would carry genuine TrueType/
46 // OpenType font data here.
47 let embedded_font = EmbeddedFont::new("Custom Sans")
48 .with_regular(vec![0u8; 16])
49 .with_bold(vec![0u8; 16]);
50
51 // A slide with no shapes at all renders as a blank page — nothing shows
52 // the custom theme actually took effect. `drawing::Color` has no
53 // scheme-relative variant yet (`<a:schemeClr>` isn't modeled, see that
54 // enum's own doc comment), so this can't reference the theme's accent1
55 // symbolically; it uses the same literal hex values the theme itself
56 // was built from, purely so the slide visibly matches the palette above.
57 let title_shape = AutoShape::new(2, "Title")
58 .with_properties(
59 ShapeProperties::new()
60 .with_transform(
61 Transform2D::new()
62 .with_offset(838_200, 838_200)
63 .with_extent(6_000_000, 1_500_000),
64 )
65 .with_fill(Fill::Solid(Color::Rgb(custom_theme.colors.accent1.clone()))),
66 )
67 .with_text_body(
68 TextBody::new().with_paragraph(
69 TextParagraph::new().with_run(TextRun::text_with_properties(
70 "Custom Brand theme — Georgia / Verdana, accent1 = #0A2540",
71 TextRunProperties::new()
72 .with_font_family(custom_theme.fonts.major_latin.clone())
73 .with_font_size_points(24.0)
74 .with_fill(Fill::Solid(Color::Rgb(custom_theme.colors.light1.clone()))),
75 )),
76 ),
77 );
78
79 let themed_presentation = Presentation::new()
80 .with_theme(custom_theme)
81 .with_embedded_font(embedded_font)
82 .with_slide(Slide::new().with_shape(Shape::AutoShape(title_shape)));
83 let theme_path = output_path("pptx_theme.pptx");
84 themed_presentation.save_to_file(&theme_path)?;
85 println!("Wrote {}", theme_path.display());
86
87 // Document metadata (docProps/core.xml, app.xml, and custom.xml).
88 let properties = DocumentProperties::new()
89 .with_title("Metadata example")
90 .with_author("Example Author")
91 .with_subject("Presentation-level features")
92 .with_custom_property(
93 "ProjectCode",
94 CustomPropertyValue::Text("PPTX-META".to_string()),
95 );
96 // Same reasoning as `title_shape` above: an empty slide would render
97 // blank, so a text shape spells out where the metadata actually lives.
98 let metadata_shape = AutoShape::new(2, "Note")
99 .with_properties(ShapeProperties::new().with_transform(Transform2D::new().with_offset(838_200, 838_200).with_extent(7_000_000, 1_000_000)))
100 .with_text_body(TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(
101 "This presentation's metadata is in File > Info (title, author, subject, and a custom \"ProjectCode\" property) — not on this slide.",
102 ))));
103 let metadata_presentation = Presentation::new()
104 .with_properties(properties)
105 .with_slide(Slide::new().with_shape(Shape::AutoShape(metadata_shape)));
106 let metadata_path = output_path("pptx_metadata.pptx");
107 metadata_presentation.save_to_file(&metadata_path)?;
108 println!("Wrote {}", metadata_path.display());
109
110 Ok(())
111}More examples
16fn main() -> office_toolkit::Result<()> {
17 let path = output_path("pptx_grouping_and_connectors.pptx");
18
19 // Every shape below sets an explicit fill (and the connector an
20 // explicit line): with neither a fill/line nor a `<p:style>` theme
21 // reference, a shape has nothing to paint and renders as fully
22 // invisible — the slide then looks blank even though the shapes are
23 // there. `AutoShape`/`Connector` have no `<p:style>` support yet, so an
24 // explicit `Fill`/`Line` is the only way to make a shape actually show.
25 let circle_fill = || Fill::Solid(Color::Rgb("4472C4".to_string()));
26
27 let circle = AutoShape::new(11, "Circle").with_properties(
28 ShapeProperties::new()
29 .with_transform(
30 Transform2D::new()
31 .with_offset(0, 0)
32 .with_extent(1_000_000, 1_000_000),
33 )
34 .with_fill(circle_fill()),
35 );
36 let label = AutoShape::new(12, "Label")
37 .with_properties(
38 ShapeProperties::new()
39 .with_transform(
40 Transform2D::new()
41 .with_offset(1_200_000, 300_000)
42 .with_extent(1_500_000, 400_000),
43 )
44 .with_fill(Fill::Solid(Color::Rgb("E8622C".to_string()))),
45 )
46 .with_text_body(
47 TextBody::new()
48 .with_paragraph(TextParagraph::new().with_run(TextRun::text("Grouped label"))),
49 );
50
51 let group = ShapeGroup::new(2, "Group")
52 .with_transform(
53 (838_200, 838_200),
54 (2_700_000, 1_000_000),
55 (0, 0),
56 (2_700_000, 1_000_000),
57 )
58 .with_shape(Shape::AutoShape(circle))
59 .with_shape(Shape::AutoShape(label));
60
61 let rotated_circle = AutoShape::new(11, "Circle").with_properties(
62 ShapeProperties::new()
63 .with_transform(
64 Transform2D::new()
65 .with_offset(0, 0)
66 .with_extent(1_000_000, 1_000_000),
67 )
68 .with_fill(circle_fill()),
69 );
70 let rotated_group = ShapeGroup::new(2, "Rotated and flipped group")
71 .with_transform(
72 (838_200, 838_200),
73 (1_000_000, 1_000_000),
74 (0, 0),
75 (1_000_000, 1_000_000),
76 )
77 .with_rotation_degrees(45.0)
78 .with_flip_horizontal(true)
79 .with_shape(Shape::AutoShape(rotated_circle));
80
81 let box_a = AutoShape::new(2, "Box A").with_properties(
82 ShapeProperties::new()
83 .with_transform(
84 Transform2D::new()
85 .with_offset(838_200, 838_200)
86 .with_extent(1_000_000, 1_000_000),
87 )
88 .with_fill(Fill::Solid(Color::Rgb("2E86AB".to_string()))),
89 );
90 let box_b = AutoShape::new(3, "Box B").with_properties(
91 ShapeProperties::new()
92 .with_transform(
93 Transform2D::new()
94 .with_offset(3_500_000, 838_200)
95 .with_extent(1_000_000, 1_000_000),
96 )
97 .with_fill(Fill::Solid(Color::Rgb("6FB98F".to_string()))),
98 );
99 // `Connector::new` leaves position/size unset, which the writer then
100 // emits as a zero-size `<a:xfrm>` (off 0,0 / ext 0,0) — a real point
101 // with no length, invisible regardless of line/fill. `stCxn`/`endCxn`
102 // alone don't supply geometry; PowerPoint only recomputes it once you
103 // drag one of the attached shapes. So this also sets an explicit
104 // transform spanning Box A's right edge to Box B's left edge.
105 let connector = Connector::new(4, "Connector")
106 .with_properties(
107 ShapeProperties::new()
108 .with_transform(
109 Transform2D::new()
110 .with_offset(1_838_200, 1_338_200)
111 .with_extent(1_662_000, 0),
112 )
113 .with_line(
114 Line::new()
115 .with_width_emu(25_400)
116 .with_fill(Fill::Solid(Color::Rgb("000000".to_string()))),
117 ),
118 )
119 .with_start_connection(2, 0)
120 .with_end_connection(3, 0);
121
122 let presentation = Presentation::new()
123 .with_slide(Slide::new().with_shape(Shape::Group(group)))
124 .with_slide(Slide::new().with_shape(Shape::Group(rotated_group)))
125 .with_slide(
126 Slide::new()
127 .with_shape(Shape::AutoShape(box_a))
128 .with_shape(Shape::AutoShape(box_b))
129 .with_shape(Shape::Connector(connector)),
130 );
131
132 presentation.save_to_file(&path)?;
133 println!("Wrote {}", path.display());
134 Ok(())
135}Sourcepub fn with_line(self, line: Line) -> ShapeProperties
pub fn with_line(self, line: Line) -> ShapeProperties
Sets the shape’s outline stroke (<a:ln>).
Examples found in repository?
16fn main() -> office_toolkit::Result<()> {
17 let path = output_path("pptx_grouping_and_connectors.pptx");
18
19 // Every shape below sets an explicit fill (and the connector an
20 // explicit line): with neither a fill/line nor a `<p:style>` theme
21 // reference, a shape has nothing to paint and renders as fully
22 // invisible — the slide then looks blank even though the shapes are
23 // there. `AutoShape`/`Connector` have no `<p:style>` support yet, so an
24 // explicit `Fill`/`Line` is the only way to make a shape actually show.
25 let circle_fill = || Fill::Solid(Color::Rgb("4472C4".to_string()));
26
27 let circle = AutoShape::new(11, "Circle").with_properties(
28 ShapeProperties::new()
29 .with_transform(
30 Transform2D::new()
31 .with_offset(0, 0)
32 .with_extent(1_000_000, 1_000_000),
33 )
34 .with_fill(circle_fill()),
35 );
36 let label = AutoShape::new(12, "Label")
37 .with_properties(
38 ShapeProperties::new()
39 .with_transform(
40 Transform2D::new()
41 .with_offset(1_200_000, 300_000)
42 .with_extent(1_500_000, 400_000),
43 )
44 .with_fill(Fill::Solid(Color::Rgb("E8622C".to_string()))),
45 )
46 .with_text_body(
47 TextBody::new()
48 .with_paragraph(TextParagraph::new().with_run(TextRun::text("Grouped label"))),
49 );
50
51 let group = ShapeGroup::new(2, "Group")
52 .with_transform(
53 (838_200, 838_200),
54 (2_700_000, 1_000_000),
55 (0, 0),
56 (2_700_000, 1_000_000),
57 )
58 .with_shape(Shape::AutoShape(circle))
59 .with_shape(Shape::AutoShape(label));
60
61 let rotated_circle = AutoShape::new(11, "Circle").with_properties(
62 ShapeProperties::new()
63 .with_transform(
64 Transform2D::new()
65 .with_offset(0, 0)
66 .with_extent(1_000_000, 1_000_000),
67 )
68 .with_fill(circle_fill()),
69 );
70 let rotated_group = ShapeGroup::new(2, "Rotated and flipped group")
71 .with_transform(
72 (838_200, 838_200),
73 (1_000_000, 1_000_000),
74 (0, 0),
75 (1_000_000, 1_000_000),
76 )
77 .with_rotation_degrees(45.0)
78 .with_flip_horizontal(true)
79 .with_shape(Shape::AutoShape(rotated_circle));
80
81 let box_a = AutoShape::new(2, "Box A").with_properties(
82 ShapeProperties::new()
83 .with_transform(
84 Transform2D::new()
85 .with_offset(838_200, 838_200)
86 .with_extent(1_000_000, 1_000_000),
87 )
88 .with_fill(Fill::Solid(Color::Rgb("2E86AB".to_string()))),
89 );
90 let box_b = AutoShape::new(3, "Box B").with_properties(
91 ShapeProperties::new()
92 .with_transform(
93 Transform2D::new()
94 .with_offset(3_500_000, 838_200)
95 .with_extent(1_000_000, 1_000_000),
96 )
97 .with_fill(Fill::Solid(Color::Rgb("6FB98F".to_string()))),
98 );
99 // `Connector::new` leaves position/size unset, which the writer then
100 // emits as a zero-size `<a:xfrm>` (off 0,0 / ext 0,0) — a real point
101 // with no length, invisible regardless of line/fill. `stCxn`/`endCxn`
102 // alone don't supply geometry; PowerPoint only recomputes it once you
103 // drag one of the attached shapes. So this also sets an explicit
104 // transform spanning Box A's right edge to Box B's left edge.
105 let connector = Connector::new(4, "Connector")
106 .with_properties(
107 ShapeProperties::new()
108 .with_transform(
109 Transform2D::new()
110 .with_offset(1_838_200, 1_338_200)
111 .with_extent(1_662_000, 0),
112 )
113 .with_line(
114 Line::new()
115 .with_width_emu(25_400)
116 .with_fill(Fill::Solid(Color::Rgb("000000".to_string()))),
117 ),
118 )
119 .with_start_connection(2, 0)
120 .with_end_connection(3, 0);
121
122 let presentation = Presentation::new()
123 .with_slide(Slide::new().with_shape(Shape::Group(group)))
124 .with_slide(Slide::new().with_shape(Shape::Group(rotated_group)))
125 .with_slide(
126 Slide::new()
127 .with_shape(Shape::AutoShape(box_a))
128 .with_shape(Shape::AutoShape(box_b))
129 .with_shape(Shape::Connector(connector)),
130 );
131
132 presentation.save_to_file(&path)?;
133 println!("Wrote {}", path.display());
134 Ok(())
135}Sourcepub fn with_effects(self, effects: EffectList) -> ShapeProperties
pub fn with_effects(self, effects: EffectList) -> ShapeProperties
Sets the shape’s visual effects (<a:effectLst>).
Sourcepub fn with_geometry_adjustments(
self,
adjustments: Vec<GeometryAdjustment>,
) -> ShapeProperties
pub fn with_geometry_adjustments( self, adjustments: Vec<GeometryAdjustment>, ) -> ShapeProperties
Sets a preset shape’s adjustment handle values (<a:avLst>); no effect unless geometry is
also Some(Geometry::Preset(_)).
Trait Implementations§
Source§impl Clone for ShapeProperties
impl Clone for ShapeProperties
Source§fn clone(&self) -> ShapeProperties
fn clone(&self) -> ShapeProperties
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more