Replace hanging STL dialog with local file picker
This commit is contained in:
+21
-20
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user