diff --git a/crates/ui-egui/src/panels/right.rs b/crates/ui-egui/src/panels/right.rs index 6dde13136..02578c071 100644 --- a/crates/ui-egui/src/panels/right.rs +++ b/crates/ui-egui/src/panels/right.rs @@ -89,12 +89,18 @@ impl FigApp { /// Apply a field edit through any command: `params` builds the command's params from the value. pub fn field_run(&mut self, edit: Option, cmd: &str, params: impl Fn(f64) -> Value) { + self.field_run_named(edit, "Edit", cmd, params); + } + + /// Apply a field edit with a specific undo label for scrubs; commit only on release. + /// Typed edits use `run`; scrub errors are discarded as in `field_run`. + pub(crate) fn field_run_named(&mut self, edit: Option, label: &str, cmd: &str, params: impl Fn(f64) -> Value) { match edit { Some(FieldEdit::Set(v)) => { self.run(cmd, params(v)); } Some(FieldEdit::Scrub(v, done)) => { - let _ = self.session.begin_interaction("Edit"); + let _ = self.session.begin_interaction(label); let _ = self.session.execute(cmd, ¶ms(v)); if done { let _ = self.session.commit_interaction(); diff --git a/crates/ui-egui/src/panels/selection_colors.rs b/crates/ui-egui/src/panels/selection_colors.rs index f6c4e25e8..92fcd941e 100644 --- a/crates/ui-egui/src/panels/selection_colors.rs +++ b/crates/ui-egui/src/panels/selection_colors.rs @@ -157,15 +157,7 @@ pub fn section(app: &mut FigApp, ui: &mut Ui, doc: &Arc, ids: &[NodeId d.remove::(scrub_key); } }); - if scrub { - let _ = app.session.begin_interaction("Opacity"); - let _ = app.session.execute("selection.setPaint", &json!({"targets": group.targets, "paint": paint})); - if done { - let _ = app.session.commit_interaction(); - } - } else { - app.run("selection.setPaint", json!({"targets": group.targets, "paint": paint})); - } + app.field_run_named(Some(edit), "Opacity", "selection.setPaint", |_| json!({"targets": group.targets, "paint": paint})); } widgets::tight_end(ui, |ui| { if linked_name.is_some() { @@ -469,6 +461,7 @@ mod tests { for dx in [-10.0, -20.0, -30.0] { p.frame(vec![Event::PointerMoved(start + vec2(dx, 0.0))]); } + assert!(p.app.session.ds().unwrap().interaction.is_some(), "the scrub commits only on release"); assert!(p.frame(vec![]).iter().any(|(text, _)| text == "70%"), "the live opacity stays visible while scrubbing"); p.frame(vec![Event::PointerButton { pos: start - vec2(30.0, 0.0), @@ -478,6 +471,7 @@ mod tests { }]); assert!(p.app.session.ds().unwrap().interaction.is_none()); assert_eq!(p.app.session.doc().unwrap().node(a).unwrap().fills[0].opacity, 0.7); + assert_eq!(p.app.session.undo_labels(1), ["Opacity"], "the shared helper preserves the scrub's undo label"); p.app.run("edit.undo", json!({})); assert_eq!(p.app.session.doc().unwrap().node(a).unwrap().fills[0].opacity, 1.0); assert_eq!(p.app.session.selection().len(), 2);