#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:
parent
4eaa5f0b56
commit
c7522b7f0c
File diff suppressed because one or more lines are too long
|
|
@ -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> {
|
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
|
||||||
let (id, params) = command(d);
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -201,3 +201,19 @@ fn offset_path_previews() {
|
||||||
cancel(&mut app);
|
cancel(&mut app);
|
||||||
assert_eq!(count(&app), 1, "rolled back");
|
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));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.spotColors" => crate::dialogs::spot_colors::open(app),
|
||||||
"ui.menuDialog" => match s("command").as_deref() {
|
"ui.menuDialog" => match s("command").as_deref() {
|
||||||
Some(c) if crate::dialogs::envelope::opens(c) => crate::dialogs::envelope::open(app, c),
|
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)) => {
|
Some((kind, fields)) => {
|
||||||
app.ui.dialog = Some(crate::state::Dialog::new(kind, fields));
|
app.ui.dialog = Some(crate::state::Dialog::new(kind, fields));
|
||||||
Ok(Value::Null)
|
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.
|
/// 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 {
|
Some(match id {
|
||||||
"object.move" => ("move", json!({"dx": "0 pt", "dy": "0 pt"})),
|
"object.move" => ("move", json!({"dx": "0 pt", "dy": "0 pt"})),
|
||||||
"object.rotate" => ("rotate", json!({"angle": 0})),
|
"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.reflect" => ("reflect", json!({"axis": "vertical"})),
|
||||||
"object.shear" => ("shear", json!({"angle": 0, "axis": "horizontal"})),
|
"object.shear" => ("shear", json!({"angle": 0, "axis": "horizontal"})),
|
||||||
"path.average" => ("average", json!({"axis": "both"})),
|
"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.offsetPath" => ("offsetPath", json!({"offset": "10 pt", "joins": "miter", "miterLimit": 4})),
|
||||||
"object.path.simplify" => ("simplify", json!({"tolerance": "1 pt"})),
|
"object.path.simplify" => ("simplify", json!({"tolerance": "1 pt"})),
|
||||||
"object.path.splitIntoGrid" => ("splitIntoGrid", json!({"rows": 2, "columns": 2, "gutter": "12 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) {
|
if waits_for_ime(app, id) {
|
||||||
return;
|
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())
|
&& p.as_object().is_none_or(|o| o.is_empty())
|
||||||
{
|
{
|
||||||
app.ui.dialog = Some(crate::state::Dialog::new(kind, fields));
|
app.ui.dialog = Some(crate::state::Dialog::new(kind, fields));
|
||||||
|
|
|
||||||
|
|
@ -388,6 +388,10 @@ pub struct UiState {
|
||||||
/// The EPS Options chosen last (`document.exportEps` options; null: never used).
|
/// The EPS Options chosen last (`document.exportEps` options; null: never used).
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub eps_options: Value,
|
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:
|
/// The DXF Import Options chosen last (fit, scaleLineweights, center, mergeLayers; null:
|
||||||
/// never used).
|
/// never used).
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|
@ -639,6 +643,7 @@ impl Default for UiState {
|
||||||
dialog_search: None,
|
dialog_search: None,
|
||||||
dxf_options: Value::Null,
|
dxf_options: Value::Null,
|
||||||
eps_options: Value::Null,
|
eps_options: Value::Null,
|
||||||
|
offset_path: Value::Null,
|
||||||
dxf_import: Value::Null,
|
dxf_import: Value::Null,
|
||||||
home: None,
|
home: None,
|
||||||
layers_panel: Default::default(),
|
layers_panel: Default::default(),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue