From c543ef350ef052910728b5f0fbcd862a60eac464 Mon Sep 17 00:00:00 2001 From: alexanderalber <90604107+alexanderalber@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:17:32 +0200 Subject: [PATCH] Slide show: transitions show the old slide instead of the new one twice (#33) (#46) On a slide change the show kept a clone of the old slide's texture handle as the transition's "old" picture, then rendered the new slide into that same texture with set(). Old and new were the same image, so every transition (except Morph, which renders into its own texture) blended the new slide with itself and looked like an instant cut. The old texture is now taken out of show.tex, so the new slide gets a texture of its own. generated with Claude Code --- crates/ui-egui/src/show.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/show.rs b/crates/ui-egui/src/show.rs index 1335f03..fd7b3ce 100644 --- a/crates/ui-egui/src/show.rs +++ b/crates/ui-egui/src/show.rs @@ -121,8 +121,10 @@ impl Show { .and_then(|s| s.transition.as_ref()) .map(|t| (t.kind.clone(), t.option.clone(), t.duration_ms as f64 / 1000.0)) .unwrap_or(("none".into(), String::new(), 0.0)); - let old = self.tex.as_ref().map(|(_, t)| t.clone()); - let from = self.tex.as_ref().map(|(k, _)| k.slide); + // Take the old slide's texture rather than cloning its handle: the new slide is + // otherwise rendered into the same texture, and the transition blends the new + // slide with itself (#33). + let (from, old) = self.tex.take().map(|(k, t)| (k.slide, t)).unzip(); self.trans = if kind != "none" && dur > 0.0 && !doc.show.without_animation { Some(Transition { old, from, morph: None, start: now, kind, option, dur }) } else { @@ -736,3 +738,29 @@ fn presenter_window(ctx: &egui::Context, show: &mut Show, doc: &Presentation, no } } } + +#[cfg(test)] +mod tests { + #![allow(clippy::unwrap_used, clippy::expect_used)] + + use super::*; + + #[test] + fn a_transition_keeps_the_old_slide_in_its_own_texture() { + // #33: the old slide's handle was cloned, so the new slide was rendered into the same + // texture and every transition blended the new slide with itself. + let mut s = deckcraft_engine::Session::with_new(); + s.execute("slide.new", &json!({})).unwrap(); + s.execute("transition.set", &json!({"kind": "fade", "index": 1})).unwrap(); + let doc = s.active().unwrap().doc.clone(); + let ctx = egui::Context::default(); + let red = ctx.load_texture("show", egui::ColorImage::filled([1, 1], Color32::RED), egui::TextureOptions::LINEAR); + let mut show = Show::new(&doc, 0, false, false); + show.tex = Some((Key { slide: 0, step: 0, size: (1, 1), doc: 0, hidden: vec![] }, red.clone())); + assert!(show.apply(ShowAction::Slide(1), &doc, 0.0)); + let tr = show.trans.as_ref().expect("the fade plays"); + assert_eq!(tr.old.as_ref().map(TextureHandle::id), Some(red.id())); + assert_eq!(tr.from, Some(0)); + assert!(show.tex.is_none(), "the new slide gets a texture of its own instead of overwriting the old one"); + } +}