diff --git a/crates/engine/src/cmd/ruler_tests.rs b/crates/engine/src/cmd/ruler_tests.rs index 95c87c6c..e920ce93 100644 --- a/crates/engine/src/cmd/ruler_tests.rs +++ b/crates/engine/src/cmd/ruler_tests.rs @@ -50,7 +50,9 @@ fn tabs_add_move_remove_clear_and_undo() { assert_eq!(tabs(&mut s).len(), 2); s.execute("format.tabs", &json!({"clear": true})).unwrap(); assert!(tabs(&mut s).is_empty()); - assert!(s.execute("format.tabs", &json!({})).is_err()); + s.ui_requests.clear(); + s.execute("format.tabs", &json!({})).unwrap(); + assert!(matches!(s.ui_requests.last(), Some(crate::UiRequest::Dialog { id, .. }) if id == "tabs"), "no fields opens the Tabs dialog"); assert!(s.execute("format.tabs", &json!({"add": {"pos": f64::MAX}})).is_ok(), "clamped, not a crash"); for i in 0..100 { s.execute("format.tabs", &json!({"add": {"pos": i as f64 * 3.0}})).unwrap(); diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs index fb890e1f..e570233b 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -2773,7 +2773,9 @@ const TAB_KINDS: [(&str, &str); 4] = [("l", "Left"), ("ctr", "Center"), ("r", "R /// list (inches, as PowerPoint's dialog) and applied together with OK. fn tabs_dialog(app: &mut SlideApp, ui: &mut Ui, d: &mut Dialog) -> bool { if !d.fields.contains_key("stops") { - let r = app.session.execute("format.ruler", &json!({})).unwrap_or_default(); + // Opened from Paragraph (or by `format.tabs` with no fields) the stops come with the + // dialog; otherwise they are read from the caret's paragraph. + let r = if d.params.get("tabs").is_some() { d.params.clone() } else { app.session.execute("format.ruler", &json!({})).unwrap_or_default() }; let stops: Vec = r["tabs"] .as_array() .map(|a| a.iter().filter_map(|t| Some(format!("{}:{}", t["pos"].as_f64()? / 72.0, t["align"].as_str().unwrap_or("l")))).collect()) @@ -2846,6 +2848,10 @@ fn tabs_dialog(app: &mut SlideApp, ui: &mut Ui, d: &mut Dialog) -> bool { let dt = num(d, "default", 1.0).clamp(0.02, 56.0) * 72.0; if let Err(e) = app.run("format.tabs", json!({"set": set, "defaultTab": dt})) { app.set_status(e); + } else if let Some(ret) = d.params.get_mut("returnParams").and_then(Value::as_object_mut) { + // Back in Paragraph, its Tabs… shows what was just applied. + ret.insert("tabs".into(), json!(set)); + ret.insert("defaultTab".into(), json!(dt)); } } ok || cancel diff --git a/crates/ui-egui/src/paragraph_dialog_tests.rs b/crates/ui-egui/src/paragraph_dialog_tests.rs index cba8fe53..fb8e796b 100644 --- a/crates/ui-egui/src/paragraph_dialog_tests.rs +++ b/crates/ui-egui/src/paragraph_dialog_tests.rs @@ -71,8 +71,7 @@ fn tabs_from_paragraph_applies_a_stop_and_returns() { assert_eq!(h.state().dialog.as_ref().map(|d| d.id.as_str()), Some("tabs"), "status {:?}", h.state().status); { let d = h.state_mut().dialog.as_mut().unwrap(); - d.params["editing"] = json!(true); - d.params["edit"] = json!([{"pos": 144.0, "align": "ctr"}]); + d.fields.insert("stops".into(), "2:ctr".into()); } h.get_by_label("OK").click_accesskit(); // The Tabs OK frame restores Paragraph; the next frame fills its fields.