diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs index 239a913b2..898548a37 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -1732,6 +1732,13 @@ pub fn confirm(app: &mut DesignApp) -> Result { } Ok(r) } + "paragraphRules" => { + let attrs = rule_edits(&d, ""); + if attrs.is_empty() { + return Ok(Value::Null); + } + app.run("type.para", json!({"attrs": attrs})) + } "characterStyleOptions" => { let name = d.s("name"); let mut chars = Map::new(); @@ -1769,13 +1776,6 @@ pub fn confirm(app: &mut DesignApp) -> Result { } r } - "paragraphRules" => { - let attrs = rule_edits(&d, ""); - if attrs.is_empty() { - return Ok(Value::Null); - } - app.run("type.para", json!({"attrs": attrs})) - } "colorPicker" => { let hex = d.s("hex"); app.run("object.color", json!({"color": hex, "target": d.s("target"), "text": d.b("text")})) @@ -3672,73 +3672,6 @@ fn find_font(app: &mut DesignApp, ui: &mut egui::Ui, d: &mut Dialog) { mod tests { use super::*; - fn command_app(id: &str, fields: Value) -> DesignApp { - let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default()); - app.ui.dialog = Some(Dialog::new(&format!("cmd:{id}"), fields)); - app - } - - #[test] - fn generic_new_document_preserves_typed_values_and_text_entry() { - for pages in [json!(2), json!(" 2 ")] { - let mut app = command_app( - "file.new", - json!({ - "preset": "A4", "pages": pages, "facingPages": false, "gutter": 0, - "margins": {"top": 10, "bottom": 20, "inside": 30, "outside": 40}, - "title": " ", "status": "internal", "primaryTextFrame": true - }), - ); - confirm(&mut app).unwrap(); - let doc = &app.session.active().unwrap().doc; - assert_eq!(doc.page_count(), 2); - assert!(!doc.settings.facing_pages); - assert!(doc.title.starts_with("Untitled-")); - for page in doc.spreads.iter().flat_map(|s| &s.pages) { - assert!((page.width - 595.2755905511812).abs() < 0.01); - assert!((page.height - 841.8897637795277).abs() < 0.01); - assert_eq!(page.columns.gutter, 0.0); - assert_eq!(page.margins.top, 10.0); - assert_eq!(page.margins.outside, 40.0); - } - assert!(doc.spreads.iter().all(|s| s.items.is_empty()), "undocumented fields stay excluded"); - assert!(app.ui.dialog.is_none()); - } - } - - #[test] - fn generic_command_preserves_array_geometry() { - let mut app = command_app("file.new", json!({})); - confirm(&mut app).unwrap(); - app.ui.dialog = Some(Dialog::new("cmd:frame.create", json!({"rect": [10, 20, 110, 220]}))); - confirm(&mut app).unwrap(); - let doc = &app.session.active().unwrap().doc; - let item = doc.spreads.iter().flat_map(|s| &s.items).next().unwrap(); - assert_eq!(item.bounds(), designcraft_geom::Rect::new(10.0, 20.0, 110.0, 220.0)); - } - - #[test] - fn generic_explicit_null_uses_the_commands_existing_semantics() { - // file.new accepts null width by using the selected preset's width. - for width in [Value::Null, json!("null")] { - let mut app = command_app("file.new", json!({"preset": "A4", "width": width, "title": " Sample layout "})); - confirm(&mut app).unwrap(); - let doc = &app.session.active().unwrap().doc; - assert_eq!(doc.title, "Sample layout"); - assert!((doc.settings.page_width - 595.2755905511812).abs() < 0.01); - } - } - - #[test] - fn generic_invalid_number_retains_dialog_without_creating_document() { - let mut app = command_app("file.new", json!({"width": 0})); - assert!(confirm(&mut app).is_err()); - assert!(app.session.active().is_none()); - let dialog = app.ui.dialog.as_ref().unwrap(); - assert_eq!(dialog.fields["width"], 0); - assert!(dialog.fields["status"].as_str().unwrap().contains("page size out of range")); - } - fn draw(app: &mut DesignApp, ctx: &egui::Context) { let input = egui::RawInput { screen_rect: Some(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1400.0, 900.0))), ..Default::default() }; @@ -3812,6 +3745,73 @@ mod tests { assert_eq!(resolved(&app)["ruleBelow"], rule); } + fn command_app(id: &str, fields: Value) -> DesignApp { + let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default()); + app.ui.dialog = Some(Dialog::new(&format!("cmd:{id}"), fields)); + app + } + + #[test] + fn generic_new_document_preserves_typed_values_and_text_entry() { + for pages in [json!(2), json!(" 2 ")] { + let mut app = command_app( + "file.new", + json!({ + "preset": "A4", "pages": pages, "facingPages": false, "gutter": 0, + "margins": {"top": 10, "bottom": 20, "inside": 30, "outside": 40}, + "title": " ", "status": "internal", "primaryTextFrame": true + }), + ); + confirm(&mut app).unwrap(); + let doc = &app.session.active().unwrap().doc; + assert_eq!(doc.page_count(), 2); + assert!(!doc.settings.facing_pages); + assert!(doc.title.starts_with("Untitled-")); + for page in doc.spreads.iter().flat_map(|s| &s.pages) { + assert!((page.width - 595.2755905511812).abs() < 0.01); + assert!((page.height - 841.8897637795277).abs() < 0.01); + assert_eq!(page.columns.gutter, 0.0); + assert_eq!(page.margins.top, 10.0); + assert_eq!(page.margins.outside, 40.0); + } + assert!(doc.spreads.iter().all(|s| s.items.is_empty()), "undocumented fields stay excluded"); + assert!(app.ui.dialog.is_none()); + } + } + + #[test] + fn generic_command_preserves_array_geometry() { + let mut app = command_app("file.new", json!({})); + confirm(&mut app).unwrap(); + app.ui.dialog = Some(Dialog::new("cmd:frame.create", json!({"rect": [10, 20, 110, 220]}))); + confirm(&mut app).unwrap(); + let doc = &app.session.active().unwrap().doc; + let item = doc.spreads.iter().flat_map(|s| &s.items).next().unwrap(); + assert_eq!(item.bounds(), designcraft_geom::Rect::new(10.0, 20.0, 110.0, 220.0)); + } + + #[test] + fn generic_explicit_null_uses_the_commands_existing_semantics() { + // file.new accepts null width by using the selected preset's width. + for width in [Value::Null, json!("null")] { + let mut app = command_app("file.new", json!({"preset": "A4", "width": width, "title": " Sample layout "})); + confirm(&mut app).unwrap(); + let doc = &app.session.active().unwrap().doc; + assert_eq!(doc.title, "Sample layout"); + assert!((doc.settings.page_width - 595.2755905511812).abs() < 0.01); + } + } + + #[test] + fn generic_invalid_number_retains_dialog_without_creating_document() { + let mut app = command_app("file.new", json!({"width": 0})); + assert!(confirm(&mut app).is_err()); + assert!(app.session.active().is_none()); + let dialog = app.ui.dialog.as_ref().unwrap(); + assert_eq!(dialog.fields["width"], 0); + assert!(dialog.fields["status"].as_str().unwrap().contains("page size out of range")); + } + #[test] fn text_frame_options_change_only_what_was_edited() { let mut app = crate::DesignApp::new(designcraft_engine::Session::new(), crate::Services::default()); diff --git a/crates/ui-egui/src/i18n.rs b/crates/ui-egui/src/i18n.rs index 13192562a..db3a7faf7 100644 --- a/crates/ui-egui/src/i18n.rs +++ b/crates/ui-egui/src/i18n.rs @@ -2314,7 +2314,6 @@ const TABLE: &[(&str, [&str; 5])] = &[ ("Baseline Shift:", ["Baseline Shift:", "Baseline Shift:", "Baseline Shift:", "Baseline Shift:", "基线偏移:"]), ("Skew:", ["Skew:", "Skew:", "Skew:", "Skew:", "倾斜:"]), ("Language:", ["Language:", "Language:", "Language:", "Language:", "语言:"]), - ("Tint:", ["Farbton:", "Teinte:", "Matiz:", "濃淡:", "色调:"]), ("Figure Style:", ["Figure Style:", "Figure Style:", "Figure Style:", "Figure Style:", "数字样式:"]), ("Underline On", ["Underline On", "Underline On", "Underline On", "Underline On", "启用下划线"]), ("Strikethrough On", ["Strikethrough On", "Strikethrough On", "Strikethrough On", "Strikethrough On", "启用删除线"]), @@ -2794,6 +2793,7 @@ const TABLE: &[(&str, [&str; 5])] = &[ ("Paragraph Rules…", ["Absatzlinien …", "Filets de paragraphe…", "Filetes de párrafo…", "段落境界線…", "段落线…"]), ("Paragraph Rules", ["Absatzlinien", "Filets de paragraphe", "Filetes de párrafo", "段落境界線", "段落线"]), ("Rule Below", ["Linie unterhalb", "Filet après", "Filete después", "後境界線", "下方横线"]), + ("Tint:", ["Farbton:", "Teinte:", "Matiz:", "濃淡:", "色调:"]), ("Column", ["Spalte", "Colonne", "Columna", "段", "栏"]), ];