Merge PR #3252 (author's fix: an expanded formula bar leaves room for the worksheet)

# Conflicts:
#	crates/ui-egui/src/formula_bar.rs
This commit is contained in:
Brandon Thomas committed 2026-11-03 10:00:05 -05:00
commit ed2347782d
2 files changed
+27 -6

No files matched your search

+13 -6
View File
@@ -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.
@@ -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");
}