mirror of
https://github.com/storytold/deckcraft.git
synced 2026-11-10 04:14:16 +00:00
commit
597b9488f5
2 files changed
+111
-4
No files matched your search
@@ -1,4 +1,3 @@
|
||||
use super::transitions::option_label;
|
||||
use super::{
|
||||
Align2, AnimClass, CornerRadius, Icon, Rect, Sense, SlideApp, Tokens, Ui, big, big_button, big_button_ex, dropdown, enabled, group, icons, json,
|
||||
pos2, rows, run, theme, vec2, widgets,
|
||||
@@ -81,12 +80,13 @@ pub(super) fn animations(app: &mut SlideApp, ui: &mut Ui) {
|
||||
}
|
||||
});
|
||||
let effect_rows = cur.as_ref().map(|c| animation_effect_rows(&c.effect, c.class, Some(c.option.as_str()))).unwrap_or_default();
|
||||
let effect = cur.as_ref().map(|c| c.effect.as_str()).unwrap_or_default();
|
||||
let build = cur.as_ref().map(|c| text_build_id(c.text_build));
|
||||
let build_rows = marked_options(&["asOne", "byParagraph"], build);
|
||||
let r = big_button(ui, Icon::EffectOptions, "Effect\nOptions", !effect_rows.is_empty());
|
||||
egui::Popup::menu(&r).show(|ui| {
|
||||
for &(o, on) in &effect_rows {
|
||||
if ui.selectable_label(on, option_label(o)).clicked() {
|
||||
if ui.selectable_label(on, animation_option_label(effect, o)).clicked() {
|
||||
run(app, "animation.options", json!({"option": o}));
|
||||
ui.close();
|
||||
}
|
||||
@@ -216,6 +216,70 @@ pub(super) fn animation_effect_rows(effect: &str, class: AnimClass, current: Opt
|
||||
marked_options(opts, current)
|
||||
}
|
||||
|
||||
fn animation_option_label(effect: &str, option: &str) -> String {
|
||||
let direction = match option {
|
||||
"b" => Some("From Bottom"),
|
||||
"lb" => Some("From Bottom-Left"),
|
||||
"l" => Some("From Left"),
|
||||
"lt" => Some("From Top-Left"),
|
||||
"t" => Some("From Top"),
|
||||
"rt" => Some("From Top-Right"),
|
||||
"r" => Some("From Right"),
|
||||
"rb" => Some("From Bottom-Right"),
|
||||
_ => None,
|
||||
};
|
||||
if matches!(effect, "fly" | "flyOut" | "wipe" | "wipeOut" | "peek" | "peekOut" | "crawl" | "crawlOut")
|
||||
&& let Some(label) = direction
|
||||
{
|
||||
if matches!(effect, "flyOut" | "peekOut" | "crawlOut") {
|
||||
return label.replacen("From", "To", 1);
|
||||
}
|
||||
return label.into();
|
||||
}
|
||||
|
||||
match (effect, option) {
|
||||
("float" | "floatOut", "u") => "Up".into(),
|
||||
("float" | "floatOut", "d") => "Down".into(),
|
||||
("split" | "splitOut", "horzIn") => "Horizontal In".into(),
|
||||
("split" | "splitOut", "horzOut") => "Horizontal Out".into(),
|
||||
("split" | "splitOut", "vertIn") => "Vertical In".into(),
|
||||
("split" | "splitOut", "vertOut") => "Vertical Out".into(),
|
||||
("shape" | "shapeOut", o) if o.ends_with("In") => format!("{} In", title_first(shape_option_name(o))),
|
||||
("shape" | "shapeOut", o) if o.ends_with("Out") => format!("{} Out", title_first(shape_option_name(o))),
|
||||
("wheel" | "wheelOut", "1") => "1 Spoke".into(),
|
||||
("wheel" | "wheelOut", n) => format!("{n} Spokes"),
|
||||
("box" | "boxOut" | "circle" | "diamond" | "diamondOut", "in") => format!("{} In", title_first(effect.trim_end_matches("Out"))),
|
||||
("box" | "boxOut" | "circle" | "diamond" | "diamondOut", "out") => format!("{} Out", title_first(effect.trim_end_matches("Out"))),
|
||||
("zoom" | "zoomOut", "in") => "Zoom In".into(),
|
||||
("zoom" | "zoomOut", "out") => "Zoom Out".into(),
|
||||
("strips" | "stripsOut", "lu") => "Left Up".into(),
|
||||
("strips" | "stripsOut", "ru") => "Right Up".into(),
|
||||
("strips" | "stripsOut", "ld") => "Left Down".into(),
|
||||
("strips" | "stripsOut", "rd") => "Right Down".into(),
|
||||
(_, "horz") => "Horizontal".into(),
|
||||
(_, "vert") => "Vertical".into(),
|
||||
(_, "across") => "Across".into(),
|
||||
(_, "down") => "Down".into(),
|
||||
(_, "up") => "Up".into(),
|
||||
(_, "right") => "Right".into(),
|
||||
(_, "left") => "Left".into(),
|
||||
(_, "clockwise") => "Clockwise".into(),
|
||||
(_, "counterClockwise") => "Counterclockwise".into(),
|
||||
(_, "in") => "In".into(),
|
||||
(_, "out") => "Out".into(),
|
||||
(_, other) => super::transitions::option_label(other),
|
||||
}
|
||||
}
|
||||
|
||||
fn shape_option_name(option: &str) -> &str {
|
||||
option.strip_suffix("In").or_else(|| option.strip_suffix("Out")).unwrap_or(option)
|
||||
}
|
||||
|
||||
fn title_first(value: &str) -> String {
|
||||
let mut chars = value.chars();
|
||||
chars.next().map(|c| c.to_uppercase().collect::<String>() + chars.as_str()).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub(super) fn text_build_id(build: deckcraft_model::anim::TextBuild) -> &'static str {
|
||||
match build {
|
||||
deckcraft_model::anim::TextBuild::ByParagraph => "byParagraph",
|
||||
@@ -224,3 +288,45 @@ pub(super) fn text_build_id(build: deckcraft_model::anim::TextBuild) -> &'static
|
||||
deckcraft_model::anim::TextBuild::AsOne => "asOne",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod animation_option_label_tests {
|
||||
use super::animation_option_label;
|
||||
use deckcraft_model::anim::ANIMATIONS;
|
||||
|
||||
#[test]
|
||||
fn labels_every_animation_gallery_option_without_changing_its_code() {
|
||||
for &(effect, _, _, _, _, options) in ANIMATIONS {
|
||||
for &option in options {
|
||||
let label = animation_option_label(effect, option);
|
||||
assert!(!label.is_empty(), "{effect}/{option}");
|
||||
assert_ne!(label, option, "raw option shown for {effect}/{option}");
|
||||
}
|
||||
}
|
||||
assert_eq!(animation_option_label("fly", "lb"), "From Bottom-Left");
|
||||
assert_eq!(animation_option_label("flyOut", "rt"), "To Top-Right");
|
||||
assert_eq!(animation_option_label("flyOut", "b"), "To Bottom");
|
||||
assert_eq!(animation_option_label("peekOut", "l"), "To Left");
|
||||
assert_eq!(animation_option_label("wipe", "b"), "From Bottom");
|
||||
assert_eq!(animation_option_label("wheel", "1"), "1 Spoke");
|
||||
assert_eq!(animation_option_label("split", "vertOut"), "Vertical Out");
|
||||
assert_eq!(animation_option_label("shape", "circleIn"), "Circle In");
|
||||
assert_eq!(animation_option_label("diamond", "out"), "Diamond Out");
|
||||
assert_eq!(animation_option_label("diamondOut", "in"), "Diamond In");
|
||||
assert_eq!(animation_option_label("diamondOut", "out"), "Diamond Out");
|
||||
assert_eq!(animation_option_label("strips", "lu"), "Left Up");
|
||||
assert_eq!(animation_option_label("strips", "ru"), "Right Up");
|
||||
assert_eq!(animation_option_label("strips", "ld"), "Left Down");
|
||||
assert_eq!(animation_option_label("strips", "rd"), "Right Down");
|
||||
assert_eq!(animation_option_label("crawl", "b"), "From Bottom");
|
||||
assert_eq!(animation_option_label("crawl", "l"), "From Left");
|
||||
assert_eq!(animation_option_label("crawl", "t"), "From Top");
|
||||
assert_eq!(animation_option_label("crawl", "r"), "From Right");
|
||||
assert_eq!(animation_option_label("crawlOut", "l"), "To Left");
|
||||
assert_eq!(animation_option_label("crawlOut", "r"), "To Right");
|
||||
assert_eq!(animation_option_label("plus", "in"), "In");
|
||||
assert_eq!(animation_option_label("plus", "out"), "Out");
|
||||
assert_eq!(animation_option_label("changeFontSize", "increase"), "Increase");
|
||||
assert_eq!(animation_option_label("changeFontSize", "decrease"), "Decrease");
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# Transitions and animations: parity with PowerPoint
|
||||
|
||||
> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-29 · **Change:** minor (going back in the show reverses the left slide's transition, #1531; previous: minor, Animation Pane ▸ Play From plays from the selected effect; previous: community PR wave 2026-10-14: interactive-deck triggers, canvas preview, the Animation Pane timeline, repeat and bounce end round-trip; duplicated rows and headers folded; previous: major, transitions measured frame by frame against PowerPoint for Windows' video export) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365)
|
||||
> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-30 · **Change:** trivial (animation Effect Options translate stored codes into readable labels; previous: minor, going back in the show reverses the left slide's transition, #1531; previous: minor, Animation Pane ▸ Play From plays from the selected effect; previous: community PR wave 2026-10-14: interactive-deck triggers, canvas preview, the Animation Pane timeline, repeat and bounce end round-trip; duplicated rows and headers folded; previous: major, transitions measured frame by frame against PowerPoint for Windows' video export) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365)
|
||||
|
||||
Transitions and animations are what make a deck a presentation, and the part of PowerPoint people
|
||||
notice first when it's missing. Scores roll up into [target-app-parity.md](target-app-parity.md)
|
||||
@@ -65,7 +65,7 @@ In, Wipe, Zoom, Float In, Grow/Shrink, Pulse, Spin, motion lines): weighted, ~85
|
||||
| Animation feature | PowerPoint | DeckCraft |
|
||||
|---|---|---|
|
||||
| Start On Click / With Previous / After Previous, duration, delay | yes | yes |
|
||||
| Effect Options (direction, sequence by paragraph) | yes | yes |
|
||||
| Effect Options (direction, sequence by paragraph) | yes | yes; every gallery option has a readable label while retaining its stored code |
|
||||
| Effect dialog: sound, after-animation dim/hide, animate text by word/letter, smooth start/end, bounce end, repeat, rewind | yes | partly; repeat, bounce end and rewind round-trip |
|
||||
| By-paragraph text builds, sub-bullets follow parents | yes | yes; builds edited in PowerPoint (own start per paragraph, other effects in between, by 2nd-level paragraphs) import as one effect per paragraph and keep their clicks (#844) |
|
||||
| Triggers (on click of a shape) | yes | yes; played in the show: a step per click, the sequence starts over after its last step, a click completes a playing step. Separate click steps, mixed starts and paragraph builds survive PPTX save (`trigger_steps.rs`) |
|
||||
@@ -94,6 +94,7 @@ In, Wipe, Zoom, Float In, Grow/Shrink, Pulse, Spin, motion lines): weighted, ~85
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-30 | trivial | Animation Effect Options show readable, effect-aware labels for all gallery option codes; stored values and command parameters stay unchanged |
|
||||
| 2026-10-29 | minor | Going back in the show plays the transition of the slide being left, reversed, instead of the previous slide's entrance transition (#1531); new row in the transition features. Scores unchanged |
|
||||
| 2026-10-22 | minor | Animation Pane ▸ Play From: with an effect selected, the preview starts at that effect on the play-all clock; the row says yes and the estimate drops to ~14–26 h |
|
||||
| 2026-10-15 | trivial | PPTX interactive sequences preserve later On Click effects and one click per paragraph; no change to playback or feature scores |
|
||||
|
||||
Reference in new issue
Block a user