mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-25 11:07:01 -06:00
Merge PR #136 from alexanderalber: Morph: text boxes without a partner fade in place instead of moving (#119)
This commit is contained in:
@@ -12,7 +12,9 @@ fn text_of(s: &Shape) -> String {
|
||||
|
||||
/// Pairs of (shape on `a`, shape on `b`) that Morph animates from one to the other: first by
|
||||
/// `!!name` (forced match), then by exact name, then by the same kind and text, then by the same
|
||||
/// kind and preset geometry. Each shape is used once; top-level shapes only (groups move whole).
|
||||
/// kind and preset geometry if neither carries text. A text box with neither a name nor its text on
|
||||
/// the other slide stays unpaired and fades in place, as in PowerPoint (#119). Each shape is used
|
||||
/// once; top-level shapes only (groups move whole).
|
||||
pub fn morph_pairs(a: &Slide, b: &Slide) -> Vec<(ShapeId, ShapeId)> {
|
||||
let mut pairs: Vec<(ShapeId, ShapeId)> = Vec::new();
|
||||
let mut used_a = vec![false; a.shapes.len()];
|
||||
@@ -31,7 +33,8 @@ pub fn morph_pairs(a: &Slide, b: &Slide) -> Vec<(ShapeId, ShapeId)> {
|
||||
x.kind_name() == y.kind_name()
|
||||
&& x.geom.preset_name().is_some()
|
||||
&& x.geom.preset_name() == y.geom.preset_name()
|
||||
&& text_of(x).trim().is_empty() == text_of(y).trim().is_empty()
|
||||
&& text_of(x).trim().is_empty()
|
||||
&& text_of(y).trim().is_empty()
|
||||
},
|
||||
];
|
||||
for pass in passes {
|
||||
|
||||
@@ -529,6 +529,26 @@ fn morph_pairs_by_name_text_and_geometry() {
|
||||
assert!(morph_pairs(&Slide::default(), &b).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn morph_pairs_leaves_unrelated_text_boxes_alone() {
|
||||
// A text box that leaves and an unrelated one that arrives fade in place (#119).
|
||||
let p = deckcraft_model::defaults::new_presentation(None);
|
||||
let mut a = Slide::default();
|
||||
let mut b = Slide::default();
|
||||
let tb = |id, name, x, text| Shape { xfrm: Some(Xfrm::new(x, 100.0, 200.0, 100.0)), text: Some(TextBody::from_text(text)), ..shape(id, name) };
|
||||
a.shapes = vec![tb(1, "TextBox 1", 0.0, "Gone")];
|
||||
b.shapes = vec![tb(2, "TextBox 2", 400.0, "New")];
|
||||
assert!(morph_pairs(&a, &b).is_empty());
|
||||
let f = morph_frame(&p, &a, &b, 0.5, &|_| false);
|
||||
let xs: Vec<(&str, f64)> = f.shapes.iter().map(|(s, _)| (s.name.as_str(), s.xfrm.map_or(f64::NAN, |x| x.x))).collect();
|
||||
assert_eq!(xs, [("TextBox 1", 0.0), ("TextBox 2", 400.0)]);
|
||||
// Empty shapes of one kind and geometry still pair, and a named text box keeps its partner.
|
||||
a.shapes.push(shape(3, "Rect A"));
|
||||
b.shapes.push(shape(4, "Rect B"));
|
||||
b.shapes[0].name = "TextBox 1".into();
|
||||
assert_eq!(morph_pairs(&a, &b), [(ShapeId(1), ShapeId(2)), (ShapeId(3), ShapeId(4))]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn morph_xfrm_interpolates() {
|
||||
let a = Xfrm { rot: 350.0, ..Xfrm::new(0.0, 0.0, 100.0, 100.0) };
|
||||
|
||||
@@ -42,7 +42,7 @@ perspective-correct subdivided meshes.
|
||||
| Duration, advance on click / after time, Apply To All | yes | yes |
|
||||
| Transition sounds | yes | yes: Transitions › Sound offers six built-in sounds (synthesised, no sound files shipped), Other Sound…, [Stop Previous Sound] and Loop Until Next Sound; they play in the show and round-trip |
|
||||
| Preview in the editor | yes | yes |
|
||||
| Morph: objects move, resize, recolour | yes | yes |
|
||||
| Morph: objects move, resize, recolour; unmatched text boxes fade in place | yes | yes (#119) |
|
||||
| Morph: Words and Characters | yes | yes (#5) |
|
||||
| Morph: geometry (circle to star) | yes | yes (#27) |
|
||||
| Morph: `!!` name forcing, pictures, 3-D models, ink | yes | names partly; no 3-D or ink |
|
||||
@@ -99,4 +99,5 @@ In, Wipe, Zoom, Float In, Grow/Shrink, Pulse, Spin, motion lines): weighted, ~85
|
||||
| 2026-10-14 | trivial | Repeat and bounce end round-trip through PPTX; rewind is still lost (#77) |
|
||||
| 2026-10-13 | major | Transitions measured frame by frame against PowerPoint's video export and retuned (mean diff 35.7 → 15.0); PowerPoint's XML defaults and option meanings; new options |
|
||||
| 2026-10-13 | minor | Triggers now play in the slide show (they were read and written but never started), effects of different triggers apply in the order they were clicked |
|
||||
| 2026-10-11 | minor | Morph leaves unrelated text boxes unpaired: they fade in place (#119) |
|
||||
| 2026-10-10 | major | Created: 48/48 transitions, 64 of ~190 animation effects, pane and option depth, estimates |
|
||||
|
||||
Reference in New Issue
Block a user