diff --git a/crates/ui-egui/src/grid.rs b/crates/ui-egui/src/grid.rs index 40ef2c8e9..acef3f8cb 100644 --- a/crates/ui-egui/src/grid.rs +++ b/crates/ui-egui/src/grid.rs @@ -3087,6 +3087,13 @@ fn keyboard(app: &mut SheetApp, ctx: &egui::Context, resp: &egui::Response, geo: } } +/// Room the in-cell editor keeps right of its text. It is sized from the text of the last frame, so +/// the next typed character must still fit: a fixed 14 px was less than one glyph at high zoom, +/// and the field scrolled and snapped back on every key (#2336). `size` is the font size in px. +fn editor_slack(size: f32) -> f32 { + 14.0 + size +} + fn in_cell_editor(app: &mut SheetApp, ui: &mut egui::Ui, geo: &Geo, sh: &Sheet, wb: &Workbook) { let Some(ed) = app.editor.as_ref() else { return }; if ed.sheet != wb.active_sheet { @@ -3113,7 +3120,7 @@ fn in_cell_editor(app: &mut SheetApp, ui: &mut egui::Ui, geo: &Geo, sh: &Sheet, let text_w = ui.painter().layout_no_wrap(ed.text.clone(), font.clone(), Color32::BLACK).size().x; // Excel keeps the cell's height for one line and only grows for extra lines. let h = if lines > 1.0 { (size * 1.3 * lines + 4.0).max(rect.height()) } else { rect.height() }; - ((text_w + 14.0).max(rect.width()).min(geo.cells.right() - rect.left()), h) + ((text_w + editor_slack(size)).max(rect.width()).min(geo.cells.right() - rect.left()), h) }; // Grows to the left on a right-to-left sheet. let erect = geo.mirror_rect(Rect::from_min_size(rect.min, vec2(w, h))); @@ -4002,6 +4009,15 @@ pub(crate) fn heading_font_size(zoom: f32) -> f32 { #[cfg(test)] mod tests { + #[test] + fn editor_slack_fits_one_more_glyph_at_high_zoom() { + use super::editor_slack; + // A glyph is at most about one em wide; at 400% an em is ~60 px, far over the old fixed 14 px. + for size in [14.7_f32, 25.0, 60.0] { + assert!(editor_slack(size) - 4.0 >= size, "slack {} too small for a {size} px glyph", editor_slack(size)); + } + } + #[test] fn explicit_left_and_right_keep_their_side_on_a_right_to_left_sheet() { use super::{HAlign, painted_halign};