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;