From 527a2142d9e6a121223ca61a980177958efe5056 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sun, 15 Nov 2026 08:35:38 -0800 Subject: [PATCH] Effects: Radial Blur's dialog sends a saved Blur Center outside the bounds at the edge A Radial Blur whose saved centerX or centerY lies outside 0 to 1 draws at the nearest edge, and its dialog showed the center there. The dialog kept the saved value in its fields, though, so OK without moving the center sent that value, and effect.setParams refused it. The Blur Center box now writes the center it shows, kept within 0 to 1, into the dialog's fields on every frame, so OK stores the edge. --- crates/ui-egui/src/dialogs/effect.rs | 47 +++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/crates/ui-egui/src/dialogs/effect.rs b/crates/ui-egui/src/dialogs/effect.rs index cd089e04bd..5a4799d22d 100644 --- a/crates/ui-egui/src/dialogs/effect.rs +++ b/crates/ui-egui/src/dialogs/effect.rs @@ -321,12 +321,12 @@ fn center_round(x: f64) -> f64 { /// for Zoom, rings for Spin) drawn about the center. A press or a drag in the box puts the center /// there; with the keyboard focus the arrow keys move it 1 % of the box (10 % with Shift). The /// Horizontal and Vertical fields beside it type the same position in percent of the bounds' width -/// and height. Changes go to `d.fields["centerX"]` and `["centerY"]`. +/// and height. The center the box shows, kept within 0 to 1, goes to `d.fields["centerX"]` and +/// `["centerY"]`. fn blur_center(ui: &mut egui::Ui, d: &mut Dialog) { use egui::{Key, Modifiers, Sense, Stroke}; let [kx, ky] = BLUR_CENTER; let mut c = [d.f64(kx, 0.5).clamp(0.0, 1.0), d.f64(ky, 0.5).clamp(0.0, 1.0)]; - let before = c; let t = Tokens::get(ui.ctx()); let zoom = d.str("method").eq_ignore_ascii_case("zoom"); form::caption(ui, "Blur Center"); @@ -404,9 +404,12 @@ fn blur_center(ui: &mut egui::Ui, d: &mut Dialog) { }); }); }); - if c != before { - d.fields.insert(kx.into(), json!(c[0])); - d.fields.insert(ky.into(), json!(c[1])); + // A saved center outside the bounds is drawn at the nearest edge, and the fields hold that + // edge too, so OK sends the center the box shows. + for (key, v) in [(kx, c[0]), (ky, c[1])] { + if d.fields.get(key).and_then(Value::as_f64) != Some(v) { + d.fields.insert(key.into(), json!(v)); + } } } @@ -1502,4 +1505,38 @@ mod tests { "OK applies it" ); } + + /// A Radial Blur whose saved Blur Center lies outside the object's bounds (a document written + /// by hand or by another build) opens with the center at the nearest edge, and OK stores that + /// edge instead of sending the saved value, which `effect.setParams` refuses. + #[test] + fn radial_blur_center_outside_the_bounds_opens_at_the_edge_and_ok_keeps_it() { + let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default()); + app.run("file.new", json!({"width": 200, "height": 200})).unwrap(); + let id = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 50, "height": 50})).unwrap()["id"].as_u64().unwrap(); + app.run("select.all", json!({})).unwrap(); + app.run("effect.apply", json!({"effect": RADIAL_BLUR, "params": {"amount": 20}})).unwrap(); + { + let st = app.session.doc_mut().unwrap(); + let d = std::sync::Arc::make_mut(&mut st.doc); + let fx = &mut d.node_mut(vectorcraft_doc::NodeId(id)).unwrap().appearance.effects[0]; + fx.params["centerX"] = json!(1.5); + fx.params["centerY"] = json!(-0.25); + } + app.run("effect.dialog", json!({"effect": RADIAL_BLUR, "index": 0})).unwrap(); + let ctx = egui::Context::default(); + crate::theme::install_fonts(&ctx); + crate::theme::apply(&ctx, Default::default()); + for k in 0..4 { + let input = egui::RawInput { time: Some(f64::from(k) * 0.05), ..Default::default() }; + let mut out = ctx.run_ui(input, |ui| super::super::show(&mut app, ui.ctx())); + out.textures_delta.clear(); + } + let field = |k: &str| app.ui.dialog.as_ref().unwrap().fields.get(k).and_then(Value::as_f64); + assert_eq!((field("centerX"), field("centerY")), (Some(1.0), Some(0.0)), "the fields hold the center the box shows"); + super::super::confirm(&mut app).unwrap(); + let st = app.session.doc().unwrap(); + let fx = &st.doc.node(vectorcraft_doc::NodeId(id)).unwrap().appearance.effects[0]; + assert_eq!((fx.params["centerX"].as_f64(), fx.params["centerY"].as_f64()), (Some(1.0), Some(0.0)), "OK stores the edge"); + } }