Merge PR #705 from NikitkaRa: PPTX: write Color Pulse emphasis as a colour change, not a scale

# Conflicts:
#	crates/pptx/tests/roundtrip.rs
This commit is contained in:
Brandon Thomas
2026-10-14 13:09:10 -04:00
2 changed files with 44 additions and 0 deletions
+19
View File
@@ -364,6 +364,25 @@ fn behaviors(w: &mut W, x: &mut Exp, ids: &mut Ids, e: &Eff) {
w.close("p:to");
w.close("p:set");
}
"colorPulse" => {
// As PowerPoint writes it: text and fill go to the colour and back (autoRev). The behaviour
// duration is the one import reads as the effect duration.
let c = a.color.clone().unwrap_or(deckcraft_model::ColorRef::rgb(deckcraft_color::Rgba::rgb(0xC0, 0x00, 0x00)));
for (attr, child) in [("style.color", true), ("fillcolor", false)] {
w.open("p:animClr", A::new().a("clrSpc", "rgb").a("dir", "cw"));
w.open("p:cBhvr", A::new().o("override", child.then_some("childStyle")));
w.empty("p:cTn", A::new().a("id", ids.next()).a("dur", dur.max(1)).a("autoRev", "1").a("fill", "remove"));
tgt(w, e.spid, e.paragraph);
w.open0("p:attrNameLst");
w.elt("p:attrName", attr);
w.close("p:attrNameLst");
w.close("p:cBhvr");
w.open0("p:to");
super::dml::color(w, &c);
w.close("p:to");
w.close("p:animClr");
}
}
"fillColor" | "objectColor" | "fontColor" | "lineColor" | "complementaryColor" | "darken" | "lighten" => {
let attr = match a.effect.as_str() {
"fontColor" => "style.color",
+25
View File
@@ -1350,3 +1350,28 @@ fn literal_line_ends_in_run_text_read_as_breaks_and_survive_save() {
assert_eq!(runs_of(&a, "one"), want);
assert_eq!(runs_of(&round(&a), "one"), want, "save and reopen keep the runs");
}
#[test]
fn color_pulse_keeps_its_effect_colour_and_duration() {
let mut p = defaults::new_presentation(None);
let s = shape(&mut p, "Pulsed", 10.0, 10.0, 200.0, 100.0);
let id = s.id;
let first = p.slides[0].id;
let sl = p.slide_mut(first).expect("slide");
sl.shapes.push(s);
let white = ColorRef::rgb(Rgba::rgb(255, 255, 255));
sl.animations.push(Animation {
shape: id,
class: AnimClass::Emphasis,
effect: "colorPulse".into(),
duration_ms: 1000,
color: Some(white.clone()),
..Default::default()
});
let q = round(&p);
let a = &q.slides[0].animations[0];
assert_eq!((a.class, a.effect.as_str()), (AnimClass::Emphasis, "colorPulse"));
assert_eq!(a.color, Some(white));
assert_eq!(a.amount, None, "no grow/shrink scale is invented");
assert_eq!(a.duration_ms, 1000);
}