pptx_rs/oxml/
presentation.rs1use std::str::FromStr;
33
34use crate::oxml::ns::{NS_DRAWING_MAIN, NS_PRESENTATION_MAIN};
35use crate::oxml::writer::XmlWriter;
36use crate::units::Emu;
37
38#[derive(Clone, Debug)]
40pub struct PresentationRoot {
41 pub slide_width: Option<Emu>,
43 pub slide_height: Option<Emu>,
45 pub slide_ids: Vec<SlideIdEntry>,
47 pub sld_master_ids: Vec<SldMasterIdEntry>,
52 pub notes_master_ids: Vec<NotesMasterIdEntry>,
57 pub default_text_style: Option<String>,
59 pub notes_size: Option<(Emu, Emu)>,
61 pub sections: crate::oxml::section::SectionList,
66}
67
68impl Default for PresentationRoot {
69 fn default() -> Self {
70 Self {
73 slide_width: None,
74 slide_height: None,
75 slide_ids: Vec::new(),
76 sld_master_ids: Vec::new(),
77 notes_master_ids: Vec::new(),
78 default_text_style: Some(DEFAULT_TEXT_STYLE.to_string()),
79 notes_size: None,
80 sections: crate::oxml::section::SectionList::default(),
81 }
82 }
83}
84
85#[derive(Clone, Debug)]
87pub struct SlideIdEntry {
88 pub id: u32,
90 pub rid: String,
92}
93
94#[derive(Clone, Debug)]
98pub struct SldMasterIdEntry {
99 pub id: u32,
101 pub rid: String,
103}
104
105#[derive(Clone, Debug)]
110pub struct NotesMasterIdEntry {
111 pub id: u32,
113 pub rid: String,
115}
116
117impl PresentationRoot {
118 pub fn to_xml(&self) -> String {
120 let mut w = XmlWriter::with_decl();
121 let root_attrs: Vec<(&str, &str)> = vec![
122 ("xmlns:a", NS_DRAWING_MAIN),
123 ("xmlns:p", NS_PRESENTATION_MAIN),
124 ("xmlns:r", crate::oxml::ns::NS_DRAWING_RELS),
125 (
126 "xmlns:p14",
127 "http://schemas.microsoft.com/office/powerpoint/2010/main",
128 ),
129 ];
130 w.open_with("p:presentation", &root_attrs);
131
132 w.open("p:sldMasterIdLst");
134 if self.sld_master_ids.is_empty() {
135 w.empty_with("p:sldMasterId", &[("id", "2147483648"), ("r:id", "rIdP1")]);
137 } else {
138 for m in &self.sld_master_ids {
140 let id_s = m.id.to_string();
141 w.empty_with("p:sldMasterId", &[("id", &id_s), ("r:id", m.rid.as_str())]);
142 }
143 }
144 w.close("p:sldMasterIdLst");
145
146 if !self.notes_master_ids.is_empty() {
149 w.open("p:notesMasterIdLst");
150 for nm in &self.notes_master_ids {
151 let id_s = nm.id.to_string();
152 w.empty_with(
153 "p:notesMasterId",
154 &[("id", &id_s), ("r:id", nm.rid.as_str())],
155 );
156 }
157 w.close("p:notesMasterIdLst");
158 }
159
160 w.open("p:sldIdLst");
162 for s in &self.slide_ids {
163 let id_s = s.id.to_string();
165 w.empty_with("p:sldId", &[("id", &id_s), ("r:id", s.rid.as_str())]);
166 }
167 w.close("p:sldIdLst");
168
169 if let (Some(w_), Some(h)) = (self.slide_width, self.slide_height) {
171 let cx_s = w_.value().to_string();
172 let cy_s = h.value().to_string();
173 w.empty_with("p:sldSz", &[("cx", &cx_s), ("cy", &cy_s)]);
174 }
175 let (nw, nh) = self.notes_size.unwrap_or((Emu(6_858_000), Emu(9_144_000)));
177 let ncx = nw.value().to_string();
178 let ncy = nh.value().to_string();
179 w.empty_with("p:notesSz", &[("cx", &ncx), ("cy", &ncy)]);
180 if let Some(s) = &self.default_text_style {
182 w.raw(s);
183 }
184 let section_xml = self.sections.write_xml();
188 if !section_xml.is_empty() {
189 w.raw(§ion_xml);
190 }
191
192 w.close("p:presentation");
193 w.into_string()
194 }
195}
196
197impl FromStr for PresentationRoot {
198 type Err = crate::Error;
199 fn from_str(_s: &str) -> Result<Self, Self::Err> {
200 Ok(PresentationRoot::default())
202 }
203}
204
205const DEFAULT_TEXT_STYLE: &str = r##"<p:defaultTextStyle><a:defPPr><a:defRPr lang="en-US"/></a:defPPr><a:lvl1pPr marL="0" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl1pPr><a:lvl2pPr marL="457200" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl2pPr><a:lvl3pPr marL="914400" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl3pPr><a:lvl4pPr marL="1371600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl4pPr><a:lvl5pPr marL="1828800" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl5pPr><a:lvl6pPr marL="2286000" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl6pPr><a:lvl7pPr marL="2743200" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl7pPr><a:lvl8pPr marL="3200400" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl8pPr><a:lvl9pPr marL="3657600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl9pPr></p:defaultTextStyle>"##;