diff --git a/src/aare/gui/new_gui/main_window.py b/src/aare/gui/new_gui/main_window.py index a2ec8d1e..ccd8f0f6 100644 --- a/src/aare/gui/new_gui/main_window.py +++ b/src/aare/gui/new_gui/main_window.py @@ -89,6 +89,10 @@ class MainWindow(QWidget): self._baton_poll.setInterval(1000) self._baton_poll.timeout.connect(self._poll_baton_timeout) + # mounted-sample sync with the backend (status.sample) + self._mounted_db_id = None # what the GUI currently shows mounted + self._last_unmount_id = None # suppress re-adopting a just-unmounted one + # last payloads cached so a live theme rebuild can re-feed the new views self._last_status = None self._last_spreadsheet = None @@ -231,6 +235,7 @@ class MainWindow(QWidget): s = self.state s.mode_changed.connect(self._on_mode_changed) s.mount_requested.connect(self._on_mount_requested) + s.unmount_requested.connect(self._on_unmount_note) s.unmount_requested.connect(self.daq.unmount) self.daq.update.connect(self._on_status) @@ -453,6 +458,26 @@ class MainWindow(QWidget): if self._precondition_ok(): self.daq.fluorimeter_spectrum(req) + def _sync_mounted_from_status(self, s) -> None: + """Reflect the backend's mounted sample (status.sample) in the GUI, so a + restart (or an external mount) doesn't 'forget' a mounted sample.""" + bs = getattr(s, "sample", None) + if bs is None: + self._last_unmount_id = None # unmount confirmed by backend + return + bid = getattr(bs, "db_id", None) + if bid is not None and bid == self._last_unmount_id: + return # don't re-adopt a just-unmounted one + cur = self.state.mount_sample + cur_id = getattr(cur, "db_id", None) if cur is not None else None + if self.state.mount_phase != "mounted" or cur_id != bid: + self._mounted_db_id = bid + self.state.sync_mounted(bs) + + def _on_unmount_note(self) -> None: + self._last_unmount_id = self._mounted_db_id + self._mounted_db_id = None + @Slot(object, bool) def _on_mount_requested(self, sample, reference: bool = False) -> None: reason = preconditions.hutch_blocks_mount(self.manual.last_status) @@ -460,6 +485,8 @@ class MainWindow(QWidget): QMessageBox.critical(self, "Mounting blocked", reason) self.alert.show_message(reason, "error") return + self._mounted_db_id = getattr(sample, "db_id", None) + self._last_unmount_id = None self.daq.mount(sample, reference) def _open_staff_tools(self) -> None: @@ -530,6 +557,7 @@ class MainWindow(QWidget): def _on_status(self, s) -> None: self._last_status = s self._auto_busy_edge(s) + self._sync_mounted_from_status(s) session = getattr(s, "session", None) staff = bool(getattr(session, "staff", False)) if session else False if staff != self._staff: diff --git a/src/aare/gui/new_gui/state.py b/src/aare/gui/new_gui/state.py index 362f25fe..c0641e6f 100644 --- a/src/aare/gui/new_gui/state.py +++ b/src/aare/gui/new_gui/state.py @@ -216,6 +216,18 @@ class AppState(QObject): self.mount_changed.emit() self.pipe_changed.emit() + def sync_mounted(self, sample) -> None: + """Adopt a sample the backend reports as mounted (e.g. on GUI restart). + + Does NOT drive the robot — it only reflects reality. No mount_requested.""" + self._mount_sample = sample + self._manual_mount = False + if self._mount_phase != "mounted": + self._reset_pipe() + self.pipe_changed.emit() + self._mount_phase = "mounted" + self.mount_changed.emit() + def unmount(self) -> None: """mounted -> empty: clear sample. Robot unmount only for DB samples.""" manual = getattr(self, "_manual_mount", False)