Merge #608: Fix #592: file dialogs on Linux no longer stop the window answering

# Conflicts:
#	ROADMAP.md
This commit is contained in:
bflatastic
2026-10-09 05:03:38 +07:00
27 changed files with 536 additions and 75 deletions
@@ -424,11 +424,8 @@ fn destination(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) {
let pick = app.services.pick_folder.is_some();
ui.horizontal(|ui| {
form::text(ui, d, "folder", if pick { 300.0 } else { 334.0 });
if pick
&& widgets::icon_button(ui, "folder-open", tl!("Choose a folder"), false, 26.0).clicked()
&& let Some(f) = app.services.pick_folder.as_mut().and_then(|pick| pick())
{
d.fields.insert("folder".into(), json!(f));
if pick && widgets::icon_button(ui, "folder-open", tl!("Choose a folder"), false, 26.0).clicked() {
crate::picks::folder_field(app, d, "folder");
}
});
form::check(ui, d, "openLocation", tl!("Open Location after Export"));
@@ -145,10 +145,17 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
}
}
}
if let Some(a) = act
&& let Err(e) = run(app, d, a, &preset.name)
{
app.status(e);
if let Some(a) = act {
let r = if matches!(a, Action::Import) {
// Its file dialog, shown off the UI thread, imports into the dialog as it is then.
let current = preset.name.clone();
crate::picks::in_dialog(app, d, move |app, d| run(app, d, Action::Import, &current))
} else {
run(app, d, a, &preset.name)
};
if let Err(e) = r {
app.status(e);
}
}
false
}
@@ -181,7 +188,7 @@ fn run(app: &mut VectorcraftApp, d: &mut Dialog, act: Action, current: &str) ->
return Ok(());
}
let pick = crate::FilePick { filters: vec![("Flattener presets", PRESET_EXTS)], ..Default::default() };
let path = app.services.pick_open.as_mut().and_then(|f| f(&pick)).ok_or("cancelled")?;
let path = crate::picks::open(app, &pick).ok_or("cancelled")?;
let r = app.run("flattener.presets.import", json!({ "path": path }))?;
if let Some(first) = r["imported"].get(0).and_then(Value::as_str) {
select(d, first);
+1 -1
View File
@@ -122,7 +122,7 @@ fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
p if !p.is_empty() => p,
_ => {
let pick = crate::FilePick { filters: vectorcraft_engine::cmd::fileio::place_filters().collect(), ..Default::default() };
app.services.pick_open.as_mut().and_then(|f| f(&pick)).ok_or("cancelled")?
crate::picks::open(app, &pick).ok_or("cancelled")?
}
};
out = app.run("links.relink", json!({ "ids": current["ids"], "path": path }))?;
+2 -1
View File
@@ -315,7 +315,8 @@ pub fn cancel(app: &mut VectorcraftApp) {
/// Apply the open dialog (OK).
pub fn confirm(app: &mut VectorcraftApp) -> DialogResult {
let Some(d) = app.ui.dialog.clone() else { return Err("no dialog open".into()) };
(spec(&d.kind).confirm)(app, &d)
// A file dialog it shows off the UI thread confirms the dialog as it is again.
crate::picks::as_entry(app, || crate::picks::Entry::Confirm(Box::new(d.clone())), |app| (spec(&d.kind).confirm)(app, &d))
}
pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) {
+2 -5
View File
@@ -70,11 +70,8 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
if !downloads(app) {
widgets::label_row(ui, tl!("Location:"), LABEL, |ui| {
form::text(ui, d, "folder", 230.0);
if let Some(pick) = app.services.pick_folder.as_mut()
&& ui.button(tl!("Choose…")).clicked()
&& let Some(f) = pick()
{
d.fields.insert("folder".into(), json!(f));
if app.services.pick_folder.is_some() && ui.button(tl!("Choose…")).clicked() {
crate::picks::folder_field(app, d, "folder");
}
});
ui.add_space(4.0);
+12 -5
View File
@@ -102,10 +102,17 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
details(ui, &t, preset, builtin);
});
});
if let Some(a) = act
&& let Err(e) = run(app, d, a, &preset.name)
{
app.status(e);
if let Some(a) = act {
let r = if matches!(a, Action::Import) {
// Its file dialog, shown off the UI thread, imports into the dialog as it is then.
let current = preset.name.clone();
crate::picks::in_dialog(app, d, move |app, d| run(app, d, Action::Import, &current))
} else {
run(app, d, a, &preset.name)
};
if let Err(e) = r {
app.status(e);
}
}
false
}
@@ -169,7 +176,7 @@ fn run(app: &mut VectorcraftApp, d: &mut Dialog, act: Action, current: &str) ->
return Ok(());
}
let pick = crate::FilePick { filters: vec![("PDF presets", vectorcraft_engine::cmd::pdfcmds::PRESET_EXTS)], ..Default::default() };
let path = app.services.pick_open.as_mut().and_then(|f| f(&pick)).ok_or("cancelled")?;
let path = crate::picks::open(app, &pick).ok_or("cancelled")?;
let r = app.run("pdf.preset.import", json!({ "path": path }))?;
if let Some(first) = r["imported"].get(0).and_then(Value::as_str) {
select(d, first);
@@ -150,10 +150,17 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
});
});
let name = preset.name.clone();
if let Some(a) = act
&& let Err(e) = run(app, d, a, &name)
{
app.status(e);
if let Some(a) = act {
let r = if matches!(a, Action::Import) {
// Its file dialog, shown off the UI thread, imports into the dialog as it is then.
let current = name.clone();
crate::picks::in_dialog(app, d, move |app, d| run(app, d, Action::Import, &current))
} else {
run(app, d, a, &name)
};
if let Err(e) = r {
app.status(e);
}
}
false
}
@@ -187,7 +194,7 @@ pub(super) fn run(app: &mut VectorcraftApp, d: &mut Dialog, act: Action, current
return Ok(());
}
let pick = crate::FilePick { filters: vec![("Perspective grid presets", PRESET_EXTS)], ..Default::default() };
let path = app.services.pick_open.as_mut().and_then(|f| f(&pick)).ok_or("cancelled")?;
let path = crate::picks::open(app, &pick).ok_or("cancelled")?;
let r = app.run("perspective.presets.import", json!({ "path": path }))?;
if let Some(first) = r["imported"].get(0).and_then(Value::as_str) {
select(d, first);
+12 -5
View File
@@ -111,10 +111,17 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
}
});
});
if let Some(a) = act
&& let Err(e) = run(app, d, a, &name)
{
app.status(e);
if let Some(a) = act {
let r = if matches!(a, Action::Import) {
// Its file dialog, shown off the UI thread, imports into the dialog as it is then.
let current = name.clone();
crate::picks::in_dialog(app, d, move |app, d| run(app, d, Action::Import, &current))
} else {
run(app, d, a, &name)
};
if let Err(e) = r {
app.status(e);
}
}
false
}
@@ -149,7 +156,7 @@ pub(super) fn run(app: &mut VectorcraftApp, d: &mut Dialog, act: Action, current
return Ok(());
}
let pick = crate::FilePick { filters: vec![("Print presets", PRESET_EXTS)], ..Default::default() };
let path = app.services.pick_open.as_mut().and_then(|f| f(&pick)).ok_or("cancelled")?;
let path = crate::picks::open(app, &pick).ok_or("cancelled")?;
let r = app.run("print.presets.import", json!({ "path": path }))?;
if let Some(first) = r["imported"].get(0).and_then(Value::as_str) {
select(d, first);