diff --git a/crates/ui-egui/src/first_run.rs b/crates/ui-egui/src/first_run.rs index 37b206f7..182dcfa1 100644 --- a/crates/ui-egui/src/first_run.rs +++ b/crates/ui-egui/src/first_run.rs @@ -13,15 +13,19 @@ pub fn show(app: &mut CraftApp, ui: &mut Ui) { let t = Tokens::get(ui.ctx()); let full = ui.max_rect(); let width = 640.0_f32.min(full.width() - 48.0); - ui.add_space(((full.height() - 560.0) / 2.0).clamp(24.0, 120.0)); - ui.vertical_centered(|ui| { - ui.set_max_width(width); - match app.state.first_run { - FirstRunStep::Welcome => welcome(app, ui), - FirstRunStep::Brain => brain(app, ui, width), - FirstRunStep::Purpose => purpose(app, ui, width), - FirstRunStep::Done => done(app, ui), - } + // A step taller than the window scrolls above the footer, so Continue stays reachable (#231). + egui::ScrollArea::vertical().max_height(full.height() - 52.0).show(ui, |ui| { + ui.add_space(((full.height() - 560.0) / 2.0).clamp(24.0, 120.0)); + ui.vertical_centered(|ui| { + ui.set_max_width(width); + match app.state.first_run { + FirstRunStep::Welcome => welcome(app, ui), + FirstRunStep::Brain => brain(app, ui, width), + FirstRunStep::Purpose => purpose(app, ui, width), + FirstRunStep::Done => done(app, ui), + } + }); + ui.add_space(12.0); }); // Where you are, the ArtCraft way: "02 / 04 AI", plus a progress hairline. let step = app.state.first_run.index(); diff --git a/crates/ui-egui/tests/smoke.rs b/crates/ui-egui/tests/smoke.rs index e331665e..6117c0d4 100644 --- a/crates/ui-egui/tests/smoke.rs +++ b/crates/ui-egui/tests/smoke.rs @@ -59,6 +59,23 @@ fn first_run_walks_through_four_screens() { h.get_by_label("Just look inside"); } +/// #231: at the smallest window the app allows, Purpose's Continue was below the window with +/// nothing to scroll; it scrolls into view above the footer and works. +#[test] +fn first_run_continue_is_reachable_at_the_smallest_window() { + let (w, hgt) = (760.0, 520.0); + let mut h = harness_sized(egui::vec2(w, hgt), || demo::app(demo::engine(Mode::Beginner, false))); + h.state_mut().state.first_run = FirstRunStep::Purpose; + h.run_steps(3); + h.get_by_label("Continue").scroll_to_me(); + h.run_steps(3); + let r = h.get_by_label("Continue").rect(); + assert!(r.top() >= 0.0 && r.bottom() <= hgt - 48.0, "Continue at {r:?} isn't in view above the footer"); + h.get_by_label("Continue").click(); + h.run_steps(3); + assert_eq!(h.state().state.first_run, FirstRunStep::Done); +} + #[test] fn simple_title_bar_keeps_only_the_essentials() { let mut h = harness(|| demo::app(demo::engine(Mode::Beginner, true)));