mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 02:27:08 -06:00
Play From: skip triggered effects, reject an invalid from
- The pane picks the first effect of the selected shape that is on the click sequence, so a triggered effect before it no longer turns the button back into Play All; a clicked triggered row falls back the same way. - animation.preview rejects a from that is not an effect index instead of playing all. - target-app-parity: the Animation Pane timeline is no longer a shortfall.
This commit is contained in:
@@ -162,6 +162,33 @@ fn moving_an_effect_forgets_the_clicked_row() {
|
||||
assert!(at < 0.1, "back to the shape's first effect, not the spin now in that row: {at}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn play_from_skips_a_triggered_effect() {
|
||||
let mut h = harness();
|
||||
// The zoomed shape's first effect becomes triggered by the faded shape; its second effect,
|
||||
// after the 1 s fade, is still on the click sequence.
|
||||
let first = h.state().session.active().unwrap().current_slide().unwrap().animations[0].shape.0;
|
||||
h.state_mut().session.execute("animation.timing", &json!({"index": 1, "trigger": first})).unwrap();
|
||||
h.state_mut().session.execute("animation.add", &json!({"effect": "pulse", "start": "afterPrevious", "duration": 1000})).unwrap();
|
||||
h.run_steps(2);
|
||||
let at = play(&mut h, "▶ Play From");
|
||||
assert!((1.0..1.1).contains(&at), "from the shape's first effect on the click sequence: {at}");
|
||||
// A clicked triggered row falls back the same way.
|
||||
click_row(&mut h, 2, egui::PointerButton::Primary);
|
||||
let at = play(&mut h, "▶ Play From");
|
||||
assert!((1.0..1.1).contains(&at), "{at}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preview_rejects_a_from_that_is_not_an_effect_index() {
|
||||
let mut h = harness();
|
||||
for from in [json!("1"), json!(-1), json!(1.5)] {
|
||||
assert!(h.state_mut().run("animation.preview", json!({"from": from})).is_err(), "{from}");
|
||||
assert!(h.state().anim_preview_report().is_none(), "{from}");
|
||||
}
|
||||
assert_eq!(h.state_mut().run("animation.preview", json!({"from": 1})).unwrap()["from"], 1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "writes a screenshot for review"]
|
||||
fn screenshot() {
|
||||
|
||||
@@ -971,7 +971,10 @@ impl SlideApp {
|
||||
self.anim_preview = None;
|
||||
return Ok(json!({"playing": false}));
|
||||
}
|
||||
let from = p.get("from").and_then(Value::as_u64).map(|v| usize::try_from(v).unwrap_or(usize::MAX));
|
||||
let from = match p.get("from") {
|
||||
None | Some(Value::Null) => None,
|
||||
Some(v) => Some(v.as_u64().map(|v| usize::try_from(v).unwrap_or(usize::MAX)).ok_or("`from` must be an effect index")?),
|
||||
};
|
||||
return self.start_anim_preview(from);
|
||||
}
|
||||
"app.home" => {
|
||||
|
||||
@@ -1022,10 +1022,9 @@ fn animation(app: &mut SlideApp, ui: &mut Ui) {
|
||||
// index would point at another effect.
|
||||
let pick_id = egui::Id::new(("anim_pane_pick", st.uid, st.selection.slide));
|
||||
let pick = ui.data(|m| m.get_temp::<usize>(pick_id));
|
||||
let from = pick
|
||||
.filter(|&i| anims.get(i).is_some_and(|a| selected.contains(&a.shape.0)))
|
||||
.or_else(|| anims.iter().position(|a| selected.contains(&a.shape.0)))
|
||||
.filter(|&i| tl.start_of(i).is_some());
|
||||
// A triggered effect is not on the click sequence, so it can't be played from.
|
||||
let eligible = |i: usize| anims.get(i).is_some_and(|a| selected.contains(&a.shape.0)) && tl.start_of(i).is_some();
|
||||
let from = pick.filter(|&i| eligible(i)).or_else(|| (0..anims.len()).find(|&i| eligible(i)));
|
||||
ui.horizontal(|ui| {
|
||||
let playing = app.anim_preview_active();
|
||||
let label = match (playing, from) {
|
||||
|
||||
@@ -194,7 +194,7 @@ Features row of the dimension table keeps ~62% until the next full re-measure).
|
||||
| Pictures | 7 | 60% | ~45% | 12–20 | SVG, EMF+ records, clipboard paste on Windows/Linux (#53), remove background, artistic-effect and correction depth | [file-format-parity.md](file-format-parity.md) |
|
||||
| Media | 4 | 67% | ~60% | 8–14 | WMA/WMV decode, record audio/screen, 3-D models and stock content, playback options lost on PPTX round trip (#74) | [file-format-parity.md](file-format-parity.md) |
|
||||
| Transitions | 4 | 100% | ~80% | 4–8 | 3-D transitions approximated in 2-D | [animation-parity.md](animation-parity.md) |
|
||||
| Animations | 6 | 85% | ~65% | 10–16 | 64 of PowerPoint's ~190 effects, Animation Pane timeline, rewind lost on save (#77) | [animation-parity.md](animation-parity.md) |
|
||||
| Animations | 6 | 85% | ~65% | 10–16 | 64 of PowerPoint's ~190 effects, rewind lost on save (#77) | [animation-parity.md](animation-parity.md) |
|
||||
| Slide show and presenter view | 8 | 68% | ~60% | 10–16 | Second-display placement, laser from presenter view, recording, subtitles, ink depth | [slideshow-parity.md](slideshow-parity.md) |
|
||||
| Review | 3 | 70% | ~45% | 8–14 | Compare depth, version history, real spelling dictionaries | [file-format-parity.md](file-format-parity.md) |
|
||||
| Draw (ink) | 2 | 50% | ~30% | 5–9 | Pen tilt, ink to math, lasso, ink to shape/text depth | [hardware-parity.md](hardware-parity.md) |
|
||||
|
||||
Reference in New Issue
Block a user