mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-25 11:07:01 -06:00
Keep later On Click effects and paragraph builds in separate interactive steps. Add round-trip and headless show regressions. Contribution on behalf of @MMexicann.
96 lines
3.9 KiB
Rust
96 lines
3.9 KiB
Rust
//! Synthetic interactive sequences must keep one step per click across a save.
|
|
|
|
use std::io::{Cursor, Read};
|
|
use std::sync::Arc;
|
|
|
|
use deckcraft_geom::Xfrm;
|
|
use deckcraft_model::anim::{AnimStart, Animation, TextBuild};
|
|
use deckcraft_model::text::TextBody;
|
|
use deckcraft_model::{Presentation, Shape, ShapeId, defaults};
|
|
|
|
fn deck() -> Presentation {
|
|
let mut p = defaults::new_presentation(None);
|
|
let shapes: Vec<_> = ["Button", "Other button", "Content"]
|
|
.into_iter()
|
|
.map(|name| Shape {
|
|
id: ShapeId(p.alloc_id().expect("id")),
|
|
name: name.into(),
|
|
xfrm: Some(Xfrm::new(40.0, 40.0, 200.0, 100.0)),
|
|
text: Some(TextBody::from_text("First\nSecond\nThird")),
|
|
..Default::default()
|
|
})
|
|
.collect();
|
|
Arc::make_mut(&mut p.slides[0]).shapes = shapes;
|
|
p
|
|
}
|
|
|
|
fn round(p: &Presentation) -> Presentation {
|
|
deckcraft_pptx::import(&deckcraft_pptx::export(p).expect("export")).expect("import")
|
|
}
|
|
|
|
fn slide_xml(p: &Presentation) -> String {
|
|
let bytes = deckcraft_pptx::export(p).expect("export");
|
|
let mut z = zip::ZipArchive::new(Cursor::new(bytes)).expect("zip");
|
|
let mut xml = String::new();
|
|
z.by_name("ppt/slides/slide1.xml").expect("slide").read_to_string(&mut xml).expect("xml");
|
|
xml
|
|
}
|
|
|
|
#[test]
|
|
fn triggered_click_steps_survive_import_edit_save_reopen() {
|
|
use AnimStart::{AfterPrevious, OnClick, WithPrevious};
|
|
let mut p = deck();
|
|
let ids: Vec<_> = p.slides[0].shapes.iter().map(|s| s.id).collect();
|
|
let starts = [OnClick, WithPrevious, AfterPrevious, OnClick, WithPrevious, OnClick];
|
|
for (i, start) in starts.into_iter().enumerate() {
|
|
Arc::make_mut(&mut p.slides[0]).animations.push(Animation {
|
|
shape: ids[2],
|
|
trigger: Some(ids[0]),
|
|
start,
|
|
effect: "appear".into(),
|
|
delay_ms: i as u32 * 100,
|
|
..Default::default()
|
|
});
|
|
}
|
|
// An independent button and the main sequence must not borrow this button's steps.
|
|
for trigger in [Some(ids[1]), None] {
|
|
for start in [OnClick, AfterPrevious, OnClick] {
|
|
Arc::make_mut(&mut p.slides[0]).animations.push(Animation { shape: ids[2], trigger, start, ..Default::default() });
|
|
}
|
|
}
|
|
let mut q = round(&p);
|
|
for pass in 0..2 {
|
|
for trigger in [Some(ids[0]), Some(ids[1]), None] {
|
|
let state = |deck: &Presentation| {
|
|
deck.slides[0].animations.iter().filter(|a| a.trigger == trigger).map(|a| (a.start, a.delay_ms)).collect::<Vec<_>>()
|
|
};
|
|
assert_eq!(state(&q), state(&p), "trigger {trigger:?}, pass {pass}");
|
|
}
|
|
assert_eq!(q.slides[0].animations.len(), p.slides[0].animations.len());
|
|
Arc::make_mut(&mut q.slides[0]).shapes[2].name = "Edited content".into();
|
|
q = round(&q);
|
|
}
|
|
let xml = slide_xml(&p);
|
|
assert_eq!(xml.matches("nodeType=\"interactiveSeq\"").count(), 2);
|
|
assert_eq!(xml.matches("nodeType=\"clickEffect\"").count(), 7);
|
|
// The first step in each interactive sequence begins at zero; subsequent steps wait.
|
|
assert_eq!(xml.matches("delay=\"indefinite\"").count(), 5);
|
|
}
|
|
|
|
#[test]
|
|
fn triggered_paragraph_build_keeps_a_click_for_each_paragraph() {
|
|
let mut p = deck();
|
|
let ids: Vec<_> = p.slides[0].shapes.iter().map(|s| s.id).collect();
|
|
Arc::make_mut(&mut p.slides[0]).animations =
|
|
vec![Animation { shape: ids[2], trigger: Some(ids[0]), text_build: TextBuild::ByParagraph, start: AnimStart::OnClick, ..Default::default() }];
|
|
for q in [p.clone(), round(&p)] {
|
|
let xml = slide_xml(&q);
|
|
assert_eq!(xml.matches("nodeType=\"clickEffect\"").count(), 3);
|
|
assert_eq!(xml.matches("delay=\"indefinite\"").count(), 2);
|
|
let back = round(&q);
|
|
assert_eq!(back.slides[0].animations.len(), 1);
|
|
assert_eq!(back.slides[0].animations[0].text_build, TextBuild::ByParagraph);
|
|
assert_eq!(back.slides[0].animations[0].trigger, Some(ids[0]));
|
|
}
|
|
}
|