From 1a7fa68376a3f94632e958abe64360a478b4736f Mon Sep 17 00:00:00 2001 From: Hector Villarreal Date: Tue, 3 Nov 2026 08:52:05 -0600 Subject: [PATCH] #1246: an expanded formula bar leaves room for the worksheet Addresses review comment 4456174694: the drag/expand cap was half the window, so in a 400 pt window a ~195 pt bar left the grid about 1.6 pt under the status bar and sheet tabs. The cap is now also limited by the room left under the ribbon, keeping the status bar, sheet tabs, column headings and two rows below the bar. Test: ui-egui formula_bar_expand::an_expanded_formula_bar_leaves_room_for_the_worksheet_in_a_short_window. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/formula_bar.rs | 19 +++++++++++++------ crates/ui-egui/tests/it/formula_bar_expand.rs | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/crates/ui-egui/src/formula_bar.rs b/crates/ui-egui/src/formula_bar.rs index 9be205a4f..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.ctx().content_rect().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 in a window `window_h` tall: half the window, as in Excel, 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"); +}