Merge PR #685 from NikitkaRa: PPTX: keep the notes master's own placeholders and colour map on save

# Conflicts:
#	crates/pptx/src/write/mod.rs
#	crates/pptx/tests/roundtrip.rs
This commit is contained in:
Brandon Thomas
2026-10-14 13:31:17 -04:00
2 changed files with 43 additions and 5 deletions
+9 -5
View File
@@ -385,23 +385,27 @@ struct NotesMasterWrite {
}
fn notes_master_write(p: &Presentation) -> Option<NotesMasterWrite> {
let kept = p.notes_master.as_ref().filter(|m| !m.shapes.is_empty());
let nm = p.notes_master.as_deref();
let kept = nm.filter(|m| !m.shapes.is_empty());
let has_notes = p.slides.iter().any(|s| !s.notes.is_empty());
if !has_notes && kept.is_none() {
if !has_notes && nm.is_none() {
return None;
}
let default_bg = || Background::Ref { idx: 1001, color: deckcraft_model::ColorRef::scheme(deckcraft_color::SchemeSlot::Bg1) };
Some(match kept {
Some(m) => NotesMasterWrite {
shapes: m.shapes.clone(),
background: m.background.clone(),
background: Some(m.background.clone().unwrap_or_else(default_bg)),
color_map: m.color_map.clone(),
style: if m.body_style.is_empty() { notes_style() } else { m.body_style.clone() },
theme: Some(m.theme.clone()),
},
// A master without placeholders of its own gets PowerPoint's defaults, keeping its
// background and colour map.
None => NotesMasterWrite {
shapes: notes_master_shapes(p.notes_size),
background: Some(Background::Ref { idx: 1001, color: deckcraft_model::ColorRef::scheme(deckcraft_color::SchemeSlot::Bg1) }),
color_map: vec![],
background: Some(nm.and_then(|m| m.background.clone()).unwrap_or_else(default_bg)),
color_map: nm.map(|m| m.color_map.clone()).unwrap_or_default(),
style: notes_style(),
theme: None,
},
+34
View File
@@ -1376,3 +1376,37 @@ fn color_pulse_keeps_its_effect_colour_and_duration() {
assert_eq!(a.amount, None, "no grow/shrink scale is invented");
assert_eq!(a.duration_ms, 1000);
}
#[test]
fn notes_master_placeholders_and_colour_map_survive_save() {
let mut p = defaults::new_presentation(None);
let mut box1 = shape(&mut p, "Confidential", 100000.0, 200000.0, 3000000.0, 400000.0);
box1.text = Some(TextBody::from_text("Company confidential"));
let map: Vec<(String, String)> = [("bg1", "dk1"), ("tx1", "lt1"), ("bg2", "dk2"), ("tx2", "lt2")]
.iter()
.chain(
[
("accent1", "accent1"),
("accent2", "accent2"),
("accent3", "accent3"),
("accent4", "accent4"),
("accent5", "accent5"),
("accent6", "accent6"),
("hlink", "hlink"),
("folHlink", "folHlink"),
]
.iter(),
)
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect();
let m = deckcraft_model::Master { name: "Notes Master".into(), shapes: vec![box1], color_map: map.clone(), ..Default::default() };
p.notes_master = Some(Arc::new(m));
// No slide has notes: the notes master must still be written.
let q = round(&p);
let nm = q.notes_master.as_deref().expect("notes master kept");
assert_eq!(nm.shapes.len(), 1, "own shapes, not the defaults");
let sh = &nm.shapes[0];
assert_eq!(sh.name, "Confidential");
assert_eq!(sh.text.as_ref().map(|t| t.text()), Some("Company confidential".to_string()));
assert_eq!(nm.color_map, map);
}