A panel label too wide for its panel (beside its caret) wraps between words onto a second line; a single word wider than the panel stays whole. Each line is centred, and the label's hover area grows to hold both lines. A panel's buttons are centred in the panel, so a one-button panel such as Finish Sketch lines its icon up with its label. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
102 lines
4.7 KiB
Rust
102 lines
4.7 KiB
Rust
//! Localization must not change scenario handles or leave the next app in another locale.
|
|
|
|
use crate::scenario::{self, Harness};
|
|
use serde_json::json;
|
|
|
|
#[test]
|
|
fn japanese_dialog_keeps_english_scenario_handles() {
|
|
let mut h = Harness::new();
|
|
h.app.preferences.language = "ja".into();
|
|
h.app.home.open = false;
|
|
h.call("ui.start", json!({"command":"sketch.create"}));
|
|
h.frames(3);
|
|
assert!(h.widget("平面").is_some(), "the input label must be translated");
|
|
assert!(h.widget("キャンセル").is_some(), "the close button must be translated");
|
|
assert!(!scenario::handles("dialog:Plane").is_empty(), "scenario handles must retain source labels");
|
|
assert_eq!(crate::i18n::tr("ui.preferences"), "Preferences", "the render scope must restore English");
|
|
|
|
h.app.preferences.language = "en".into();
|
|
h.frames(3);
|
|
assert!(h.widget("Plane").is_some());
|
|
assert!(h.widget("Cancel").is_some());
|
|
}
|
|
|
|
#[test]
|
|
fn language_preference_cancel_restores_previous_locale() {
|
|
let mut h = Harness::new();
|
|
h.app.home.open = false;
|
|
h.call("ui.prefs", json!({"open":"General"}));
|
|
h.call("ui.prefs", json!({"language":"ja"}));
|
|
assert!(h.widget("言語").is_some());
|
|
assert_eq!(h.app.preferences.language, "ja");
|
|
h.call("ui.prefs", json!({"button":"cancel"}));
|
|
assert_eq!(h.app.preferences.language, "en");
|
|
assert_eq!(h.app.tr("ui.preferences"), "Preferences");
|
|
}
|
|
|
|
#[test]
|
|
fn translated_dialog_buttons_do_not_wrap() {
|
|
fn cancel_rows(shape: &egui::Shape) -> Option<usize> {
|
|
match shape {
|
|
egui::Shape::Text(text) if text.galley.job.text == "キャンセル" => Some(text.galley.rows.len()),
|
|
egui::Shape::Vec(shapes) => shapes.iter().find_map(cancel_rows),
|
|
_ => None,
|
|
}
|
|
}
|
|
let mut h = Harness::new();
|
|
crate::fonts::setup_fonts(&h.ctx);
|
|
h.app.preferences.language = "ja".into();
|
|
h.app.home.open = false;
|
|
h.call("ui.start", json!({"command":"solid.extrude"}));
|
|
let mut out = h.ctx.run_ui(
|
|
egui::RawInput { screen_rect: Some(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1600.0, 1000.0))), ..Default::default() },
|
|
|ui| h.app.ui(ui),
|
|
);
|
|
assert_eq!(out.shapes.iter().find_map(|shape| cancel_rows(&shape.shape)), Some(1));
|
|
out.textures_delta.clear();
|
|
}
|
|
|
|
#[test]
|
|
fn long_panel_label_wraps_centred_and_its_button_is_centred() {
|
|
fn label_rows(shape: &egui::Shape) -> Option<Vec<egui::Rect>> {
|
|
match shape {
|
|
egui::Shape::Text(text) if text.galley.job.text == "SKIZZE BEENDEN" => {
|
|
Some(text.galley.rows.iter().map(|row| row.rect().translate(text.pos.to_vec2())).collect())
|
|
}
|
|
egui::Shape::Vec(shapes) => shapes.iter().find_map(label_rows),
|
|
_ => None,
|
|
}
|
|
}
|
|
fn hover_rect(shape: &egui::Shape, hover: egui::Color32, at: egui::Pos2) -> Option<egui::Rect> {
|
|
match shape {
|
|
egui::Shape::Rect(r) if r.fill == hover && r.rect.contains(at) => Some(r.rect),
|
|
egui::Shape::Vec(shapes) => shapes.iter().find_map(|s| hover_rect(s, hover, at)),
|
|
_ => None,
|
|
}
|
|
}
|
|
let mut h = Harness::new();
|
|
h.app.preferences.language = "de".into();
|
|
h.app.home.open = false;
|
|
h.app.run("sketch.create", json!({"plane":"xy"})).unwrap();
|
|
h.frames(2);
|
|
let label = scenario::handles("panel:SKETCH:FINISH SKETCH")[0].1;
|
|
let button = scenario::handles("button:sketch.finish")[0].1;
|
|
assert!((label.x - button.x).abs() < 1.0, "the only button sits centred over its label: {label:?} {button:?}");
|
|
|
|
let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1600.0, 1000.0));
|
|
let mut out =
|
|
h.ctx.run_ui(egui::RawInput { screen_rect: Some(screen), events: vec![egui::Event::PointerMoved(label)], ..Default::default() }, |ui| {
|
|
h.app.ui(ui)
|
|
});
|
|
out.textures_delta.clear();
|
|
let mut out = h.ctx.run_ui(egui::RawInput { screen_rect: Some(screen), ..Default::default() }, |ui| h.app.ui(ui));
|
|
let rows = out.shapes.iter().find_map(|shape| label_rows(&shape.shape)).expect("the Finish Sketch panel label is drawn");
|
|
assert_eq!(rows.len(), 2, "the label wider than its one-button panel wraps: {rows:?}");
|
|
assert!(rows[0].width() != rows[1].width(), "the lines differ in width: {rows:?}");
|
|
assert!((rows[0].center().x - rows[1].center().x).abs() < 1.0, "each line is centred: {rows:?}");
|
|
let hover = crate::theme::Tokens::get().hover;
|
|
let lr = out.shapes.iter().find_map(|shape| hover_rect(&shape.shape, hover, label)).expect("the hovered label is highlighted");
|
|
assert!(rows.iter().all(|row| lr.contains_rect(*row)), "the highlight holds both lines: {lr:?} {rows:?}");
|
|
out.textures_delta.clear();
|
|
}
|