From 27e34098d323d73be74e8e5dbbfc242ae4bff113 Mon Sep 17 00:00:00 2001 From: FredApps <153173854+FredApps@users.noreply.github.com> Date: Sun, 1 Nov 2026 16:34:15 +0100 Subject: [PATCH] fix(ui): size the font field for the localized mixed label Measure Mixed with the active body font and include the input margins and caret allowance. Keep that minimum stable while typing so the full label is visible without shifting the row on each keystroke. A themed panel regression fails against the old 40-pixel input, verifies the text fits inside the field margins and keeps the alignment control inside a 272-pixel pane. Linux scoped clippy, format tests, wasm, formatting, layering and assets pass. Co-Authored-By: Codex GPT-6.1 --- crates/ui-egui/src/panels/format_text_ui.rs | 40 +++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/panels/format_text_ui.rs b/crates/ui-egui/src/panels/format_text_ui.rs index 3a3fa7d517..963032fc4e 100644 --- a/crates/ui-egui/src/panels/format_text_ui.rs +++ b/crates/ui-egui/src/panels/format_text_ui.rs @@ -471,8 +471,13 @@ fn font_size_input(ui: &mut egui::Ui, size: &mut f64, mixed: bool) -> bool { if previous != size.to_bits() || previous_mixed != mixed { text = initial_text(); } - let field = egui::TextEdit::singleline(&mut text).id(id).desired_width(40.0); - let response = ui.add_sized([40.0, ui.spacing().interact_size.y], field).accessible_name(tl!("Font size:")); + // Reserve the localized mixed label, field margins and caret without resizing while typing. + let font = egui::TextStyle::Body.resolve(ui.style()); + let margin = egui::Margin::from(ui.spacing().button_padding); + let mixed_width = ui.painter().layout_no_wrap(tl!("Mixed").into(), font.clone(), ui.visuals().text_color()).size().x; + let width = (mixed_width + margin.sum().x + 2.0).ceil().max(40.0); + let field = egui::TextEdit::singleline(&mut text).id(id).font(font).margin(margin).desired_width(width); + let response = ui.add_sized([width, ui.spacing().interact_size.y], field).accessible_name(tl!("Font size:")); let cancel = (response.has_focus() || response.lost_focus()) && ui.input(|i| i.key_pressed(egui::Key::Escape)); if cancel { text = initial_text(); @@ -541,6 +546,37 @@ mod typed_size_tests { } } + #[test] + fn mixed_size_label_fits_the_themed_panel() { + crate::i18n::set_current(crate::i18n::Lang::EN); + let mut ready = false; + let mut h = egui_kittest::Harness::builder().with_size(vec2(272.0, 500.0)).with_accessibility_check(false).build_ui_state( + move |ui, look: &mut AddedText| { + if !ready { + egui_extras::install_image_loaders(ui.ctx()); + crate::theme::install_fonts(ui.ctx()); + crate::theme::apply(ui.ctx(), crate::theme::ThemeKind::Light); + ready = true; + return; + } + let fonts = Fonts { sources: Some(&[]), shown: tl!("Mixed").into(), mixed_size: true }; + panel(ui, &Tokens::get(ui.ctx()), look, None, fonts, None); + }, + AddedText::default(), + ); + h.run_steps(4); + let field = h.get_by_role_and_label(egui::accesskit::Role::TextInput, "Font size:"); + let style = h.ctx.global_style(); + let font = egui::TextStyle::Body.resolve(&style); + let width = h.ctx.fonts_mut(|fonts| fonts.layout_no_wrap(tl!("Mixed").into(), font, Color32::BLACK).size().x); + let padding = 2.0 * style.spacing.button_padding.x; + assert!(field.rect().width() - padding >= width, "Mixed must fit inside the input margins"); + assert!(h.get_by_label("Alignment").rect().right() <= 272.0, "the wider size field must leave room for the rest of the format row"); + if let Ok(path) = std::env::var("PDFCRAFT_MIXED_PANEL_SHOT") { + h.render().unwrap().save(path).unwrap(); + } + } + #[test] fn mixed_size_changes_refresh_the_field_without_discarding_a_draft() { let mut h = egui_kittest::Harness::new_ui_state(