Save as mesh: one dialog for STL and 3MF, with Send to slicer (#1272)

One docked Save as mesh dialog replaces Export STL / 3MF / 3MF with face tags, with an optional Send to slicer that lists the slicers installed on this machine. Engine: file.save_mesh and file.slicers; the Convert Mesh dialog goes (mesh.convert and the MeshConvert feature stay, so existing designs open). Strings in all catalogs; screenshots in the PR. Checked on main + this branch: cargo check --workspace, the engine slicer/mesh/file tests, the UI catalog and menu tests and scenario s14 (the one local colour-token failure is epaint's TexturesDelta panic, which main shows on this machine too).
This commit is contained in:
froglemonade2 authored and GitHub committed 2026-10-15 03:51:28 -04:00
1 parent 3e13eb6392
commit 0872eb959a
28 files changed
+1483 -100

No files matched your search

+36
View File
@@ -127,3 +127,39 @@ fn stl_export_is_closed_where_faces_meet() {
}
}
}
#[test]
fn save_mesh_rejects_unknown_format_and_slicer_without_writing() {
let mut s = imported_box();
let path = std::env::temp_dir().join(format!("solvecraft-save-mesh-{}.stl", std::process::id()));
let _ = std::fs::remove_file(&path);
for params in [json!({"path":path,"format":"nope"}), json!({"path":path,"slicer":"no such slicer anywhere"})] {
assert!(s.execute("file.save_mesh", &params).is_err());
assert!(!path.exists());
}
}
#[test]
fn save_mesh_writes_stl_and_3mf() {
let mut s = imported_box();
let dir = std::env::temp_dir();
for (ext, format) in [("stl", None), ("3mf", None), ("dat", Some("3mf"))] {
let path = dir.join(format!("solvecraft-save-mesh-{}.{ext}", std::process::id()));
let mut params = json!({"path": path});
if let Some(f) = format {
params["format"] = json!(f);
}
s.execute("file.save_mesh", &params).unwrap();
let bytes = std::fs::read(&path).unwrap();
// A 3MF file is a zip archive; a binary STL starts with its 80-byte header.
assert_eq!(bytes.starts_with(b"PK"), ext == "3mf" || format == Some("3mf"), "{ext}");
std::fs::remove_file(path).unwrap();
}
}
#[test]
fn installed_slicers_are_listed() {
let mut s = imported_box();
let r = s.execute("file.slicers", &json!({})).unwrap();
assert!(r["slicers"].is_array());
}