feat(wasm): save files from the browser
Wire up save for the web build: - `io::save_to_bytes`: serialize a document to a byte buffer (DXF via write_to_vec, DWG via write_to_writer over a Cursor). - `io::download_web`: browser save dialog → write bytes (triggers a download). - Save and Save As on wasm both go through a new `web_save` helper: serialize the active tab and offer a download (no persistent path or in-app save dialog on the web). Format follows the tab name's extension, defaulting to DWG. Result reported via `WebSaveResult`. Native build + 75 tests unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
1ab892c635
commit
9d378a0533
3 changed files with 108 additions and 17 deletions
|
|
@ -49,6 +49,39 @@ fn format_size(bytes: u64) -> String {
|
|||
}
|
||||
|
||||
impl OpenCADStudio {
|
||||
/// Web save: serialize the active document to bytes and offer a browser
|
||||
/// download. Used for both Save and Save As on wasm (there is no persistent
|
||||
/// path or in-app save dialog). Format follows the tab name's extension,
|
||||
/// defaulting to DWG.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn web_save(&mut self) -> Task<Message> {
|
||||
let i = self.active_tab;
|
||||
self.tabs[i].scene.document.header.user_real1 =
|
||||
self.tabs[i].scene.annotation_scale as f64;
|
||||
let base = self.tabs[i].tab_display_name();
|
||||
let lower = base.to_lowercase();
|
||||
let name = if lower.ends_with(".dwg") || lower.ends_with(".dxf") {
|
||||
base
|
||||
} else {
|
||||
format!("{base}.dwg")
|
||||
};
|
||||
let ext = if name.to_lowercase().ends_with(".dxf") {
|
||||
"dxf"
|
||||
} else {
|
||||
"dwg"
|
||||
};
|
||||
match crate::io::save_to_bytes(&self.tabs[i].scene.document, ext) {
|
||||
Ok(bytes) => {
|
||||
self.tabs[i].dirty = false;
|
||||
Task::perform(crate::io::download_web(name, bytes), Message::WebSaveResult)
|
||||
}
|
||||
Err(e) => {
|
||||
self.command_line.push_error(&format!("Save failed: {e}"));
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, msg: Message) -> Task<Message> {
|
||||
let task = self.update_inner(msg);
|
||||
// After every message, mirror the active command step's prompt so
|
||||
|
|
@ -709,30 +742,56 @@ impl OpenCADStudio {
|
|||
Message::ObjImportPath(None) => Task::none(),
|
||||
|
||||
Message::SaveFile => {
|
||||
let i = self.active_tab;
|
||||
if let Some(path) = &self.tabs[i].current_path {
|
||||
let path = path.clone();
|
||||
self.tabs[i].scene.document.header.user_real1 =
|
||||
self.tabs[i].scene.annotation_scale as f64;
|
||||
match crate::io::save(&self.tabs[i].scene.document, &path) {
|
||||
Ok(()) => {
|
||||
self.command_line
|
||||
.push_output(&format!("Saved: {}", path.display()));
|
||||
self.tabs[i].dirty = false;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
self.web_save()
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let i = self.active_tab;
|
||||
if let Some(path) = &self.tabs[i].current_path {
|
||||
let path = path.clone();
|
||||
self.tabs[i].scene.document.header.user_real1 =
|
||||
self.tabs[i].scene.annotation_scale as f64;
|
||||
match crate::io::save(&self.tabs[i].scene.document, &path) {
|
||||
Ok(()) => {
|
||||
self.command_line
|
||||
.push_output(&format!("Saved: {}", path.display()));
|
||||
self.tabs[i].dirty = false;
|
||||
}
|
||||
Err(e) => self.command_line.push_error(&format!("Save failed: {e}")),
|
||||
}
|
||||
Err(e) => self.command_line.push_error(&format!("Save failed: {e}")),
|
||||
Task::none()
|
||||
} else {
|
||||
self.save_dialog_for_unsaved = false;
|
||||
self.open_save_dialog_window(i)
|
||||
}
|
||||
Task::none()
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
Message::SaveAs => {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
self.web_save()
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let i = self.active_tab;
|
||||
self.save_dialog_for_unsaved = false;
|
||||
self.open_save_dialog_window(i)
|
||||
}
|
||||
}
|
||||
|
||||
Message::SaveAs => {
|
||||
let i = self.active_tab;
|
||||
self.save_dialog_for_unsaved = false;
|
||||
self.open_save_dialog_window(i)
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
Message::WebSaveResult(result) => {
|
||||
match result {
|
||||
Ok(name) => self.command_line.push_output(&format!("Saved: {name}")),
|
||||
Err(e) if e != "Cancelled" => {
|
||||
self.command_line.push_error(&format!("Save failed: {e}"))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::SaveDialogFormatChanged(fmt) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue