Example #1
0
    def _on_current_feature_changes(self, feature):
        """
        Update the feature panel controls when the current feature VA is modified
        :param feature: (CryoFeature or None) the newly selected current feature
        """
        if self._feature_name_va_connector:
            self._feature_name_va_connector.disconnect()

        if self._feature_status_va_connector:
            self._feature_status_va_connector.disconnect()

        if self._feature_z_va_connector:
            self._feature_z_va_connector.disconnect()

        def enable_feature_ctrls(enable):
            self._panel.cmb_feature_status.Enable(enable)
            self._panel.ctrl_feature_z.Enable(enable)
            self._panel.btn_use_current_z.Enable(enable)
            self._panel.btn_go_to_feature.Enable(enable)

        if not feature:
            enable_feature_ctrls(False)
            self._panel.cmb_features.SetValue("No Feature Selected")
            self._panel.cmb_feature_status.SetValue("Not Selected")
            return
        save_features(self._tab.conf.pj_last_path,
                      self._tab_data_model.main.features)

        enable_feature_ctrls(True)
        # Set feature list with the current feature
        index = self._tab_data_model.main.features.value.index(feature)
        self._panel.cmb_features.SetSelection(index)

        # Disconnect and reconnect the VA connectors to the newly selected feature
        self._feature_name_va_connector = VigilantAttributeConnector(
            feature.name,
            self._panel.cmb_features,
            events=wx.EVT_TEXT_ENTER,
            va_2_ctrl=self._on_feature_name,
            ctrl_2_va=self._on_cmb_feature_name_change,
        )

        self._feature_status_va_connector = VigilantAttributeConnector(
            feature.status,
            self._panel.cmb_feature_status,
            events=wx.EVT_COMBOBOX,
            ctrl_2_va=self._on_cmb_feature_status_change,
            va_2_ctrl=self._on_feature_status)

        # TODO: check, it seems that sometimes the EVT_TEXT_ENTER is first received
        # by the VAC, before the widget itself, which prevents getting the right value.
        self._feature_z_va_connector = VigilantAttributeConnector(
            feature.pos,
            self._panel.ctrl_feature_z,
            events=wx.EVT_TEXT_ENTER,
            ctrl_2_va=self._on_ctrl_feature_z_change,
            va_2_ctrl=self._on_feature_pos)
Example #2
0
 def __init__(self, btn_ctrl, va, _):
     self.btn = btn_ctrl
     self.vac = VigilantAttributeConnector(va,
                                           btn_ctrl,
                                           self._va_to_btn,
                                           self._btn_to_va,
                                           events=wx.EVT_BUTTON)
Example #3
0
    def __init__(self, tab_data, main_frame, tab_prefix):
        """ Binds the step and axis buttons to their appropriate
        Vigilant Attributes in the model.ActuatorGUIData. It only connects the
        buttons which exists with the actuators which exists.

        tab_data (ActuatorGUIData): the data model of the tab
        main_frame: (wx.Frame): the main frame of the GUI
        tab_prefix (string): common prefix of the names of the buttons
        """
        self._tab_data_model = tab_data
        self._main_frame = main_frame
        # Check which widgets and VAs exist. Bind the matching ones.

        # Bind size steps (= sliders)
        self._va_connectors = []
        for an, ss in tab_data.stepsizes.items():
            slider_name = tab_prefix + "slider_" + an
            try:
                slider = getattr(main_frame, slider_name)
            except AttributeError:
                continue

            slider.SetRange(*ss.range)

            vac = VigilantAttributeConnector(ss, slider, events=wx.EVT_SLIDER)
            self._va_connectors.append(vac)
        if not self._va_connectors:
            logging.warning("No slider found for tab %s", tab_prefix)

        # Bind buttons
        self._btns = []
        for actuator, axis in tab_data.axes:
            for suffix, factor in [("m", -1), ("p", 1)]:
                # something like "lens_align_btn_p_mirror_rz"
                btn_name = "%sbtn_%s_%s_%s" % (tab_prefix, suffix, actuator,
                                               axis)
                try:
                    btn = getattr(main_frame, btn_name)
                except AttributeError:
                    logging.debug("No button in GUI found for axis %s", axis)
                    continue

                def btn_action(evt,
                               tab_data=tab_data,
                               actuator=actuator,
                               axis=axis,
                               factor=factor):
                    # Button events don't contain key state, so check ourselves
                    if wx.GetKeyState(wx.WXK_SHIFT):
                        factor /= 10
                    tab_data.step(actuator, axis, factor)

                btn.Bind(wx.EVT_BUTTON, btn_action)
                self._btns.append(btn)

        tab_data.main.is_acquiring.subscribe(self._on_acquisition)
Example #4
0
    def __init__(self, tab_data, main_frame, btn_prefix):
        """ Binds the 'hardware' buttons to their appropriate
        Vigilant Attributes in the model.MainGUIData

        tab_data (MicroscopyGUIData): the data model of the tab
        main_frame: (wx.Frame): the main frame of the GUI
        btn_prefix (string): common prefix of the names of the buttons 
        """
        main_data = tab_data.main

        # Look for which buttons actually exist, and which VAs exist. Bind the
        # fitting ones
        self._callbacks = []
        self._va_connectors = []
        for btn_name, vaname in btn_to_va.items():
            try:
                btn = getattr(main_frame, btn_prefix + btn_name)
            except AttributeError:
                continue

            try:
                va = getattr(main_data, vaname)
            except AttributeError:
                # This microscope is not available
                btn.Hide()
                # TODO: need to update layout?
                continue
            logging.debug("Connecting button %s to %s", btn_name, vaname)

            vac = VigilantAttributeConnector(
                va,
                btn,
                lambda s, btn=btn: btn.SetToggle(s != model.STATE_OFF),
                lambda btn=btn: model.STATE_ON
                if btn.GetToggle() else model.STATE_OFF,
                events=wx.EVT_BUTTON)
            self._va_connectors.append(vac)

        if not self._va_connectors:
            logging.warning("No microscope button found in tab %s", btn_prefix)
Example #5
0
    def __init__(self, parent, orig_tab_data):
        xrcfr_overview_acq.__init__(self, parent)

        self.conf = get_acqui_conf()

        # True when acquisition occurs
        self.acquiring = False
        self.data = None

        # a ProgressiveFuture if the acquisition is going on
        self.acq_future = None
        self._acq_future_connector = None

        self._main_data_model = orig_tab_data.main

        # duplicate the interface, but with only one view
        self._tab_data_model = self.duplicate_tab_data_model(orig_tab_data)

        # The pattern to use for storing each tile file individually
        # None disables storing them
        self.filename_tiles = create_filename(self.conf.last_path, "{datelng}-{timelng}-overview",
                                              ".ome.tiff")

        # Create a new settings controller for the acquisition dialog
        self._settings_controller = LocalizationSettingsController(
            self,
            self._tab_data_model,
            highlight_change=True  # also adds a "Reset" context menu
        )

        self.zsteps = model.IntContinuous(1, range=(1, 51))
        self._zsteps_vac = VigilantAttributeConnector(self.zsteps, self.zstack_steps, events=wx.EVT_SLIDER)

        orig_view = orig_tab_data.focussedView.value
        self._view = self._tab_data_model.focussedView.value

        self.streambar_controller = StreamBarController(self._tab_data_model,
                                                        self.pnl_secom_streams,
                                                        static=True,
                                                        ignore_view=True)
        # The streams currently displayed are the one visible
        self.add_streams()

        # The list of streams ready for acquisition (just used as a cache)
        self._acq_streams = {}

        # Compute the preset values for each preset
        self._orig_entries = get_global_settings_entries(self._settings_controller)
        self._orig_settings = preset_as_is(self._orig_entries)
        for sc in self.streambar_controller.stream_controllers:
            self._orig_entries += get_local_settings_entries(sc)

        self.start_listening_to_va()

        # make sure the view displays the same thing as the one we are
        # duplicating
        self._view.view_pos.value = orig_view.view_pos.value
        self._view.mpp.value = orig_view.mpp.value
        self._view.merge_ratio.value = orig_view.merge_ratio.value

        # attach the view to the viewport
        self.pnl_view_acq.canvas.fit_view_to_next_image = False
        self.pnl_view_acq.setView(self._view, self._tab_data_model)

        self.Bind(wx.EVT_CHAR_HOOK, self.on_key)

        self.btn_cancel.Bind(wx.EVT_BUTTON, self.on_close)
        self.btn_secom_acquire.Bind(wx.EVT_BUTTON, self.on_acquire)
        self.Bind(wx.EVT_CLOSE, self.on_close)
        # on_streams_changed is compatible because it doesn't use the args

        # To update the estimated time when streams are removed/added
        self._view.stream_tree.flat.subscribe(self.on_streams_changed)

        # Set parameters for tiled acq
        self.overlap = 0.2
        try:
            # Use the stage range, which can be overridden by the MD_POS_ACTIVE_RANGE,
            # which can be overridden by MD_OVERVIEW_RANGE.
            # Note: this last one might be temporary, until we have a RoA tool provided in the GUI.
            stage_rng = {
                "x": self._main_data_model.stage.axes["x"].range,
                "y": self._main_data_model.stage.axes["y"].range
            }

            stage_md = self._main_data_model.stage.getMetadata()
            if model.MD_POS_ACTIVE_RANGE in stage_md:
                stage_rng.update(stage_md[model.MD_POS_ACTIVE_RANGE])
            if model.MD_OVERVIEW_RANGE in stage_md:
                stage_rng.update(stage_md[model.MD_OVERVIEW_RANGE])

            # left, bottom, right, top
            self.area = (stage_rng["x"][0], stage_rng["y"][0], stage_rng["x"][1], stage_rng["y"][1])
        except (KeyError, IndexError):
            raise ValueError("Failed to find stage.MD_POS_ACTIVE_RANGE with x and y range")

        # Note: It should never be possible to reach here with no streams
        streams = self.get_acq_streams()
        for s in streams:
            self._view.addStream(s)

        self.update_acquisition_time()
Example #6
0
    def __init__(self, parent, orig_tab_data):
        xrcfr_overview_acq.__init__(self, parent)

        self.conf = get_acqui_conf()

        # True when acquisition occurs
        self.acquiring = False
        self.data = None

        # a ProgressiveFuture if the acquisition is going on
        self.acq_future = None
        self._acq_future_connector = None

        self._main_data_model = orig_tab_data.main

        # duplicate the interface, but with only one view
        self._tab_data_model = self.duplicate_tab_data_model(orig_tab_data)

        # Store the final image as {datelng}-{timelng}-overview
        # The pattern to store them in a sub folder, with the name xxxx-overview-tiles/xxx-overview-NxM.ome.tiff
        # The pattern to use for storing each tile file individually
        # None disables storing them
        save_dir = self.conf.last_path
        if isinstance(orig_tab_data, guimodel.CryoGUIData):
            save_dir = self.conf.pj_last_path
        self.filename = create_filename(save_dir,
                                        "{datelng}-{timelng}-overview",
                                        ".ome.tiff")
        assert self.filename.endswith(".ome.tiff")
        dirname, basename = os.path.split(self.filename)
        tiles_dir = os.path.join(dirname,
                                 basename[:-len(".ome.tiff")] + "-tiles")
        self.filename_tiles = os.path.join(tiles_dir, basename)

        # Create a new settings controller for the acquisition dialog
        self._settings_controller = LocalizationSettingsController(
            self,
            self._tab_data_model,
        )

        self.zsteps = model.IntContinuous(1, range=(1, 51))
        # The depth of field is an indication of how far the focus needs to move
        # to see the current in-focus position out-of-focus. So it's a good default
        # value for the zstep size. We use 2x to "really" see something else.
        # Typically, it's about 1 µm.
        dof = self._main_data_model.ccd.depthOfField.value
        self.zstep_size = model.FloatContinuous(2 * dof,
                                                range=(1e-9, 100e-6),
                                                unit="m")
        self._zstep_size_vac = VigilantAttributeConnector(
            self.zstep_size, self.zstep_size_ctrl, events=wx.EVT_COMMAND_ENTER)

        self.tiles_nx = model.IntContinuous(5, range=(1, 1000))
        self.tiles_ny = model.IntContinuous(5, range=(1, 1000))
        self._zsteps_vac = VigilantAttributeConnector(self.zsteps,
                                                      self.zstack_steps,
                                                      events=wx.EVT_SLIDER)
        self._tiles_n_vacx = VigilantAttributeConnector(
            self.tiles_nx, self.tiles_number_x, events=wx.EVT_COMMAND_ENTER)
        self._tiles_n_vacy = VigilantAttributeConnector(
            self.tiles_ny, self.tiles_number_y, events=wx.EVT_COMMAND_ENTER)

        self.area = None  # None or 4 floats: left, top, right, bottom positions of the acquisition area (in m)

        orig_view = orig_tab_data.focussedView.value
        self._view = self._tab_data_model.focussedView.value

        self.streambar_controller = StreamBarController(self._tab_data_model,
                                                        self.pnl_secom_streams,
                                                        static=True,
                                                        ignore_view=True)
        # The streams currently displayed are the one visible
        self.add_streams()

        # The list of streams ready for acquisition (just used as a cache)
        self._acq_streams = {}

        # Find every setting, and listen to it
        self._orig_entries = get_global_settings_entries(
            self._settings_controller)
        for sc in self.streambar_controller.stream_controllers:
            self._orig_entries += get_local_settings_entries(sc)

        self.start_listening_to_va()

        # make sure the view displays the same thing as the one we are
        # duplicating
        self._view.view_pos.value = orig_view.view_pos.value
        self._view.mpp.value = orig_view.mpp.value
        self._view.merge_ratio.value = orig_view.merge_ratio.value

        # attach the view to the viewport
        self.pnl_view_acq.canvas.fit_view_to_next_image = False
        self.pnl_view_acq.setView(self._view, self._tab_data_model)

        self.Bind(wx.EVT_CHAR_HOOK, self.on_key)

        self.btn_cancel.Bind(wx.EVT_BUTTON, self.on_close)
        self.btn_secom_acquire.Bind(wx.EVT_BUTTON, self.on_acquire)
        self.Bind(wx.EVT_CLOSE, self.on_close)

        # Set parameters for tiled acq
        self.overlap = 0.2
        try:
            # Use the stage range, which can be overridden by the MD_POS_ACTIVE_RANGE.
            # Note: this last one might be temporary, until we have a RoA tool provided in the GUI.
            self._tiling_rng = {
                "x": self._main_data_model.stage.axes["x"].range,
                "y": self._main_data_model.stage.axes["y"].range
            }

            stage_md = self._main_data_model.stage.getMetadata()
            if model.MD_POS_ACTIVE_RANGE in stage_md:
                self._tiling_rng.update(stage_md[model.MD_POS_ACTIVE_RANGE])
        except (KeyError, IndexError):
            raise ValueError(
                "Failed to find stage.MD_POS_ACTIVE_RANGE with x and y range")

        # Note: It should never be possible to reach here with no streams
        streams = self.get_acq_streams()
        for s in streams:
            self._view.addStream(s)

        # To update the estimated time & area when streams are removed/added
        self._view.stream_tree.flat.subscribe(self.on_streams_changed,
                                              init=True)
Example #7
0
    def __init__(self, tab_data, tab_panel, tab_prefix):
        """ Binds the step and axis buttons to their appropriate
        Vigilant Attributes in the model.ActuatorGUIData. It only connects the
        buttons which exists with the actuators which exists.

        tab_data (ActuatorGUIData): the data model of the tab
        tab_panel: (wx.Frame): the main frame of the GUI
        tab_prefix (string): common prefix of the names of the buttons
        """
        self._tab_data_model = tab_data
        self._tab_panel = tab_panel
        # Check which widgets and VAs exist. Bind the matching ones.

        # Bind size steps (= sliders)
        self._va_connectors = []
        for an, ss in tab_data.stepsizes.items():
            slider_name = tab_prefix + "slider_" + an
            try:
                slider = getattr(tab_panel, slider_name)
            except AttributeError:
                continue

            slider.SetRange(*ss.range)

            vac = VigilantAttributeConnector(ss, slider, events=wx.EVT_SLIDER)
            self._va_connectors.append(vac)
        if not self._va_connectors:
            logging.warning("No slider found for tab %s", tab_prefix)

        # Bind buttons
        self._btns = []
        for actuator, axis in tab_data.axes:
            for suffix, factor in [("m", -1), ("p", 1)]:
                # something like "lens_align_btn_p_mirror_rz"
                btn_name = "%sbtn_%s_%s_%s" % (tab_prefix, suffix, actuator,
                                               axis)
                try:
                    btn = getattr(tab_panel, btn_name)
                except AttributeError:
                    logging.debug("No button in GUI found for axis %s", axis)
                    continue

                def btn_action(evt,
                               tab_data=tab_data,
                               actuator=actuator,
                               axis=axis,
                               factor=factor):
                    # Button events don't contain key state, so check ourselves
                    if wx.GetKeyState(wx.WXK_SHIFT):
                        factor /= 10
                    tab_data.step(actuator, axis, factor)

                btn.Bind(wx.EVT_BUTTON, btn_action)
                self._btns.append(btn)

        # On SECOM, show the right aligner panel (X/Y or A/B)
        if ("aligner", "x") in tab_data.axes:
            tab_panel.pnl_xy_align.Show()
        if ("aligner", "a") in tab_data.axes:
            tab_panel.pnl_ab_align.Show()

        # On SPARC, show the Yaw/Pitch only if available
        if hasattr(tab_panel, 'pnl_sparc_rot'):
            showrot = (("mirror", "ry") in tab_data.axes
                       or ("mirror", "rz") in tab_data.axes)
            tab_panel.pnl_sparc_rot.Show(showrot)

        # On SPARC, show the fiber aligner only if needed
        if hasattr(tab_panel, 'pnl_fibaligner'):
            showfib = ("fibaligner", "x") in tab_data.axes
            tab_panel.pnl_fibaligner.Show(showfib)

        tab_data.main.is_acquiring.subscribe(self._on_acquisition)