From d90cf79a2a482c23b442dd5b3c88897aa9644eb2 Mon Sep 17 00:00:00 2001 From: RiceDee <345114586+RiceDee@users.noreply.github.com> Date: Sun, 1 Nov 2026 20:02:38 +1100 Subject: [PATCH] fix(ui): the line spacing list keeps its column in every language (#5634) A longer "Auto" (Czech "Automaticky") pushed the list 46 pt past the Tools pane at its narrowest. It is now cut short, with the whole word in the list's menu and tooltip. A test checks the lists in every interface language the fonts can draw, and the narrow-pane test also runs at the largest interface size. --- crates/ui-egui/src/panels/format_text_ui.rs | 27 +++++++++++++------- crates/ui-egui/tests/it/content.rs | 28 +++++++++++++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/crates/ui-egui/src/panels/format_text_ui.rs b/crates/ui-egui/src/panels/format_text_ui.rs index dd60b3bcc8..7b2763bf32 100644 --- a/crates/ui-egui/src/panels/format_text_ui.rs +++ b/crates/ui-egui/src/panels/format_text_ui.rs @@ -271,13 +271,20 @@ pub(crate) fn panel( let own = tl!("Auto").to_string(); let shown = if e.line_spacing == 0.0 { own.clone() } else { number(e.line_spacing) }; outlined(ui, |ui| { - let list = craft_ui::ComboBox::from_id_salt("format-line-spacing").selected_text(centred(ui, &shown)).width(half).show_ui(ui, |ui| { - ui.selectable_value(&mut e.line_spacing, 0.0, own.as_str()); - for v in LINE_SPACINGS { - ui.selectable_value(&mut e.line_spacing, v, number(v)); - } - }); - list.response.labelled_by(label.id); + // The column is `half` wide in every language: a longer "Auto" is cut short (the + // menu and the tooltip have it whole). + ui.set_max_width(half); + let list = craft_ui::ComboBox::from_id_salt("format-line-spacing") + .selected_text(centred(ui, &shown)) + .width(half) + .wrap_mode(egui::TextWrapMode::Truncate) + .show_ui(ui, |ui| { + ui.selectable_value(&mut e.line_spacing, 0.0, own.as_str()); + for v in LINE_SPACINGS { + ui.selectable_value(&mut e.line_spacing, v, number(v)); + } + }); + list.response.labelled_by(label.id).on_hover_text(&shown); }); ui.add_space(8.0); ui.add_enabled_ui(false, |ui| { @@ -382,11 +389,13 @@ struct Number<'a> { /// A combo box's selected text, centred in its button. The button lays out the text and then its /// arrow, and every growing atom takes an equal share of the room left: a pad as wide as the arrow -/// before the text balances the arrow after it, and the text centres itself in its own share. +/// before the text balances the arrow after it, and the text centres itself in its own share. Text +/// longer than the list is wide (a translated "Auto") is cut short rather than widening it. fn centred<'a>(ui: &egui::Ui, text: &str) -> egui::Atoms<'a> { use egui::AtomExt as _; let pad = egui::Atom::custom(egui::IdSalt::new("combo-pad"), vec2(ui.spacing().icon_width, 0.0)).atom_grow(true); - egui::Atoms::new((pad, egui::Atom::from(text.to_string()).atom_grow(true).atom_align(egui::Align2::CENTER_CENTER))) + let text = egui::Atom::from(text.to_string()).atom_grow(true).atom_shrink(true).atom_align(egui::Align2::CENTER_CENTER); + egui::Atoms::new((pad, text)) } /// The arrow that lists a field's common values, centred on the 26-point field beside it. diff --git a/crates/ui-egui/tests/it/content.rs b/crates/ui-egui/tests/it/content.rs index c4d2223824..a798505551 100644 --- a/crates/ui-egui/tests/it/content.rs +++ b/crates/ui-egui/tests/it/content.rs @@ -727,6 +727,8 @@ fn format_text_rows_line_up_and_fit_the_panel() { fn format_text_fits_the_tools_pane_at_its_narrowest() { use egui::accesskit::Role; let mut h = harness(); + // At the largest interface size too: it scales points to pixels, and the layout is in points. + h.state_mut().set_option("ui-scale", "300").unwrap(); h.state_mut().side_panels.tools_width = 0.0; assert!(h.state_mut().execute("edit.text")); h.run_steps(3); @@ -752,6 +754,32 @@ fn format_text_fits_the_tools_pane_at_its_narrowest() { } } +/// The lists in Format text fit the narrowest Tools pane in every interface language: "Auto" in +/// the line spacing list is the one word in them that is translated, and in German, Ukrainian or +/// Lao it is twice as long. The font list spans the pane, so nothing may end past it. +#[test] +fn format_text_lists_fit_the_narrowest_tools_pane_in_every_language() { + use egui::accesskit::Role; + for lang in pdfcraft_ui_egui::i18n::Lang::all() { + let mut h = harness(); + // A script with no face on this machine (Lao without system fonts) can't be drawn at all. + if !h.ctx.fonts_mut(|f| f.has_glyphs(&egui::FontId::proportional(13.0), lang.name())) { + continue; + } + h.state_mut().set_option("language", lang.code()).unwrap(); + h.state_mut().side_panels.tools_width = 0.0; + assert!(h.state_mut().execute("edit.text")); + h.run_steps(3); + let lists: Vec = h.query_all_by_role(Role::ComboBox).map(|n| n.rect()).collect(); + // Found by its value (a font name, never translated), not as the widest list: an overrun + // could make another list the widest. + let font = h.query_all_by_role(Role::ComboBox).find(|n| n.value().as_deref() == Some("Helvetica")).map(|n| n.rect()).expect("the font list"); + for r in &lists { + assert!(r.right() <= font.right() + 0.5, "{}: {r:?} reaches past the font list ({font:?})", lang.code()); + } + } +} + #[test] fn format_text_panel_sets_alignment_and_lists_planned_controls_disabled() { use egui_kittest::kittest::NodeT;