1use std::collections::BTreeMap;
2
3use crate::{SlideTiming, SlideTransition};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7#[serde(rename_all = "camelCase")]
8pub struct PictureArtwork {
9 pub svg: String,
10 #[serde(default, skip_serializing_if = "Option::is_none")]
11 pub paint_bounds: Option<rust_office_art::PaintBounds>,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(rename_all = "lowercase")]
16pub enum PresentationFormat {
17 Pptx,
18 Ppt,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22#[serde(rename_all = "camelCase")]
23pub struct PresentationSize {
24 pub width_emu: u64,
25 pub height_emu: u64,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct PresentationWarning {
31 pub code: String,
32 pub message: String,
33 pub severity: String,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub slide_index: Option<usize>,
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub node_id: Option<String>,
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub part_name: Option<String>,
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub feature: Option<String>,
42}
43
44impl PresentationWarning {
45 pub fn warning(code: &str, message: impl Into<String>) -> Self {
46 Self {
47 code: code.into(),
48 message: message.into(),
49 severity: "warning".into(),
50 slide_index: None,
51 node_id: None,
52 part_name: None,
53 feature: None,
54 }
55 }
56}
57
58#[derive(Debug, Clone, Default, Serialize, Deserialize)]
59#[serde(rename_all = "camelCase")]
60pub struct PresentationMetadata {
61 #[serde(skip_serializing_if = "Option::is_none")]
62 pub title: Option<String>,
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub subject: Option<String>,
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub creator: Option<String>,
67 #[serde(skip_serializing_if = "Option::is_none")]
68 pub company: Option<String>,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
72#[serde(rename_all = "camelCase")]
73pub struct PresentationAsset {
74 pub id: String,
75 pub content_type: String,
76 pub byte_length: usize,
77 #[serde(skip_serializing_if = "Option::is_none")]
78 pub file_name: Option<String>,
79 #[serde(skip_serializing_if = "Option::is_none")]
80 pub data: Option<serde_bytes::ByteBuf>,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84#[serde(rename_all = "camelCase")]
85pub struct PresentationEmbeddedFont {
86 pub family: String,
87 pub asset_id: String,
88 pub style: String,
89 pub weight: String,
90}
91
92#[derive(Debug, Clone, Default, Serialize, Deserialize)]
93#[serde(rename_all = "camelCase")]
94pub struct Transform {
95 pub x: i64,
96 pub y: i64,
97 pub width: i64,
98 pub height: i64,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub rotation: Option<f64>,
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub flip_horizontal: Option<bool>,
103 #[serde(skip_serializing_if = "Option::is_none")]
104 pub flip_vertical: Option<bool>,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
108#[serde(
109 tag = "type",
110 rename_all = "kebab-case",
111 rename_all_fields = "camelCase"
112)]
113#[allow(clippy::large_enum_variant)]
114pub enum SlideNode {
115 Shape {
116 #[serde(flatten, default)]
117 metadata: Option<Box<NodeMetadata>>,
118 id: String,
119 name: String,
120 transform: Transform,
121 geometry: ShapeGeometry,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 shape_svg: Option<String>,
124 #[serde(skip_serializing_if = "Option::is_none")]
125 paint_bounds: Option<rust_office_art::PaintBounds>,
126 #[serde(skip_serializing_if = "Option::is_none")]
127 source_xml: Option<String>,
128 #[serde(skip_serializing_if = "Option::is_none")]
129 fill: Option<FillStyle>,
130 #[serde(skip_serializing_if = "Option::is_none")]
131 line: Option<LineStyle>,
132 paragraphs: Vec<TextParagraph>,
133 #[serde(skip_serializing_if = "Option::is_none")]
134 vertical_alignment: Option<VerticalAlignment>,
135 #[serde(skip_serializing_if = "Option::is_none")]
136 text_insets: Option<TextInsets>,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 autofit: Option<TextAutofit>,
139 #[serde(skip_serializing_if = "Option::is_none")]
140 text_rotation: Option<f64>,
141 #[serde(default, skip_serializing_if = "Option::is_none")]
142 text_transform: Option<Transform>,
143 #[serde(skip_serializing_if = "Option::is_none")]
144 vertical_text: Option<String>,
145 #[serde(skip_serializing_if = "Option::is_none")]
146 horizontal_overflow: Option<String>,
147 #[serde(skip_serializing_if = "Option::is_none")]
148 vertical_overflow: Option<String>,
149 #[serde(skip_serializing_if = "Option::is_none")]
150 text_wrap: Option<String>,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 column_count: Option<usize>,
153 #[serde(skip_serializing_if = "Option::is_none")]
154 column_spacing: Option<i64>,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 right_to_left_columns: Option<bool>,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 space_first_last_paragraph: Option<bool>,
159 },
160 Image {
161 #[serde(flatten, default)]
162 metadata: Option<Box<NodeMetadata>>,
163 #[serde(default, rename = "model3d", skip_serializing_if = "Option::is_none")]
164 model_3d: Option<Box<rust_office_art::model3d::Model3D>>,
165 #[serde(default, skip_serializing_if = "Option::is_none")]
166 ink: Option<Box<InkContent>>,
167 id: String,
168 name: String,
169 transform: Transform,
170 asset_id: String,
171 #[serde(default, skip_serializing_if = "Option::is_none")]
172 fallback_asset_id: Option<String>,
173 #[serde(skip_serializing_if = "Option::is_none")]
174 crop: Option<ImageCrop>,
175 #[serde(skip_serializing_if = "Option::is_none")]
176 opacity: Option<f64>,
177 preserve_aspect_ratio: bool,
178 #[serde(skip_serializing_if = "Option::is_none")]
179 effects: Option<ImageEffects>,
180 #[serde(skip_serializing_if = "Option::is_none")]
181 picture_svg: Option<String>,
182 #[serde(default, skip_serializing_if = "Option::is_none")]
183 fallback_picture: Option<Box<PictureArtwork>>,
184 #[serde(skip_serializing_if = "Option::is_none")]
185 paint_bounds: Option<rust_office_art::PaintBounds>,
186 #[serde(skip_serializing_if = "Option::is_none")]
187 source_xml: Option<String>,
188 },
189 Group {
190 #[serde(flatten, default)]
191 metadata: Option<Box<NodeMetadata>>,
192 id: String,
193 name: String,
194 transform: Transform,
195 children: Vec<SlideNode>,
196 #[serde(skip_serializing_if = "Option::is_none")]
197 child_transform: Option<Transform>,
198 },
199 Table {
200 #[serde(flatten, default)]
201 metadata: Option<Box<NodeMetadata>>,
202 id: String,
203 name: String,
204 transform: Transform,
205 rows: Vec<Vec<TableCell>>,
206 #[serde(skip_serializing_if = "Vec::is_empty")]
207 column_widths: Vec<i64>,
208 #[serde(skip_serializing_if = "Vec::is_empty")]
209 row_heights: Vec<i64>,
210 },
211 Chart {
212 #[serde(flatten, default)]
213 metadata: Option<Box<NodeMetadata>>,
214 id: String,
215 name: String,
216 transform: Transform,
217 chart_type: String,
218 #[serde(skip_serializing_if = "Option::is_none")]
219 title: Option<String>,
220 series: Vec<ChartSeries>,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 has_legend: Option<bool>,
223 #[serde(skip_serializing_if = "Option::is_none")]
226 chart_xml: Option<String>,
227 #[serde(skip_serializing_if = "Option::is_none")]
229 chart_svg: Option<String>,
230 #[serde(skip_serializing_if = "Option::is_none")]
232 chart_style_xml: Option<String>,
233 #[serde(skip_serializing_if = "Option::is_none")]
235 chart_colors_xml: Option<String>,
236 },
237 Media {
238 #[serde(flatten, default)]
239 metadata: Option<Box<NodeMetadata>>,
240 id: String,
241 name: String,
242 transform: Transform,
243 media_type: MediaType,
244 #[serde(skip_serializing_if = "Option::is_none")]
245 asset_id: Option<String>,
246 #[serde(skip_serializing_if = "Option::is_none")]
247 source_url: Option<String>,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 poster_asset_id: Option<String>,
250 #[serde(skip_serializing_if = "Option::is_none")]
251 poster: Option<Box<SlideNode>>,
252 #[serde(skip_serializing_if = "Option::is_none")]
253 playback: Option<MediaPlayback>,
254 #[serde(skip_serializing_if = "Option::is_none")]
255 embedded_object: Option<EmbeddedObject>,
256 #[serde(skip_serializing_if = "Option::is_none")]
257 source_xml: Option<String>,
258 },
259 Unknown {
260 #[serde(flatten, default)]
261 metadata: Option<Box<NodeMetadata>>,
262 id: String,
263 name: String,
264 transform: Transform,
265 feature: String,
266 },
267}
268
269impl SlideNode {
270 pub fn metadata_mut(&mut self) -> &mut NodeMetadata {
271 match self {
272 Self::Shape { metadata, .. }
273 | Self::Image { metadata, .. }
274 | Self::Group { metadata, .. }
275 | Self::Table { metadata, .. }
276 | Self::Chart { metadata, .. }
277 | Self::Media { metadata, .. }
278 | Self::Unknown { metadata, .. } => metadata.get_or_insert_with(Default::default),
279 }
280 }
281}
282
283#[derive(Debug, Clone, Serialize, Deserialize)]
284#[serde(rename_all = "camelCase")]
285pub struct InkContent {
286 #[serde(skip_serializing_if = "Option::is_none")]
287 pub asset_id: Option<String>,
288 #[serde(skip_serializing_if = "Option::is_none")]
289 pub source_xml: Option<String>,
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub drawing: Option<Box<rust_office_art::InkDrawing>>,
292}
293
294#[derive(Debug, Clone, Default, Serialize, Deserialize)]
295#[serde(rename_all = "camelCase")]
296pub struct NodeMetadata {
297 #[serde(default, skip_serializing_if = "Option::is_none")]
298 pub editing: Option<Box<ObjectEditing>>,
299 #[serde(skip_serializing_if = "Option::is_none")]
300 pub source_id: Option<String>,
301 #[serde(skip_serializing_if = "Option::is_none")]
302 pub hidden: Option<bool>,
303 #[serde(skip_serializing_if = "Option::is_none")]
304 pub alt_text: Option<String>,
305 #[serde(skip_serializing_if = "Option::is_none")]
306 pub accessibility_title: Option<String>,
307 #[serde(skip_serializing_if = "Option::is_none")]
308 pub description: Option<String>,
309 #[serde(skip_serializing_if = "Option::is_none")]
310 pub decorative: Option<bool>,
311 #[serde(skip_serializing_if = "Option::is_none")]
312 pub hyperlink: Option<String>,
313 #[serde(skip_serializing_if = "Option::is_none")]
314 pub click_action: Option<Box<ObjectAction>>,
315 #[serde(skip_serializing_if = "Option::is_none")]
316 pub hover_action: Option<Box<ObjectAction>>,
317 #[serde(skip_serializing_if = "Option::is_none")]
318 pub source_part: Option<String>,
319}
320
321#[derive(Debug, Clone, Serialize, Deserialize)]
322#[serde(rename_all = "camelCase")]
323pub struct ObjectEditing {
324 pub kind: ObjectEditingKind,
325 #[serde(skip_serializing_if = "Option::is_none")]
326 pub locks: Option<ObjectLocks>,
327 #[serde(skip_serializing_if = "Option::is_none")]
328 pub connector: Option<ConnectorConnections>,
329 #[serde(skip_serializing_if = "Option::is_none")]
330 pub text_box: Option<bool>,
331 #[serde(skip_serializing_if = "Option::is_none")]
332 pub prefer_relative_resize: Option<bool>,
333 #[serde(skip_serializing_if = "Option::is_none")]
334 pub is_comment: Option<bool>,
335 pub source_xml: String,
336}
337
338#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
339#[serde(rename_all = "camelCase")]
340pub enum ObjectEditingKind {
341 Shape,
342 Connector,
343 Picture,
344 Group,
345 GraphicFrame,
346 ContentPart,
347}
348
349#[derive(Debug, Clone, Default, Serialize, Deserialize)]
350#[serde(rename_all = "camelCase")]
351pub struct ObjectLocks {
352 #[serde(skip_serializing_if = "Option::is_none")]
353 pub no_grouping: Option<bool>,
354 #[serde(skip_serializing_if = "Option::is_none")]
355 pub no_ungrouping: Option<bool>,
356 #[serde(skip_serializing_if = "Option::is_none")]
357 pub no_selection: Option<bool>,
358 #[serde(skip_serializing_if = "Option::is_none")]
359 pub no_rotation: Option<bool>,
360 #[serde(skip_serializing_if = "Option::is_none")]
361 pub no_change_aspect: Option<bool>,
362 #[serde(skip_serializing_if = "Option::is_none")]
363 pub no_move: Option<bool>,
364 #[serde(skip_serializing_if = "Option::is_none")]
365 pub no_resize: Option<bool>,
366 #[serde(skip_serializing_if = "Option::is_none")]
367 pub no_edit_points: Option<bool>,
368 #[serde(skip_serializing_if = "Option::is_none")]
369 pub no_adjust_handles: Option<bool>,
370 #[serde(skip_serializing_if = "Option::is_none")]
371 pub no_change_arrowheads: Option<bool>,
372 #[serde(skip_serializing_if = "Option::is_none")]
373 pub no_change_shape_type: Option<bool>,
374 #[serde(skip_serializing_if = "Option::is_none")]
375 pub no_text_edit: Option<bool>,
376 #[serde(skip_serializing_if = "Option::is_none")]
377 pub no_crop: Option<bool>,
378 #[serde(skip_serializing_if = "Option::is_none")]
379 pub no_drilldown: Option<bool>,
380}
381
382#[derive(Debug, Clone, Default, Serialize, Deserialize)]
383#[serde(rename_all = "camelCase")]
384pub struct ConnectorConnections {
385 #[serde(skip_serializing_if = "Option::is_none")]
386 pub start: Option<ConnectorEndpoint>,
387 #[serde(skip_serializing_if = "Option::is_none")]
388 pub end: Option<ConnectorEndpoint>,
389}
390
391#[derive(Debug, Clone, Serialize, Deserialize)]
392#[serde(rename_all = "camelCase")]
393pub struct ConnectorEndpoint {
394 pub shape_id: u32,
395 pub connection_site: u32,
396}
397
398#[derive(Debug, Clone, Default, Serialize, Deserialize)]
399#[serde(rename_all = "camelCase")]
400pub struct ObjectAction {
401 #[serde(skip_serializing_if = "Option::is_none")]
402 pub external: Option<bool>,
403 #[serde(skip_serializing_if = "Option::is_none")]
404 pub relationship_id: Option<String>,
405 #[serde(skip_serializing_if = "Option::is_none")]
406 pub target: Option<String>,
407 #[serde(skip_serializing_if = "Option::is_none")]
408 pub action: Option<String>,
409 #[serde(skip_serializing_if = "Option::is_none")]
410 pub tooltip: Option<String>,
411 #[serde(skip_serializing_if = "Option::is_none")]
412 pub target_frame: Option<String>,
413 #[serde(skip_serializing_if = "Option::is_none")]
414 pub invalid_url: Option<String>,
415 #[serde(skip_serializing_if = "Option::is_none")]
416 pub history: Option<bool>,
417 #[serde(skip_serializing_if = "Option::is_none")]
418 pub highlight_click: Option<bool>,
419 #[serde(skip_serializing_if = "Option::is_none")]
420 pub end_sound: Option<bool>,
421 #[serde(skip_serializing_if = "Option::is_none")]
422 pub sound_asset_id: Option<String>,
423 #[serde(skip_serializing_if = "Option::is_none")]
424 pub sound_name: Option<String>,
425 #[serde(skip_serializing_if = "Option::is_none")]
426 pub sound_builtin: Option<bool>,
427}
428
429#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
430#[serde(rename_all = "lowercase")]
431pub enum MediaType {
432 Audio,
433 Video,
434 Ole,
435 Control,
436 Unknown,
437}
438
439#[derive(Debug, Clone, Default, Serialize, Deserialize)]
440#[serde(rename_all = "camelCase")]
441pub struct MediaPlayback {
442 #[serde(skip_serializing_if = "Option::is_none")]
443 pub trim_start_ms: Option<f64>,
444 #[serde(skip_serializing_if = "Option::is_none")]
445 pub trim_end_ms: Option<f64>,
446 #[serde(skip_serializing_if = "Option::is_none")]
447 pub fade_in_ms: Option<f64>,
448 #[serde(skip_serializing_if = "Option::is_none")]
449 pub fade_out_ms: Option<f64>,
450 #[serde(default, skip_serializing_if = "Vec::is_empty")]
451 pub bookmarks: Vec<MediaBookmark>,
452}
453
454#[derive(Debug, Clone, Serialize, Deserialize)]
455#[serde(rename_all = "camelCase")]
456pub struct MediaBookmark {
457 pub name: String,
458 pub time_ms: f64,
459}
460
461#[derive(Debug, Clone, Default, Serialize, Deserialize)]
462#[serde(rename_all = "camelCase")]
463pub struct EmbeddedObject {
464 #[serde(skip_serializing_if = "Option::is_none")]
465 pub control: Option<Box<EmbeddedControl>>,
466 #[serde(skip_serializing_if = "Option::is_none")]
467 pub program_id: Option<String>,
468 #[serde(skip_serializing_if = "Option::is_none")]
469 pub name: Option<String>,
470 #[serde(skip_serializing_if = "Option::is_none")]
471 pub relationship_id: Option<String>,
472 pub linked: bool,
473 #[serde(skip_serializing_if = "Option::is_none")]
474 pub show_as_icon: Option<bool>,
475 #[serde(skip_serializing_if = "Option::is_none")]
476 pub preview_width_emu: Option<u64>,
477 #[serde(skip_serializing_if = "Option::is_none")]
478 pub preview_height_emu: Option<u64>,
479 #[serde(skip_serializing_if = "Option::is_none")]
480 pub follow_color_scheme: Option<String>,
481 #[serde(skip_serializing_if = "Option::is_none")]
482 pub update_automatic: Option<bool>,
483}
484
485#[derive(Debug, Clone, Default, Serialize, Deserialize)]
486#[serde(rename_all = "camelCase")]
487pub struct EmbeddedControl {
488 #[serde(skip_serializing_if = "Option::is_none")]
489 pub class_id: Option<String>,
490 #[serde(skip_serializing_if = "Option::is_none")]
491 pub persistence: Option<String>,
492 #[serde(skip_serializing_if = "Option::is_none")]
493 pub source_xml: Option<String>,
494 #[serde(default, skip_serializing_if = "Vec::is_empty")]
495 pub binary_asset_ids: Vec<String>,
496 #[serde(default, skip_serializing_if = "Vec::is_empty")]
497 pub properties: Vec<ControlProperty>,
498}
499
500#[derive(Debug, Clone, Serialize, Deserialize)]
501#[serde(rename_all = "camelCase")]
502pub struct ControlProperty {
503 pub name: String,
504 #[serde(skip_serializing_if = "Option::is_none")]
505 pub value: Option<String>,
506}
507
508#[derive(Debug, Clone, Serialize, Deserialize)]
509#[serde(rename_all = "camelCase")]
510pub struct TableCell {
511 #[serde(skip_serializing_if = "Option::is_none")]
512 pub merge: Option<Box<TableCellMerge>>,
513 #[serde(skip_serializing_if = "Option::is_none")]
514 pub row_span: Option<usize>,
515 #[serde(skip_serializing_if = "Option::is_none")]
516 pub col_span: Option<usize>,
517 #[serde(skip_serializing_if = "Option::is_none")]
518 pub fill: Option<FillStyle>,
519 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
520 pub borders: BTreeMap<String, LineStyle>,
521 pub paragraphs: Vec<TextParagraph>,
522 #[serde(skip_serializing_if = "Option::is_none")]
523 pub text_insets: Option<TextInsets>,
524 #[serde(skip_serializing_if = "Option::is_none")]
525 pub vertical_alignment: Option<VerticalAlignment>,
526 #[serde(skip_serializing_if = "Option::is_none")]
527 pub text_rotation: Option<f64>,
528}
529
530#[derive(Debug, Clone, Serialize, Deserialize)]
531#[serde(rename_all = "camelCase")]
532pub struct TableCellMerge {
533 pub horizontal: bool,
534 pub vertical: bool,
535 #[serde(skip_serializing_if = "Option::is_none")]
536 pub origin: Option<TableCellPosition>,
537}
538
539#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
540pub struct TableCellPosition {
541 pub row: usize,
542 pub column: usize,
543}
544
545#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
546#[serde(rename_all = "camelCase")]
547pub struct TextInsets {
548 pub top: i64,
549 pub right: i64,
550 pub bottom: i64,
551 pub left: i64,
552}
553
554#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
555#[serde(rename_all = "camelCase")]
556pub struct ImageCrop {
557 pub top: f64,
558 pub right: f64,
559 pub bottom: f64,
560 pub left: f64,
561}
562
563#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
565#[serde(rename_all = "camelCase")]
566pub struct ImageEffects {
567 #[serde(skip_serializing_if = "Option::is_none")]
569 pub bi_level_threshold: Option<f64>,
570 #[serde(skip_serializing_if = "Option::is_none")]
572 pub grayscale: Option<bool>,
573 #[serde(skip_serializing_if = "Option::is_none")]
575 pub duotone: Option<Vec<ColorValue>>,
576 #[serde(skip_serializing_if = "Option::is_none")]
578 pub brightness: Option<f64>,
579 #[serde(skip_serializing_if = "Option::is_none")]
581 pub contrast: Option<f64>,
582}
583
584#[derive(Debug, Clone, Serialize, Deserialize)]
585#[serde(rename_all = "camelCase")]
586pub struct ChartSeries {
587 #[serde(skip_serializing_if = "Option::is_none")]
588 pub name: Option<String>,
589 #[serde(skip_serializing_if = "Option::is_none")]
590 pub categories: Option<Vec<serde_json::Value>>,
591 pub values: Vec<Option<f64>>,
592 #[serde(skip_serializing_if = "Option::is_none")]
593 pub color: Option<ColorValue>,
594}
595
596#[derive(Debug, Clone, Default, Serialize, Deserialize)]
597pub struct ShapeGeometry {
598 #[serde(skip_serializing_if = "Option::is_none")]
599 pub preset: Option<String>,
600 #[serde(skip_serializing_if = "Option::is_none")]
602 pub path: Option<String>,
603}
604
605#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
606#[serde(rename_all = "camelCase")]
607pub struct ColorValue {
608 pub value: String,
609 #[serde(skip_serializing_if = "Option::is_none")]
610 pub alpha: Option<f64>,
611}
612
613#[derive(Debug, Clone, Serialize, Deserialize)]
614#[serde(rename_all = "camelCase")]
615pub struct GradientStop {
616 pub position: f64,
617 pub color: ColorValue,
618}
619
620#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
621#[serde(rename_all = "lowercase")]
622pub enum FillImageMode {
623 Stretch,
624 Tile,
625}
626
627#[derive(Debug, Clone, Serialize, Deserialize)]
628#[serde(
629 tag = "type",
630 rename_all = "lowercase",
631 rename_all_fields = "camelCase"
632)]
633pub enum FillStyle {
634 None,
635 Solid {
636 color: ColorValue,
637 },
638 Gradient {
639 #[serde(skip_serializing_if = "Option::is_none")]
640 angle: Option<f64>,
641 stops: Vec<GradientStop>,
642 },
643 Pattern {
644 preset: String,
645 foreground: ColorValue,
646 background: ColorValue,
647 },
648 Image {
649 asset_id: String,
650 mode: FillImageMode,
651 #[serde(skip_serializing_if = "Option::is_none")]
652 crop: Option<ImageCrop>,
653 #[serde(skip_serializing_if = "Option::is_none")]
654 opacity: Option<f64>,
655 #[serde(skip_serializing_if = "Option::is_none")]
656 effects: Option<ImageEffects>,
657 },
658}
659
660#[derive(Debug, Clone, Default, Serialize, Deserialize)]
661#[serde(rename_all = "camelCase")]
662pub struct LineStyle {
663 #[serde(skip_serializing_if = "Option::is_none")]
664 pub color: Option<ColorValue>,
665 #[serde(skip_serializing_if = "Option::is_none")]
666 pub width: Option<f64>,
667 #[serde(skip_serializing_if = "Option::is_none")]
668 pub dash: Option<String>,
669 #[serde(skip_serializing_if = "Option::is_none")]
670 pub start_arrow: Option<String>,
671 #[serde(skip_serializing_if = "Option::is_none")]
672 pub end_arrow: Option<String>,
673}
674
675#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
676#[serde(rename_all = "lowercase")]
677pub enum VerticalAlignment {
678 Top,
679 Middle,
680 Bottom,
681}
682
683#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
684#[serde(rename_all = "lowercase")]
685pub enum TextAutoFitMode {
686 None,
687 Normal,
688 Shape,
689}
690
691#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
692#[serde(rename_all = "camelCase")]
693pub struct TextAutofit {
694 pub mode: TextAutoFitMode,
695 #[serde(skip_serializing_if = "Option::is_none")]
696 pub font_scale: Option<f64>,
697 #[serde(skip_serializing_if = "Option::is_none")]
698 pub line_spacing_reduction: Option<f64>,
699}
700
701#[derive(Debug, Clone, Default, Serialize, Deserialize)]
702#[serde(rename_all = "camelCase")]
703pub struct TextParagraph {
704 pub runs: Vec<TextRun>,
705 #[serde(skip_serializing_if = "Option::is_none")]
706 pub alignment: Option<String>,
707 #[serde(skip_serializing_if = "Option::is_none")]
708 pub level: Option<usize>,
709 #[serde(skip_serializing_if = "Option::is_none")]
710 pub bullet: Option<TextBullet>,
711 #[serde(skip_serializing_if = "Option::is_none")]
712 pub line_spacing: Option<TextSpacing>,
713 #[serde(skip_serializing_if = "Option::is_none")]
714 pub space_before: Option<TextSpacing>,
715 #[serde(skip_serializing_if = "Option::is_none")]
716 pub space_after: Option<TextSpacing>,
717 #[serde(skip_serializing_if = "Option::is_none")]
718 pub rtl: Option<bool>,
719 #[serde(skip_serializing_if = "Option::is_none")]
720 pub margin_left_emu: Option<i64>,
721 #[serde(skip_serializing_if = "Option::is_none")]
722 pub indent_emu: Option<i64>,
723 #[serde(skip_serializing_if = "Option::is_none")]
724 pub default_tab_size_emu: Option<i64>,
725 #[serde(skip_serializing_if = "Option::is_none")]
726 pub tab_stops: Option<Vec<TextTabStop>>,
727 #[serde(skip_serializing_if = "Option::is_none")]
728 pub east_asian_line_break: Option<bool>,
729 #[serde(skip_serializing_if = "Option::is_none")]
730 pub latin_line_break: Option<bool>,
731 #[serde(skip_serializing_if = "Option::is_none")]
732 pub hanging_punctuation: Option<bool>,
733}
734
735#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
736#[serde(rename_all = "lowercase")]
737pub enum TextTabAlignment {
738 Left,
739 Center,
740 Right,
741 Decimal,
742}
743
744#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
745#[serde(rename_all = "camelCase")]
746pub struct TextTabStop {
747 pub position_emu: i64,
748 pub alignment: TextTabAlignment,
749}
750
751#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
752#[serde(rename_all = "camelCase")]
753pub struct TextSpacing {
754 pub value: f64,
755 pub unit: TextSpacingUnit,
756}
757
758#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
759#[serde(rename_all = "lowercase")]
760pub enum TextSpacingUnit {
761 Points,
762 Percent,
763}
764
765#[derive(Debug, Clone, Serialize, Deserialize)]
766#[serde(rename_all = "camelCase")]
767pub struct TextBullet {
768 pub kind: String,
769 #[serde(skip_serializing_if = "Option::is_none")]
770 pub value: Option<String>,
771 #[serde(skip_serializing_if = "Option::is_none")]
772 pub font_family: Option<String>,
773 #[serde(skip_serializing_if = "Option::is_none")]
774 pub font_size_pt: Option<f64>,
775 #[serde(skip_serializing_if = "Option::is_none")]
776 pub size_percent: Option<f64>,
777 #[serde(skip_serializing_if = "Option::is_none")]
778 pub start_at: Option<usize>,
779}
780
781#[derive(Debug, Clone, Default, Serialize, Deserialize)]
782#[serde(rename_all = "camelCase")]
783pub struct TextRunProperties {
784 #[serde(skip_serializing_if = "Option::is_none")]
785 pub font_family: Option<String>,
786 #[serde(skip_serializing_if = "Option::is_none")]
787 pub east_asian_font_family: Option<String>,
788 #[serde(skip_serializing_if = "Option::is_none")]
789 pub complex_script_font_family: Option<String>,
790 #[serde(skip_serializing_if = "Option::is_none")]
791 pub symbol_font_family: Option<String>,
792 #[serde(skip_serializing_if = "Option::is_none")]
793 pub font_size_pt: Option<f64>,
794 #[serde(skip_serializing_if = "Option::is_none")]
795 pub bold: Option<bool>,
796 #[serde(skip_serializing_if = "Option::is_none")]
797 pub italic: Option<bool>,
798 #[serde(skip_serializing_if = "Option::is_none")]
799 pub underline: Option<bool>,
800 #[serde(skip_serializing_if = "Option::is_none")]
801 pub strike: Option<bool>,
802 #[serde(skip_serializing_if = "Option::is_none")]
803 pub color: Option<ColorValue>,
804 #[serde(skip_serializing_if = "Option::is_none")]
805 pub baseline: Option<f64>,
806 #[serde(skip_serializing_if = "Option::is_none")]
807 pub language: Option<String>,
808 #[serde(skip_serializing_if = "Option::is_none")]
809 pub alternative_language: Option<String>,
810 #[serde(skip_serializing_if = "Option::is_none")]
811 pub right_to_left: Option<bool>,
812 #[serde(skip_serializing_if = "Option::is_none")]
813 pub hyperlink: Option<String>,
814 #[serde(skip_serializing_if = "Option::is_none")]
815 pub character_spacing_pt: Option<f64>,
816 #[serde(skip_serializing_if = "Option::is_none")]
817 pub kerning_threshold_pt: Option<f64>,
818}
819
820#[derive(Debug, Clone, Default, Serialize, Deserialize)]
821#[serde(rename_all = "camelCase")]
822pub struct TextFieldParagraphProperties {
823 #[serde(skip_serializing_if = "Option::is_none")]
824 pub alignment: Option<String>,
825 #[serde(skip_serializing_if = "Option::is_none")]
826 pub level: Option<usize>,
827 #[serde(skip_serializing_if = "Option::is_none")]
828 pub bullet: Option<TextBullet>,
829 #[serde(skip_serializing_if = "Option::is_none")]
830 pub line_spacing: Option<TextSpacing>,
831 #[serde(skip_serializing_if = "Option::is_none")]
832 pub space_before: Option<TextSpacing>,
833 #[serde(skip_serializing_if = "Option::is_none")]
834 pub space_after: Option<TextSpacing>,
835 #[serde(skip_serializing_if = "Option::is_none")]
836 pub rtl: Option<bool>,
837 #[serde(skip_serializing_if = "Option::is_none")]
838 pub margin_left_emu: Option<i64>,
839 #[serde(skip_serializing_if = "Option::is_none")]
840 pub indent_emu: Option<i64>,
841 #[serde(skip_serializing_if = "Option::is_none")]
842 pub default_tab_size_emu: Option<i64>,
843 #[serde(skip_serializing_if = "Option::is_none")]
844 pub tab_stops: Option<Vec<TextTabStop>>,
845 #[serde(skip_serializing_if = "Option::is_none")]
846 pub east_asian_line_break: Option<bool>,
847 #[serde(skip_serializing_if = "Option::is_none")]
848 pub latin_line_break: Option<bool>,
849 #[serde(skip_serializing_if = "Option::is_none")]
850 pub hanging_punctuation: Option<bool>,
851 #[serde(skip_serializing_if = "Option::is_none")]
852 pub margin_right_emu: Option<i64>,
853 #[serde(skip_serializing_if = "Option::is_none")]
854 pub font_alignment: Option<String>,
855 #[serde(skip_serializing_if = "Option::is_none")]
856 pub bullet_none: Option<bool>,
857 #[serde(skip_serializing_if = "Option::is_none")]
858 pub bullet_color: Option<ColorValue>,
859 #[serde(skip_serializing_if = "Option::is_none")]
860 pub bullet_color_follow_text: Option<bool>,
861 #[serde(skip_serializing_if = "Option::is_none")]
862 pub bullet_font_follow_text: Option<bool>,
863 #[serde(skip_serializing_if = "Option::is_none")]
864 pub bullet_size_follow_text: Option<bool>,
865 #[serde(skip_serializing_if = "Option::is_none")]
866 pub bullet_image_asset_id: Option<String>,
867 #[serde(skip_serializing_if = "Option::is_none")]
868 pub default_run_properties: Option<TextRunProperties>,
869}
870
871#[derive(Debug, Clone, Serialize, Deserialize)]
872#[serde(rename_all = "camelCase")]
873pub struct TextField {
874 #[serde(skip_serializing_if = "Option::is_none")]
875 pub id: Option<String>,
876 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
877 pub field_type: Option<String>,
878 pub has_cached_text: bool,
879 #[serde(skip_serializing_if = "Option::is_none")]
880 pub paragraph_properties: Option<Box<TextFieldParagraphProperties>>,
881 #[serde(skip_serializing_if = "Option::is_none")]
882 pub source_part: Option<String>,
883 pub source_xml: String,
884}
885
886#[derive(Debug, Clone, Default, Serialize, Deserialize)]
887#[serde(rename_all = "camelCase")]
888pub struct TextRun {
889 pub text: String,
890 #[serde(default, skip_serializing_if = "Option::is_none")]
891 pub field: Option<Box<TextField>>,
892 #[serde(default, skip_serializing_if = "Option::is_none")]
893 pub math: Option<Box<rust_office_art::OfficeMath>>,
894 #[serde(skip_serializing_if = "Option::is_none")]
895 pub font_family: Option<String>,
896 #[serde(skip_serializing_if = "Option::is_none")]
897 pub east_asian_font_family: Option<String>,
898 #[serde(skip_serializing_if = "Option::is_none")]
899 pub complex_script_font_family: Option<String>,
900 #[serde(skip_serializing_if = "Option::is_none")]
901 pub symbol_font_family: Option<String>,
902 #[serde(skip_serializing_if = "Option::is_none")]
903 pub font_size_pt: Option<f64>,
904 #[serde(skip_serializing_if = "Option::is_none")]
905 pub bold: Option<bool>,
906 #[serde(skip_serializing_if = "Option::is_none")]
907 pub italic: Option<bool>,
908 #[serde(skip_serializing_if = "Option::is_none")]
909 pub underline: Option<bool>,
910 #[serde(skip_serializing_if = "Option::is_none")]
911 pub strike: Option<bool>,
912 #[serde(skip_serializing_if = "Option::is_none")]
913 pub color: Option<ColorValue>,
914 #[serde(skip_serializing_if = "Option::is_none")]
915 pub baseline: Option<f64>,
916 #[serde(skip_serializing_if = "Option::is_none")]
917 pub language: Option<String>,
918 #[serde(skip_serializing_if = "Option::is_none")]
919 pub alternative_language: Option<String>,
920 #[serde(skip_serializing_if = "Option::is_none")]
921 pub right_to_left: Option<bool>,
922 #[serde(skip_serializing_if = "Option::is_none")]
923 pub hyperlink: Option<String>,
924 #[serde(skip_serializing_if = "Option::is_none")]
925 pub character_spacing_pt: Option<f64>,
926 #[serde(skip_serializing_if = "Option::is_none")]
927 pub kerning_threshold_pt: Option<f64>,
928}
929
930#[derive(Debug, Clone, Serialize, Deserialize)]
931#[serde(rename_all = "camelCase")]
932pub struct PresentationTheme {
933 pub id: String,
934 #[serde(skip_serializing_if = "Option::is_none")]
935 pub name: Option<String>,
936 pub colors: BTreeMap<String, String>,
937 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
938 pub major_fonts: BTreeMap<String, String>,
939 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
940 pub minor_fonts: BTreeMap<String, String>,
941 #[serde(skip_serializing_if = "Option::is_none")]
942 pub format_scheme_xml: Option<String>,
943}
944
945#[derive(Debug, Clone, Serialize, Deserialize)]
946#[serde(rename_all = "camelCase")]
947pub struct SlideMaster {
948 pub id: String,
949 #[serde(skip_serializing_if = "Option::is_none")]
950 pub name: Option<String>,
951 #[serde(skip_serializing_if = "Option::is_none")]
952 pub theme_id: Option<String>,
953 #[serde(skip_serializing_if = "Option::is_none")]
954 pub transition: Option<Box<SlideTransition>>,
955 #[serde(skip_serializing_if = "Option::is_none")]
956 pub timing: Option<Box<SlideTiming>>,
957 pub nodes: Vec<SlideNode>,
958}
959
960#[derive(Debug, Clone, Serialize, Deserialize)]
961#[serde(rename_all = "camelCase")]
962pub struct SlideLayout {
963 pub id: String,
964 #[serde(skip_serializing_if = "Option::is_none")]
965 pub name: Option<String>,
966 #[serde(skip_serializing_if = "Option::is_none")]
967 pub master_id: Option<String>,
968 #[serde(skip_serializing_if = "Option::is_none")]
969 pub transition: Option<Box<SlideTransition>>,
970 #[serde(skip_serializing_if = "Option::is_none")]
971 pub timing: Option<Box<SlideTiming>>,
972 pub nodes: Vec<SlideNode>,
973}
974
975#[derive(Debug, Clone, Serialize, Deserialize)]
976#[serde(rename_all = "camelCase")]
977pub struct PresentationSlide {
978 pub id: String,
979 pub index: usize,
980 #[serde(skip_serializing_if = "Option::is_none")]
981 pub name: Option<String>,
982 #[serde(skip_serializing_if = "Option::is_none")]
983 pub hidden: Option<bool>,
984 #[serde(skip_serializing_if = "Option::is_none")]
985 pub master_id: Option<String>,
986 #[serde(skip_serializing_if = "Option::is_none")]
987 pub layout_id: Option<String>,
988 #[serde(skip_serializing_if = "Option::is_none")]
989 pub background: Option<FillStyle>,
990 #[serde(skip_serializing_if = "Option::is_none")]
991 pub transition: Option<Box<SlideTransition>>,
992 #[serde(skip_serializing_if = "Option::is_none")]
993 pub timing: Option<Box<SlideTiming>>,
994 pub nodes: Vec<SlideNode>,
995 #[serde(skip_serializing_if = "Vec::is_empty")]
996 pub notes: Vec<SlideNote>,
997 #[serde(skip_serializing_if = "Vec::is_empty")]
998 pub comments: Vec<SlideComment>,
999 #[serde(skip_serializing_if = "Option::is_none")]
1000 pub source_part: Option<String>,
1001 pub warnings: Vec<PresentationWarning>,
1002}
1003
1004#[derive(Debug, Clone, Serialize, Deserialize)]
1005pub struct SlideNote {
1006 pub text: String,
1007 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1008 pub paragraphs: Vec<TextParagraph>,
1009}
1010
1011#[derive(Debug, Clone, Serialize, Deserialize)]
1012#[serde(rename_all = "camelCase")]
1013pub struct SlideComment {
1014 pub id: String,
1015 pub text: String,
1016 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1017 pub paragraphs: Vec<TextParagraph>,
1018 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1019 pub replies: Vec<SlideComment>,
1020 #[serde(skip_serializing_if = "Option::is_none")]
1021 pub modern: Option<Box<ModernComment>>,
1022 #[serde(skip_serializing_if = "Option::is_none")]
1023 pub author: Option<String>,
1024 #[serde(skip_serializing_if = "Option::is_none")]
1025 pub author_id: Option<String>,
1026 #[serde(skip_serializing_if = "Option::is_none")]
1027 pub author_initials: Option<String>,
1028 #[serde(skip_serializing_if = "Option::is_none")]
1029 pub source_index: Option<u32>,
1030 #[serde(skip_serializing_if = "Option::is_none")]
1031 pub source_part: Option<String>,
1032 #[serde(skip_serializing_if = "Option::is_none")]
1033 pub created_at: Option<String>,
1034 #[serde(skip_serializing_if = "Option::is_none")]
1035 pub modified_at: Option<String>,
1036 #[serde(skip_serializing_if = "Option::is_none")]
1037 pub position: Option<SlideCommentPosition>,
1038 #[serde(skip_serializing_if = "Option::is_none")]
1039 pub x: Option<f64>,
1040 #[serde(skip_serializing_if = "Option::is_none")]
1041 pub y: Option<f64>,
1042}
1043
1044#[derive(Debug, Clone, Serialize, Deserialize)]
1045#[serde(rename_all = "camelCase")]
1046pub struct SlideCommentPosition {
1047 pub x: i64,
1048 pub y: i64,
1049 pub unit: SlideCommentPositionUnit,
1050}
1051
1052#[derive(Debug, Clone, Serialize, Deserialize)]
1053#[serde(rename_all = "camelCase")]
1054pub enum SlideCommentPositionUnit {
1055 EighthPoint,
1056}
1057
1058#[derive(Debug, Clone, Serialize, Deserialize)]
1059#[serde(rename_all = "camelCase")]
1060pub struct ModernComment {
1061 pub status: String,
1062 #[serde(skip_serializing_if = "Option::is_none")]
1063 pub author_user_id: Option<String>,
1064 #[serde(skip_serializing_if = "Option::is_none")]
1065 pub author_provider_id: Option<String>,
1066 #[serde(skip_serializing_if = "Option::is_none")]
1067 pub author_extensions_xml: Option<String>,
1068 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1069 pub anchors: Vec<CommentAnchor>,
1070 #[serde(skip_serializing_if = "Option::is_none")]
1071 pub position_emu: Option<CommentAnchorPosition>,
1072 #[serde(skip_serializing_if = "Option::is_none")]
1073 pub task: Option<CommentTask>,
1074 #[serde(skip_serializing_if = "Option::is_none")]
1075 pub extensions_xml: Option<String>,
1076}
1077
1078#[derive(Debug, Clone, Serialize, Deserialize)]
1079#[serde(rename_all = "camelCase")]
1080pub struct CommentTask {
1081 #[serde(skip_serializing_if = "Option::is_none")]
1082 pub start_date: Option<String>,
1083 #[serde(skip_serializing_if = "Option::is_none")]
1084 pub due_date: Option<String>,
1085 pub assigned_to: Vec<String>,
1086 pub title: String,
1087 pub completion: String,
1088 #[serde(skip_serializing_if = "Option::is_none")]
1089 pub completion_fraction: Option<f64>,
1090}
1091
1092#[derive(Debug, Clone, Serialize, Deserialize)]
1093#[serde(rename_all = "camelCase")]
1094pub struct CommentAnchorPosition {
1095 pub x: f64,
1096 pub y: f64,
1097 pub source_x: String,
1098 pub source_y: String,
1099}
1100
1101#[derive(Debug, Clone, Serialize, Deserialize)]
1102#[serde(rename_all = "camelCase")]
1103pub struct CommentAnchor {
1104 pub kind: CommentAnchorKind,
1105 pub monikers: Vec<CommentMoniker>,
1106}
1107
1108#[derive(Debug, Clone, Serialize, Deserialize)]
1109#[serde(rename_all = "camelCase")]
1110pub enum CommentAnchorKind {
1111 Slide,
1112 DrawingElement,
1113 TextRange,
1114 Unknown,
1115}
1116
1117#[derive(Debug, Clone, Serialize, Deserialize)]
1118pub struct CommentMoniker {
1119 pub namespace: String,
1120 pub name: String,
1121 pub attributes: BTreeMap<String, String>,
1122 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1123 pub children: Vec<CommentMoniker>,
1124 #[serde(default, skip_serializing_if = "String::is_empty")]
1125 pub text: String,
1126}
1127
1128#[derive(Debug, Clone, Serialize, Deserialize)]
1129#[serde(rename_all = "camelCase")]
1130pub struct PresentationDocument {
1131 pub format: PresentationFormat,
1132 pub size: PresentationSize,
1133 pub slides: Vec<PresentationSlide>,
1134 pub masters: Vec<SlideMaster>,
1135 pub layouts: Vec<SlideLayout>,
1136 pub themes: Vec<PresentationTheme>,
1137 pub assets: BTreeMap<String, PresentationAsset>,
1138 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1139 pub embedded_fonts: Vec<PresentationEmbeddedFont>,
1140 pub warnings: Vec<PresentationWarning>,
1141 #[serde(skip_serializing_if = "Option::is_none")]
1142 pub metadata: Option<PresentationMetadata>,
1143}