#1152: Offset Path opens on the values it was last applied with

Object › Path › Offset Path (and `ui.menuDialog` for it) opens on the
offset, joins and miter limit of the last time OK was pressed, as in
Illustrator, instead of 10 pt and Miter every time. The values are kept
with the rest of the remembered dialog options.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic 2026-10-11 16:32:03 +07:00
parent 4eaa5f0b56
commit c7522b7f0c
5 changed files with 35 additions and 5 deletions

File diff suppressed because one or more lines are too long

View File

@ -40,5 +40,12 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
let (id, params) = command(d);
if d.kind == "offsetPath" { form::commit_preview(app, id, params) } else { run_and_close(app, id, params) }
if d.kind != "offsetPath" {
return run_and_close(app, id, params);
}
let r = form::commit_preview(app, id, params)?;
// The fields as the dialog held them, so they show as typed when it opens again.
let kept = ["offset", "joins", "miterLimit"].into_iter().filter_map(|k| Some((k.to_string(), d.fields.get(k)?.clone())));
app.ui.offset_path = Value::Object(kept.collect());
Ok(r)
}

View File

@ -201,3 +201,19 @@ fn offset_path_previews() {
cancel(&mut app);
assert_eq!(count(&app), 1, "rolled back");
}
/// Offset Path opens on the values it was last confirmed with (#1152).
#[test]
fn offset_path_remembers_its_last_values() {
let mut app = app_with_selection();
app.run("select.all", json!({})).unwrap();
crate::menus::invoke(&mut app, "object.path.offsetPath", json!({}));
let d = app.ui.dialog.as_mut().unwrap();
d.fields.insert("offset".into(), json!(-4.5));
d.fields.insert("joins".into(), json!("round"));
confirm(&mut app).unwrap();
assert!(app.ui.dialog.is_none());
crate::menus::invoke(&mut app, "object.path.offsetPath", json!({}));
let d = app.ui.dialog.as_ref().unwrap();
assert_eq!((d.f64("offset", 0.0), d.str("joins"), d.f64("miterLimit", 0.0)), (-4.5, "round".to_string(), 4.0));
}

View File

@ -1331,7 +1331,7 @@ pub fn run_ui_command(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<R
"ui.spotColors" => crate::dialogs::spot_colors::open(app),
"ui.menuDialog" => match s("command").as_deref() {
Some(c) if crate::dialogs::envelope::opens(c) => crate::dialogs::envelope::open(app, c),
c => match c.and_then(menu_dialog) {
c => match c.and_then(|c| menu_dialog(app, c)) {
Some((kind, fields)) => {
app.ui.dialog = Some(crate::state::Dialog::new(kind, fields));
Ok(Value::Null)
@ -2976,7 +2976,7 @@ fn queried_dialog(id: &str) -> Option<(&'static str, &'static [&'static str])> {
}
/// The dialog (kind, fields) the menu item of command `id` opens, as the reference app's does.
fn menu_dialog(id: &str) -> Option<(&'static str, Value)> {
fn menu_dialog(app: &VectorcraftApp, id: &str) -> Option<(&'static str, Value)> {
Some(match id {
"object.move" => ("move", json!({"dx": "0 pt", "dy": "0 pt"})),
"object.rotate" => ("rotate", json!({"angle": 0})),
@ -2985,6 +2985,8 @@ fn menu_dialog(id: &str) -> Option<(&'static str, Value)> {
"object.reflect" => ("reflect", json!({"axis": "vertical"})),
"object.shear" => ("shear", json!({"angle": 0, "axis": "horizontal"})),
"path.average" => ("average", json!({"axis": "both"})),
// Offset Path opens on the values it was last confirmed with.
"object.path.offsetPath" if app.ui.offset_path.is_object() => ("offsetPath", app.ui.offset_path.clone()),
"object.path.offsetPath" => ("offsetPath", json!({"offset": "10 pt", "joins": "miter", "miterLimit": 4})),
"object.path.simplify" => ("simplify", json!({"tolerance": "1 pt"})),
"object.path.splitIntoGrid" => ("splitIntoGrid", json!({"rows": 2, "columns": 2, "gutter": "12 pt"})),
@ -3041,7 +3043,7 @@ pub fn invoke(app: &mut VectorcraftApp, id: &str, p: Value) {
if waits_for_ime(app, id) {
return;
}
if let Some((kind, fields)) = menu_dialog(id)
if let Some((kind, fields)) = menu_dialog(app, id)
&& p.as_object().is_none_or(|o| o.is_empty())
{
app.ui.dialog = Some(crate::state::Dialog::new(kind, fields));

View File

@ -388,6 +388,10 @@ pub struct UiState {
/// The EPS Options chosen last (`document.exportEps` options; null: never used).
#[serde(default)]
pub eps_options: Value,
/// The Offset Path fields confirmed last (offset, joins, miterLimit; null: never used): its
/// dialog opens on them (#1152).
#[serde(default)]
pub offset_path: Value,
/// The DXF Import Options chosen last (fit, scaleLineweights, center, mergeLayers; null:
/// never used).
#[serde(default)]
@ -639,6 +643,7 @@ impl Default for UiState {
dialog_search: None,
dxf_options: Value::Null,
eps_options: Value::Null,
offset_path: Value::Null,
dxf_import: Value::Null,
home: None,
layers_panel: Default::default(),