diff --git a/software/control/core/core.py b/software/control/core/core.py index 2f04d2f0..3804fab3 100644 --- a/software/control/core/core.py +++ b/software/control/core/core.py @@ -1601,7 +1601,7 @@ def acquire_at_position(self, region_id, current_path, fov): print(f"Acquiring image: ID={file_ID}, Metadata={metadata}") # laser af characterization mode - if LASER_AF_CHARACTERIZATION_MODE: + if self.microscope.laserAutofocusController.characterization_mode: image = self.microscope.laserAutofocusController.get_image() saving_path = os.path.join(current_path, file_ID + "_laser af camera" + ".bmp") iio.imwrite(saving_path, image) @@ -3748,9 +3748,11 @@ def update_laser_af_settings(self, objective: str, updates: Dict[str, Any]) -> N self.autofocus_configurations[objective] = config.model_copy(update=updates) -class ConfigurationManager: +class ConfigurationManager(QObject): """Main configuration manager that coordinates channel and autofocus configurations.""" + signal_profile_loaded = Signal() + def __init__( self, channel_manager: ChannelConfigurationManager, @@ -3800,6 +3802,8 @@ def load_profile(self, profile_name: str) -> None: if self.laser_af_manager: self.laser_af_manager.load_configurations(objective) + self.signal_profile_loaded.emit() + def create_new_profile(self, profile_name: str) -> None: """Create a new profile using current configurations.""" new_profile_path = self.base_config_path / profile_name @@ -4638,6 +4642,7 @@ def __init__( self.piezo = piezo self.objectiveStore = objectiveStore self.laserAFSettingManager = laserAFSettingManager + self.characterization_mode = LASER_AF_CHARACTERIZATION_MODE self.is_initialized = False @@ -4991,8 +4996,8 @@ def set_reference(self) -> bool: return True - def on_objective_changed(self) -> None: - """Handle objective change event. + def on_settings_changed(self) -> None: + """Handle objective change or profile load event. This method is called when the objective changes. It resets the initialization status and loads the cached configuration for the new objective. diff --git a/software/control/gui_hcs.py b/software/control/gui_hcs.py index 0002c174..0d1484aa 100644 --- a/software/control/gui_hcs.py +++ b/software/control/gui_hcs.py @@ -982,6 +982,11 @@ def makeConnections(self): self.wellSelectionWidget.signal_wellSelected.connect(self.wellplateMultiPointWidget.update_well_coordinates) self.objectivesWidget.signal_objective_changed.connect(self.wellplateMultiPointWidget.update_coordinates) + self.configurationManager.signal_profile_loaded.connect( + lambda: self.liveControlWidget.update_microscope_mode_by_name( + self.liveControlWidget.currentConfiguration.name + ) + ) self.objectivesWidget.signal_objective_changed.connect( lambda: self.liveControlWidget.update_microscope_mode_by_name( self.liveControlWidget.currentConfiguration.name @@ -990,12 +995,13 @@ def makeConnections(self): if SUPPORT_LASER_AUTOFOCUS: - def connect_objective_changed_laser_af(): - self.laserAutofocusController.on_objective_changed() + def slot_settings_changed_laser_af(): + self.laserAutofocusController.on_settings_changed() self.laserAutofocusControlWidget.update_init_state() self.laserAutofocusSettingWidget.update_values() - self.objectivesWidget.signal_objective_changed.connect(connect_objective_changed_laser_af) + self.configurationManager.signal_profile_loaded.connect(slot_settings_changed_laser_af) + self.objectivesWidget.signal_objective_changed.connect(slot_settings_changed_laser_af) self.laserAutofocusSettingWidget.signal_newExposureTime.connect( self.cameraSettingWidget_focus_camera.set_exposure_time ) @@ -1269,6 +1275,16 @@ def onDisplayTabChanged(self, index): if hasattr(current_widget, "viewer"): current_widget.activate() + # Stop focus camera live if not on laser focus tab + if SUPPORT_LASER_AUTOFOCUS: + is_laser_focus_tab = self.imageDisplayTabs.tabText(index) == "Laser-Based Focus" + + if hasattr(self, "dock_wellSelection"): + self.dock_wellSelection.setVisible(not is_laser_focus_tab) + + if not is_laser_focus_tab: + self.laserAutofocusSettingWidget.stop_live() + def onWellplateChanged(self, format_): if isinstance(format_, QVariant): format_ = format_.value() diff --git a/software/control/widgets.py b/software/control/widgets.py index 3e8b0ac4..015e63d8 100644 --- a/software/control/widgets.py +++ b/software/control/widgets.py @@ -373,6 +373,7 @@ def __init__(self, streamHandler, liveController, laserAutofocusController, stre self.spinboxes = {} self.init_ui() + self.update_calibration_label() def init_ui(self): layout = QVBoxLayout() @@ -479,7 +480,7 @@ def init_ui(self): characterization_group = QFrame() characterization_layout = QHBoxLayout() self.characterization_checkbox = QCheckBox("Laser AF Characterization Mode") - self.characterization_checkbox.setChecked(False) + self.characterization_checkbox.setChecked(self.laserAutofocusController.characterization_mode) characterization_layout.addWidget(self.characterization_checkbox) characterization_group.setLayout(characterization_layout) @@ -498,7 +499,7 @@ def init_ui(self): self.analog_gain_spinbox.valueChanged.connect(self.update_analog_gain) self.apply_button.clicked.connect(self.apply_settings) self.run_spot_detection_button.clicked.connect(self.run_spot_detection) - self.characterization_checkbox.stateChanged.connect(self.toggle_characterization_mode) + self.characterization_checkbox.toggled.connect(self.toggle_characterization_mode) def _add_spinbox( self, layout, label: str, property_name: str, min_val: float, max_val: float, decimals: int @@ -530,9 +531,13 @@ def toggle_live(self, pressed): self.btn_live.setText("Start Live") self.run_spot_detection_button.setEnabled(True) + def stop_live(self): + """Used for stopping live when switching to other tabs""" + self.toggle_live(False) + self.btn_live.setChecked(False) + def toggle_characterization_mode(self, state): - global LASER_AF_CHARACTERIZATION_MODE - LASER_AF_CHARACTERIZATION_MODE = bool(state == Qt.Checked) + self.laserAutofocusController.characterization_mode = state def update_exposure_time(self, value): self.signal_newExposureTime.emit(value) @@ -557,6 +562,8 @@ def update_values(self): if index >= 0: self.spot_mode_combo.setCurrentIndex(index) + self.update_calibration_label() + def apply_settings(self): updates = { "laser_af_averaging_n": int(self.spinboxes["laser_af_averaging_n"].value()), @@ -578,7 +585,9 @@ def apply_settings(self): self.laserAutofocusController.set_laser_af_properties(updates) self.laserAutofocusController.initialize_auto() self.signal_apply_settings.emit() + self.update_calibration_label() + def update_calibration_label(self): # Show calibration result # Clear previous calibration label if it exists if hasattr(self, "calibration_label"):