Morph: the same text moves and resizes instead of cross-fading

A title typed as "TEST" on a title slide and on a content slide pairs
the two titles, but they differ in placeholder, size and alignment, so
Morph with the default Objects option cross-faded them: the old title
rose and faded out while the new one faded in.

Paired shapes whose text is the same now use the word morph (shared
words travel and resize from their old place to their new one) whatever
the Morph option, as PowerPoint does. Different texts still cross-fade
with Objects.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Nikita Rakitin
2026-10-13 23:22:19 +03:00
co-authored by Cursor
parent 457406a7a5
commit c22747b104
2 changed files with 32 additions and 1 deletions
+5 -1
View File
@@ -237,7 +237,11 @@ pub fn morph_frame(pres: &Presentation, a: &Slide, b: &Slide, t: f64, hidden_b:
} else {
let new = push(Shape { xfrm: x, ..sb.clone() }, false, s);
let old = push(Shape { xfrm: x, ..sa.clone() }, true, 1.0 - s);
if by_text
// The same text in shapes that differ otherwise (a title slide's centred title and a
// content slide's title: other placeholder, size, alignment) moves and resizes word
// by word even with the Objects option, as PowerPoint does, instead of cross-fading.
let same_text = text_of(sa).trim() == text_of(sb).trim();
if (by_text || same_text)
&& has_text(sa)
&& has_text(sb)
&& let (Some(from), Some(to)) = (box_of(ca.as_ref(), sa), box_of(cb.as_ref(), sb))
+27
View File
@@ -789,3 +789,30 @@ fn show_follows_links() {
assert_eq!(s.follow(&p, &Action::LastViewed, None), LinkJump::None);
assert_eq!(s.slide, 3);
}
/// #316: the same text in two shapes that differ otherwise (a title slide's big centred title,
/// a content slide's title) morphs word by word with the default Objects option, instead of
/// the old box cross-fading into the new one.
#[test]
fn same_text_morphs_even_by_objects() {
let p = deckcraft_model::defaults::new_presentation(None);
let titled = |id, x, size: f64, text: &str| {
let mut body = TextBody::from_text(text);
for para in &mut body.paragraphs {
for r in &mut para.runs {
r.props.size = Some(size);
}
}
Shape { xfrm: Some(Xfrm::new(x, 100.0, 600.0, 120.0)), text: Some(body), ..shape(id, "Title 1") }
};
let mut a = Slide::default();
let mut b = Slide::default();
a.shapes = vec![titled(1, 100.0, 60.0, "TEST")];
b.shapes = vec![titled(2, 40.0, 44.0, "TEST")];
let f = morph_frame(&p, &a, &b, 0.5, &|_| false);
assert_eq!(f.text.len(), 1, "the shared text morphs");
assert!(!f.text[0].chars);
// Different texts still cross-fade with the Objects option.
b.shapes = vec![titled(2, 40.0, 44.0, "Other")];
assert!(morph_frame(&p, &a, &b, 0.5, &|_| false).text.is_empty());
}