mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-31 07:38:16 +00:00
Merge pull request #1438
Animations: the Add Animation menu scrolls when it is taller than the window (fixes #1370)
This commit is contained in:
commit
cee1d015ec
3 files changed
+85
-16
No files matched your search
@@ -429,6 +429,9 @@ mod master_layout_tests;
|
||||
#[cfg(test)]
|
||||
mod icons_popup_tests;
|
||||
|
||||
#[cfg(test)]
|
||||
mod add_animation_menu_tests;
|
||||
|
||||
#[cfg(test)]
|
||||
mod align_tests;
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
//! Add Animation (#1370): the menu scrolls, so the last effect can be reached and added.
|
||||
|
||||
use deckcraft_engine::Session;
|
||||
use egui_kittest::Harness;
|
||||
use egui_kittest::kittest::Queryable;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{Services, SlideApp};
|
||||
|
||||
fn harness(size: egui::Vec2) -> Harness<'static, SlideApp> {
|
||||
let mut session = Session::with_new();
|
||||
let id = session.execute("shape.insert", &json!({"preset": "rect", "rect": [80.0, 80.0, 200.0, 120.0]})).unwrap()["id"].as_u64().unwrap();
|
||||
session.execute("edit.select", &json!({"ids": [id]})).unwrap();
|
||||
let mut app = SlideApp::new(session, Services::default());
|
||||
app.ui.tab = "Animations".into();
|
||||
let mut h = Harness::builder().with_size(size).with_step_dt(1.0 / 60.0).build_ui_state(
|
||||
|ui, app: &mut SlideApp| {
|
||||
app.logic(ui.ctx());
|
||||
app.ui(ui);
|
||||
},
|
||||
app,
|
||||
);
|
||||
h.run_steps(3);
|
||||
h
|
||||
}
|
||||
|
||||
fn open_add_animation(h: &mut Harness<'static, SlideApp>, window: egui::Vec2) {
|
||||
// The Animations ribbon is wider than a short window. The edge chevron is what a person uses
|
||||
// to reach Add Animation; scroll-into-view on the button does not move that bar.
|
||||
for _ in 0..12 {
|
||||
let rect = h.get_by_label("Add Animation").rect();
|
||||
if rect.min.x >= 8.0 && rect.max.x <= window.x - 8.0 {
|
||||
break;
|
||||
}
|
||||
let Some(cue) = h.query_by_label("Scroll ribbon right") else { break };
|
||||
cue.click();
|
||||
h.run_steps(2);
|
||||
}
|
||||
h.get_by_label("Add Animation").click();
|
||||
h.run_steps(3);
|
||||
}
|
||||
|
||||
fn added_effect(h: &Harness<'_, SlideApp>) -> Option<(String, deckcraft_model::anim::AnimClass)> {
|
||||
h.state().session.active().and_then(|d| d.current_slide()).and_then(|s| s.animations.first()).map(|a| (a.effect.clone(), a.class))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_last_effect_is_reachable_by_scrolling() {
|
||||
let size = egui::vec2(800.0, 700.0);
|
||||
let mut h = harness(size);
|
||||
open_add_animation(&mut h, size);
|
||||
let before = h.get_by_label("Neutron — Motion").rect();
|
||||
assert!(before.min.y > 700.0, "the last effect starts below the window: {before:?}");
|
||||
h.get_by_label("Neutron — Motion").scroll_to_me();
|
||||
h.run_steps(4);
|
||||
let row = h.get_by_label("Neutron — Motion").rect();
|
||||
assert!(row.min.y >= 0.0 && row.max.y <= 700.0, "a scrolled effect stays inside the window: {row:?}");
|
||||
h.get_by_label("Neutron — Motion").click();
|
||||
h.run_steps(3);
|
||||
assert_eq!(added_effect(&h), Some(("neutron".into(), deckcraft_model::anim::AnimClass::Path)));
|
||||
}
|
||||
@@ -103,24 +103,29 @@ pub(super) fn animations(app: &mut SlideApp, ui: &mut Ui) {
|
||||
});
|
||||
group(ui, |ui| {
|
||||
let r = big_button(ui, Icon::AddAnimation, "Add\nAnimation", has_sel);
|
||||
// Every effect in one column is taller than a 1440p screen, so cap the height and scroll (#1370).
|
||||
// The menu opens under the title bar and the ribbon; keep that chrome out of the cap.
|
||||
let max_h = (r.ctx.viewport_rect().height() - 160.0).max(120.0);
|
||||
egui::Popup::menu(&r).width(260.0).show(|ui| {
|
||||
for a in deckcraft_model::anim::ANIMATIONS.iter().filter(|a| a.2 != AnimClass::Media) {
|
||||
if ui
|
||||
.button(format!(
|
||||
"{} — {}",
|
||||
a.1,
|
||||
match a.2 {
|
||||
AnimClass::Entrance => "Entrance",
|
||||
AnimClass::Emphasis => "Emphasis",
|
||||
AnimClass::Exit => "Exit",
|
||||
_ => "Motion",
|
||||
}
|
||||
))
|
||||
.clicked()
|
||||
{
|
||||
run(app, "animation.add", json!({"effect": a.0, "class": a.2.xml()}));
|
||||
egui::ScrollArea::vertical().id_salt("add_animation").max_height(max_h).show(ui, |ui| {
|
||||
for a in deckcraft_model::anim::ANIMATIONS.iter().filter(|a| a.2 != AnimClass::Media) {
|
||||
if ui
|
||||
.button(format!(
|
||||
"{} — {}",
|
||||
a.1,
|
||||
match a.2 {
|
||||
AnimClass::Entrance => "Entrance",
|
||||
AnimClass::Emphasis => "Emphasis",
|
||||
AnimClass::Exit => "Exit",
|
||||
_ => "Motion",
|
||||
}
|
||||
))
|
||||
.clicked()
|
||||
{
|
||||
run(app, "animation.add", json!({"effect": a.0, "class": a.2.xml()}));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
big(app, ui, Icon::AnimationPane, "Animation\nPane", "view.pane", json!({"pane": "animation"}));
|
||||
let r = big_button(ui, Icon::Trigger, "Trigger", cur.is_some());
|
||||
|
||||
Reference in new issue
Block a user