D604: readable animation effect labels

This commit is contained in:
Harrison Booth
2026-10-30 18:57:51 -05:00
parent c4221b1a7c
commit d453bee54f
4 changed files with 96 additions and 5 deletions
+87 -2
View File
@@ -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,67 @@ 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")
&& let Some(label) = direction
{
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", "in") => format!("{} In", title_first(effect.trim_end_matches("Out"))),
("box" | "boxOut" | "circle" | "diamond", "out") => format!("{} Out", title_first(effect.trim_end_matches("Out"))),
("zoom" | "zoomOut", "in") => "Zoom In".into(),
("zoom" | "zoomOut", "out") => "Zoom Out".into(),
(_, "lu") => "From Top-Left".into(),
(_, "ru") => "From Top-Right".into(),
(_, "ld") => "From Bottom-Left".into(),
(_, "rd") => "From Bottom-Right".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 +285,27 @@ 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"), "From Top-Right");
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");
}
}