feat(export): batch wafer-map PNG export from file list

- BatchExport worker + BatchExportController (threaded, busy flag)
- SourcePanel: Export Maps button → FolderDialog → batch export
  with progress/summary banner (dismissible)
- StreamControlPanel: name single export after loaded CSV + timestamp
This commit is contained in:
jack
2026-07-11 23:53:45 -07:00
parent c26de492d7
commit 7d98759b43
9 changed files with 448 additions and 8 deletions
@@ -0,0 +1,62 @@
from __future__ import annotations
import logging
import threading
from PySide6.QtCore import Property, QObject, Qt, Signal, Slot
from pygui.backend.utils import slot_error_boundary
from pygui.backend.wafer.batch_export import BatchExportResult, export_batch
log = logging.getLogger(__name__)
class BatchExportController(QObject):
busyChanged = Signal()
exportFinished = Signal(str)
_batchFinished = Signal(list)
def __init__(self, parent: QObject | None = None) -> None:
super().__init__(parent)
self._busy = False
self._batchFinished.connect(self._handle_batch_finished, Qt.ConnectionType.QueuedConnection)
@Property(bool, notify=busyChanged)
def busy(self) -> bool:
return self._busy
@Slot("QVariantList", str)
def start(self, file_paths: list, output_dir: str) -> None:
if self._busy:
return
self._busy = True
self.busyChanged.emit()
threading.Thread(
target=self._worker, args=(list(file_paths), output_dir), daemon=True
).start()
def _worker(self, file_paths: list[str], output_dir: str) -> None:
try:
results = export_batch(file_paths, output_dir)
except Exception as exc:
log.exception("Batch export worker crashed: %s", exc)
results = []
self._batchFinished.emit(results)
@Slot(list)
@slot_error_boundary
def _handle_batch_finished(self, results: list[BatchExportResult]) -> None:
try:
total = len(results)
succeeded = sum(1 for r in results if r.success)
failed = total - succeeded
summary = (
f"Exported {succeeded}/{total}{failed} failed"
if failed
else f"Exported {succeeded}/{total}"
)
self.exportFinished.emit(summary)
finally:
self._busy = False
self.busyChanged.emit()