mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 10:37:03 -06:00
PPTX: a lone guide keeps the name its preset uses, adj1 or adj (#214)
The writer named a preset's only guide `adj` whenever the preset has one adjust value, but bentConnector3, curvedConnector3, frame, mathPlus, mathMinus and mathMultiply call it `adj1`, and PowerPoint refuses to open a file that renames it. The names come from PowerPoint itself: every autoshape and connector created with an adjusted first value and saved; these six are the only single-guide presets named `adj1`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
0ec0cc5e81
commit
aaec22c681
@@ -100,7 +100,10 @@ pub fn geometry(w: &mut W, g: &Geom) {
|
||||
vals.push(defaults.get(vals.len()).copied().unwrap_or(0.0));
|
||||
}
|
||||
w.open0("a:avLst");
|
||||
let single = if defaults.is_empty() { vals.len() == 1 } else { defaults.len() == 1 };
|
||||
// A lone guide is `adj`, except in these presets, which name it `adj1` (as PowerPoint
|
||||
// writes them); PowerPoint won't open a file that renames it (#214).
|
||||
let adj1 = matches!(name, "bentConnector3" | "curvedConnector3" | "frame" | "mathPlus" | "mathMinus" | "mathMultiply");
|
||||
let single = !adj1 && if defaults.is_empty() { vals.len() == 1 } else { defaults.len() == 1 };
|
||||
for (i, v) in vals.iter().enumerate() {
|
||||
let n = if single && i == 0 { "adj".to_string() } else { format!("adj{}", i + 1) };
|
||||
let v = if v.is_finite() { v.round().clamp(-2.0e9, 2.0e9) as i64 } else { 0 };
|
||||
|
||||
@@ -730,3 +730,33 @@ fn date_fields_keep_their_type_and_saved_text() {
|
||||
assert_eq!(by_name(&q.slides[0], name).text, by_name(&p.slides[0], name).text, "{name}");
|
||||
}
|
||||
}
|
||||
|
||||
/// #214: a lone guide was always written `adj`, but these presets name it `adj1`, and PowerPoint
|
||||
/// won't open the file otherwise. (Names as PowerPoint writes them.)
|
||||
#[test]
|
||||
fn single_guide_names_follow_the_preset() {
|
||||
let mut p = defaults::new_presentation(None);
|
||||
let mut s = new_slide(&mut p, "Guides");
|
||||
let cases = [
|
||||
("bentConnector3", "adj1"),
|
||||
("curvedConnector3", "adj1"),
|
||||
("frame", "adj1"),
|
||||
("mathPlus", "adj1"),
|
||||
("mathMinus", "adj1"),
|
||||
("mathMultiply", "adj1"),
|
||||
("roundRect", "adj"),
|
||||
("chevron", "adj"),
|
||||
];
|
||||
for (prst, _) in cases {
|
||||
let mut sh = shape(&mut p, prst, 0.0, 0.0, 100.0, 50.0);
|
||||
sh.geom = Geom::Preset { name: prst.into(), adj: vec![20000.0] };
|
||||
s.shapes.push(sh);
|
||||
}
|
||||
p.slides.push(Arc::new(s));
|
||||
let bytes = deckcraft_pptx::export(&p).expect("export");
|
||||
let mut z = zip::ZipArchive::new(std::io::Cursor::new(&bytes)).expect("zip");
|
||||
let xml = std::io::read_to_string(z.by_name("ppt/slides/slide2.xml").expect("slide")).expect("read");
|
||||
for (prst, gd) in cases {
|
||||
assert!(xml.contains(&format!(r#"<a:prstGeom prst="{prst}"><a:avLst><a:gd name="{gd}" fmla="val 20000"/>"#)), "{prst} → {gd}: {xml}");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user