From 625f598b64b0868c7ed4881e3e36c210433fe42a Mon Sep 17 00:00:00 2001 From: batistalucasv Date: Sun, 8 Nov 2026 00:56:55 -0300 Subject: [PATCH] Fix #5750: style-set gallery follows RTL interface direction (#5857) --- crates/ui-egui/src/previews.rs | 2 +- crates/ui-egui/src/ribbon/design.rs | 5 ++-- crates/ui-egui/src/ribbon/tests.rs | 43 +++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/crates/ui-egui/src/previews.rs b/crates/ui-egui/src/previews.rs index 5d02c834dd..1ff99e1073 100644 --- a/crates/ui-egui/src/previews.rs +++ b/crates/ui-egui/src/previews.rs @@ -694,7 +694,7 @@ pub fn style_gallery(app: &mut WordApp, ui: &mut Ui, state: &Value) { /// Style sets shown in the Design tab's gallery, in order. const STYLE_SETS: [&str; 7] = ["default", "basic", "lines", "shaded", "casual", "centered", "minimalist"]; /// Width of one gallery thumbnail, points. -const STYLE_SET_W: f32 = 56.0; +pub const STYLE_SET_W: f32 = 56.0; /// Width the whole gallery takes with the ribbon's 1 pt item spacing. pub const STYLE_SET_GALLERY_W: f32 = STYLE_SETS.len() as f32 * (STYLE_SET_W + 1.0) - 1.0; diff --git a/crates/ui-egui/src/ribbon/design.rs b/crates/ui-egui/src/ribbon/design.rs index 8208c86318..9b078e2058 100644 --- a/crates/ui-egui/src/ribbon/design.rs +++ b/crates/ui-egui/src/ribbon/design.rs @@ -3,11 +3,12 @@ use super::{CONTENT_H, Rect, Sense, Target, Ui, WordApp, big, group, json, menu_ /// The Design tab's style set gallery in a box of its own, sized from its thumbnails and clipped /// to it, with a gap on each side: the Colors and Fonts column can't be drawn over, or cut by, -/// the thumbnails (#638). Returns the box and the space the thumbnails used. +/// the thumbnails (#638). In a right-to-left interface, the thumbnails lay out from the right +/// (#5750). Returns the box and the space the thumbnails used. pub(super) fn style_set_box(app: &mut WordApp, ui: &mut Ui) -> (Rect, Rect) { ui.add_space(4.0); let (gallery, _) = ui.allocate_exact_size(vec2(crate::previews::STYLE_SET_GALLERY_W, CONTENT_H), Sense::hover()); - let mut gui = ui.new_child(egui::UiBuilder::new().max_rect(gallery).layout(egui::Layout::left_to_right(egui::Align::Min))); + let mut gui = ui.new_child(egui::UiBuilder::new().max_rect(gallery).layout(crate::rtl::row_layout(ui, egui::Align::Min))); gui.set_clip_rect(gallery.intersect(ui.clip_rect())); gui.spacing_mut().item_spacing = vec2(1.0, 1.0); crate::previews::style_set_gallery(app, &mut gui); diff --git a/crates/ui-egui/src/ribbon/tests.rs b/crates/ui-egui/src/ribbon/tests.rs index 745750b5a3..444c60acb1 100644 --- a/crates/ui-egui/src/ribbon/tests.rs +++ b/crates/ui-egui/src/ribbon/tests.rs @@ -113,6 +113,49 @@ fn design_style_set_gallery_stays_in_its_box() { assert!(next_x >= gallery.right() + 8.0 - 0.01, "{next_x} {gallery:?}"); } +/// #5750: in a right-to-left interface, the Design tab's style-set gallery lays out from the +/// right: the first style set ("default") is at the right edge, the remaining thumbnails read to +/// the left, and the next controls start after a gap to the left of the gallery. +#[test] +fn design_style_set_gallery_reads_from_the_right_in_rtl() { + crate::i18n::set_current(crate::i18n::fixture_lang("ar", "\tHome\tالرئيسية\n")); + let mut app = WordApp::new(Session::new(wordcraft_doc::Document::new()), crate::Services::default()); + let mut seen = None; + let mut h = egui_kittest::Harness::builder().with_size(vec2(1440.0, 200.0)).build_ui(|ui| { + crate::rtl::root(ui, |ui| { + crate::rtl::horizontal_top(ui, |ui| { + let (gallery, used) = style_set_box(&mut app, ui); + seen = Some((gallery, used, ui.cursor().max.x)); + }); + }); + }); + h.run_steps(2); + let tiles: Vec = h.ctx.viewport(|v| { + v.prev_pass + .widgets + .layers() + .flat_map(|(_, w)| w.iter()) + .filter(|w| (w.rect.width() - crate::previews::STYLE_SET_W).abs() < 0.1 && (w.rect.height() - CONTENT_H).abs() < 0.1) + .map(|w| w.rect) + .collect() + }); + drop(h); + crate::i18n::set_current(crate::i18n::Lang::EN); + + let (gallery, used, next_x) = seen.unwrap(); + assert!((gallery.width() - crate::previews::STYLE_SET_GALLERY_W).abs() < 0.01); + assert!(used.left() >= gallery.left() - 0.01, "{used:?} {gallery:?}"); + assert!(used.right() <= gallery.right() + 0.01, "{used:?} {gallery:?}"); + assert!(next_x <= gallery.left() - 8.0 + 0.01, "{next_x} {gallery:?}"); + + assert_eq!(tiles.len(), 7, "7 style set tiles"); + assert!((tiles[0].right() - gallery.right()).abs() < 0.01, "default tile at the right edge: {tiles:?} {gallery:?}"); + assert!((tiles[6].left() - gallery.left()).abs() < 0.01, "minimalist tile at the left edge: {tiles:?} {gallery:?}"); + for i in 1..tiles.len() { + assert!(tiles[i].right() <= tiles[i - 1].left(), "tile {i} is to the left of tile {}", i - 1); + } +} + /// #2738: Home › Underline's drop-down: every line sample is a named entry (assistive /// technology, tooltips) that applies its own style; Words only, None and Underline Color › /// Automatic do what they say.