Replace hanging STL dialog with local file picker

This commit is contained in:
2026-08-25 22:33:27 +02:00
parent 85ba44281e
commit 411eb6397c
6 changed files with 39 additions and 30 deletions
+21 -20
View File
@@ -35,6 +35,8 @@ class ControlApi:
self.motor_directions: dict[int, int] = {}
self.battery_path = Path(__file__).resolve().parent / "battery_settings.json"
self.model_path = Path(__file__).resolve().parent / "model_settings.json"
self.model_cache = Path(__file__).resolve().parent / "runtime" / "vehicle_model.stl"
self.model_cache_name = Path(__file__).resolve().parent / "runtime" / "vehicle_model_name.txt"
# Leading underscore keeps the native WebView object out of js_api
# serialization. Only the small public methods below are exposed.
self._window = None
@@ -79,29 +81,28 @@ class ControlApi:
self._window.destroy()
return True
def choose_model(self):
if not self._window:
raise RuntimeError("Window is not ready")
selected = self._window.create_file_dialog(
webview.OPEN_DIALOG,
allow_multiple=False,
file_types=("STL mesh (*.stl)", "STEP model (*.step;*.stp)"),
)
if not selected:
return None
path = Path(selected[0])
if path.suffix.lower() in (".step", ".stp"):
raise ValueError(
"STEP is a CAD solid and must be tessellated first. Export it as a binary STL, then load that file."
)
if path.suffix.lower() != ".stl":
def save_model(self, name, data):
safe_name = Path(str(name)).name
if not safe_name.lower().endswith(".stl"):
raise ValueError("Choose an STL mesh")
if path.stat().st_size > 30 * 1024 * 1024:
raise ValueError("The STL is larger than 30 MB; export a lighter mesh")
self.model_path.write_text(json.dumps({"path": str(path)}, indent=2) + "\n", encoding="utf-8")
return self._model_payload(path)
try:
content = base64.b64decode(data, validate=True)
except (ValueError, TypeError) as exc:
raise ValueError("Invalid STL data") from exc
if not content or len(content) > 30 * 1024 * 1024:
raise ValueError("STL must be between 1 byte and 30 MB")
self.model_cache.parent.mkdir(exist_ok=True)
self.model_cache.write_bytes(content)
self.model_cache_name.write_text(safe_name, encoding="utf-8")
return True
def saved_model(self):
try:
if self.model_cache.is_file() and self.model_cache.stat().st_size <= 30 * 1024 * 1024:
name = self.model_cache_name.read_text(encoding="utf-8").strip() or "vehicle_model.stl"
return {"name": name, "data": base64.b64encode(self.model_cache.read_bytes()).decode("ascii")}
except (OSError, ValueError):
pass
try:
path = Path(json.loads(self.model_path.read_text(encoding="utf-8"))["path"])
if path.is_file() and path.suffix.lower() == ".stl" and path.stat().st_size <= 30 * 1024 * 1024: