diff --git a/crates/ui-egui/src/formula_bar.rs b/crates/ui-egui/src/formula_bar.rs index afdf1987b..091869ab8 100644 --- a/crates/ui-egui/src/formula_bar.rs +++ b/crates/ui-egui/src/formula_bar.rs @@ -17,6 +17,9 @@ pub const MAX_LINES: usize = 5; pub const MAX_DRAG_LINES: usize = 100; /// How far the bar's bottom edge reaches up into the bar as a resize handle (its bottom margin). const HANDLE: f32 = 4.0; +/// What an expanded bar leaves below it: the status bar (26) and sheet tabs (32), and the +/// worksheet's column headings and two rows, so the grid never disappears in a short window. +const KEEP_BELOW: f32 = 26.0 + 32.0 + crate::grid::COL_HEADER_H + 2.0 * gridcraft_engine::model::DEFAULT_ROW_HEIGHT; /// The bar's height at one line. const ONE_LINE: f32 = 30.0; /// What the bar adds around the field's rows: the panel's margins (3 + 3), the field's (3 + 3) @@ -92,7 +95,7 @@ pub fn show(app: &mut SheetApp, ui: &mut egui::Ui) { // Height follows the content's line count (last frame's), 1 to MAX_LINES; expanded (the // chevron), it is the height the bottom edge was dragged to. It eases only when that target // changes. - let most = max_lines(ui.available_rect_before_wrap().height(), row_h); + let most = max_lines(ui.ctx().content_rect().height(), ui.available_rect_before_wrap().height(), row_h); let lines = if app.ui.formula_bar_expanded { app.ui.formula_bar_lines.clamp(1, most) } else { last.lines.clamp(1, MAX_LINES) }; let target = one_line(row_h) + (lines - 1) as f32 * row_h; let h = ui.ctx().animate_value_with_time(egui::Id::unique("formula_bar.height"), target, EASE_SECONDS); @@ -178,11 +181,15 @@ pub fn show(app: &mut SheetApp, ui: &mut egui::Ui) { ui.ctx().data_mut(|d| d.insert_temp(BarLayout::id(), layout)); } -/// The most lines the bar takes when `window_h` is the room left below the ribbon: half of it, -/// so the worksheet keeps the rest, and never fewer than the chevron's [`MAX_LINES`]. -fn max_lines(window_h: f32, row_h: f32) -> usize { - let fit = ((window_h * 0.5 - one_line(row_h)) / row_h).floor(); - if fit.is_finite() && fit > 0.0 { (fit as usize + 1).clamp(MAX_LINES, MAX_DRAG_LINES) } else { MAX_LINES } +/// The most lines the bar takes in a window `window_h` tall with `room` left under the ribbon: +/// half the window, as in Excel (never fewer than the chevron's [`MAX_LINES`]), and no more than +/// leaves [`KEEP_BELOW`] for the status bar, sheet tabs and a few rows of the grid. +fn max_lines(window_h: f32, room: f32, row_h: f32) -> usize { + let lines_in = |h: f32| { + let fit = ((h - one_line(row_h)) / row_h).floor(); + if fit.is_finite() && fit > 0.0 { fit as usize + 1 } else { 1 } + }; + lines_in(window_h * 0.5).clamp(MAX_LINES, MAX_DRAG_LINES).min(lines_in(room - KEEP_BELOW)) } /// The lines a bar whose top is at `top` shows with its bottom edge dragged to `y`, in whole lines. diff --git a/crates/ui-egui/tests/it/formula_bar_expand.rs b/crates/ui-egui/tests/it/formula_bar_expand.rs index cabf7ee70..169107ac7 100644 --- a/crates/ui-egui/tests/it/formula_bar_expand.rs +++ b/crates/ui-egui/tests/it/formula_bar_expand.rs @@ -147,3 +147,17 @@ fn expand_formula_bar_with_lines_sets_the_expanded_height() { assert_eq!(h.state_mut().run("view.expandFormulaBar", json!({"lines": 0})), Ok(json!({"on": false, "lines": 8})), "zero lines is one line"); assert_eq!(h.state_mut().run("view.expandFormulaBar", json!({"lines": u64::MAX})), Ok(json!({"on": true, "lines": 100})), "capped"); } + +#[test] +fn an_expanded_formula_bar_leaves_room_for_the_worksheet_in_a_short_window() { + // At 400 pt the title bar and ribbon leave about 236 pt: half the window as a formula bar + // would leave the status bar and sheet tabs no room for any of the grid. + let mut session = Session::new(); + session.new_workbook(); + let mut h = crate::common::harness_with(crate::common::builder().with_size(vec2(1200.0, 400.0)), crate::common::app(session), 4); + h.state_mut().run("view.expandFormulaBar", json!({"lines": 100})).unwrap(); + h.run_steps(60); + let cells = h.state().grid.cells_rect.expect("the grid is drawn"); + assert!(cells.height() >= 40.0, "a couple of rows stay visible under a {} pt bar: {cells:?}", bar(&h).height); + assert!(bar(&h).visible_lines > 1, "the bar is still expanded"); +}