def __init__(self, parent, configKey):
        super().__init__(parent=parent)

        self.configKey = configKey + self._CONFIG_KEY_SUFFIX
        self.allLights = depot.getHandlersOfType(depot.LIGHT_TOGGLE)
        self.settings = self.loadSettings()

        sizer = wx.BoxSizer(wx.VERTICAL)
        rowSizer = wx.BoxSizer(wx.HORIZONTAL)

        text = wx.StaticText(self, -1, "Exposure bleach compensation (%):")
        rowSizer.Add(text, 0, wx.ALL, 5)
        ## Ordered list of bleach compensation percentages.
        self.bleachCompensations, subSizer = guiUtils.makeLightsControls(
            self, [str(l.name) for l in self.allLights],
            self.settings['bleachCompensations'])
        rowSizer.Add(subSizer)
        sizer.Add(rowSizer)
        # Now a row for the collection order.
        rowSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.siCollectionOrder = guiUtils.addLabeledInput(
            self,
            rowSizer,
            label="Collection order",
            control=wx.Choice(self, choices=sorted(COLLECTION_ORDERS.keys())),
            helperString=
            "What order to change the angle, phase, and Z step of the experiment. E.g. for \"Angle, Phase, Z\" Angle will change most slowly and Z will change fastest."
        )
        self.siCollectionOrder.SetSelection(self.settings['siCollectionOrder'])
        sizer.Add(rowSizer)
        self.SetSizerAndFit(sizer)
    def __init__(self,
                 parent,
                 resizeCallback,
                 resetCallback,
                 configKey='singleSiteExperiment'):
        super().__init__(parent,
                         style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER
                         | wx.TAB_TRAVERSAL)
        self.parent = parent

        self.configKey = configKey
        self.resizeCallback = resizeCallback
        self.resetCallback = resetCallback

        ## cockpit.experiment.Experiment subclass instance -- mostly preserved for
        # debugging, so we can examine the state of the experiment.
        self.runner = None

        self.allLights = depot.getHandlersOfType(depot.LIGHT_TOGGLE)
        self.allLights.sort(key=lambda l: l.wavelength)
        self.allCameras = depot.getHandlersOfType(depot.CAMERA)
        self.allCameras.sort(key=lambda c: c.name)

        ## Map of default settings as loaded from config.
        self.settings = self.loadConfig()

        self.SetSizer(wx.BoxSizer(wx.VERTICAL))
        self.sizer = self.GetSizer()

        # Section for settings that are universal to all experiment types.
        universalSizer = wx.FlexGridSizer(2, 3, 5, 5)

        ## Maps experiment description strings to experiment modules.
        self.experimentStringToModule = collections.OrderedDict()
        for module in cockpit.experiment.experimentRegistry.getExperimentModules(
        ):
            self.experimentStringToModule[module.EXPERIMENT_NAME] = module

        self.experimentType = wx.Choice(
            self, choices=list(self.experimentStringToModule.keys()))
        self.experimentType.SetSelection(0)
        guiUtils.addLabeledInput(self,
                                 universalSizer,
                                 label="Experiment type:",
                                 control=self.experimentType)

        self.numReps = guiUtils.addLabeledInput(
            self,
            universalSizer,
            label="Number of reps:",
            defaultValue=self.settings['numReps'])
        self.numReps.SetValidator(guiUtils.INTVALIDATOR)

        self.repDuration = guiUtils.addLabeledInput(
            self,
            universalSizer,
            label="Rep duration (s):",
            defaultValue=self.settings['repDuration'],
            helperString="Amount of time that must pass between the start " +
            "of each rep. Use 0 if you don't want any wait time.")
        self.repDuration.SetValidator(guiUtils.FLOATVALIDATOR)

        self.zPositionMode = wx.Choice(self, choices=Z_POSITION_MODES)
        self.zPositionMode.SetSelection(0)
        guiUtils.addLabeledInput(self,
                                 universalSizer,
                                 label="Z position mode:",
                                 control=self.zPositionMode)

        self.stackHeight = guiUtils.addLabeledInput(
            self,
            universalSizer,
            label=u"Stack height (\u03bcm):",
            defaultValue=self.settings['stackHeight'])
        self.stackHeight.SetValidator(guiUtils.FLOATVALIDATOR)

        self.sliceHeight = guiUtils.addLabeledInput(
            self,
            universalSizer,
            label=u"Slice height (\u03bcm):",
            defaultValue=self.settings['sliceHeight'])
        self.sliceHeight.SetValidator(guiUtils.FLOATVALIDATOR)

        self.sizer.Add(universalSizer, 0, wx.ALL, border=5)

        ## Maps experiment modules to ExperimentUI instances holding the
        # UI for that experiment, if any.
        self.experimentModuleToPanel = {}
        for module in self.experimentStringToModule.values():
            if not hasattr(module, 'ExperimentUI'):
                # This experiment type has no special UI to set up.
                continue
            panel = module.ExperimentUI(self, self.configKey)
            panel.Hide()
            self.sizer.Add(panel)
            self.experimentModuleToPanel[module] = panel
        self.experimentType.Bind(wx.EVT_CHOICE, self.onExperimentTypeChoice)
        self.onExperimentTypeChoice()

        # Section for exposure settings. We allow either setting per-laser
        # exposure times and activating all cameras as a group, or setting
        # them per-laser and per-camera (and activating each camera-laser
        # grouping in sequence).
        exposureSizer = wx.BoxSizer(wx.VERTICAL)

        ## Controls which set of exposure settings we enable.
        self.shouldExposeSimultaneously = wx.CheckBox(
            self, label="Expose all cameras simultaneously")
        exposureSizer.Add(self.shouldExposeSimultaneously, 0, wx.ALL, border=5)
        ## Panel for holding controls for when we expose every camera
        # simultaneously.
        self.simultaneousExposurePanel = wx.Panel(
            self, name="simultaneous exposures")
        simultaneousSizer = wx.BoxSizer(wx.VERTICAL)
        simultaneousSizer.Add(
            wx.StaticText(self.simultaneousExposurePanel, -1,
                          "Exposure times for light sources:"), 0, wx.ALL, 5)

        ## Ordered list of exposure times for simultaneous exposure mode.
        self.lightExposureTimes, timeSizer = guiUtils.makeLightsControls(
            self.simultaneousExposurePanel,
            [str(l.name) for l in self.allLights],
            self.settings['simultaneousExposureTimes'])
        simultaneousSizer.Add(timeSizer)
        useCurrentButton = wx.Button(self.simultaneousExposurePanel, -1,
                                     "Use current settings")
        useCurrentButton.SetToolTip(
            wx.ToolTip(
                "Use the same settings as are currently used to take images with the '+' button"
            ))
        useCurrentButton.Bind(wx.EVT_BUTTON, self.onUseCurrentExposureSettings)
        simultaneousSizer.Add(useCurrentButton)

        self.simultaneousExposurePanel.SetSizerAndFit(simultaneousSizer)
        exposureSizer.Add(self.simultaneousExposurePanel, 0, wx.ALL, border=5)

        ## Panel for when we expose each camera in sequence.
        self.sequencedExposurePanel = wx.Panel(self,
                                               name="sequenced exposures")
        ## Maps a camera handler to an ordered list of exposure times.
        self.cameraToExposureTimes = {}
        sequenceSizer = wx.FlexGridSizer(
            len(self.settings['sequencedExposureSettings']) + 1,
            len(self.settings['sequencedExposureSettings'][0]) + 1, 1, 1)
        for label in [''] + [str(l.name) for l in self.allLights]:
            sequenceSizer.Add(
                wx.StaticText(self.sequencedExposurePanel, -1, label), 0,
                wx.ALIGN_RIGHT | wx.ALL, 5)
        for i, camera in enumerate(self.allCameras):
            sequenceSizer.Add(
                wx.StaticText(self.sequencedExposurePanel, -1,
                              str(camera.name)), 0, wx.TOP | wx.ALIGN_RIGHT, 8)
            times = []
            for (label, defaultVal) in zip(
                [str(l.name) for l in self.allLights],
                    self.settings['sequencedExposureSettings'][i]):
                exposureTime = wx.TextCtrl(self.sequencedExposurePanel,
                                           size=(40, -1),
                                           name="exposure: %s for %s" %
                                           (label, camera.name))
                exposureTime.SetValue(defaultVal)
                # allowEmpty=True lets validator know this control may be empty.
                exposureTime.SetValidator(guiUtils.FLOATVALIDATOR)
                exposureTime.allowEmpty = True
                sequenceSizer.Add(exposureTime, 0, wx.ALL, border=5)
                times.append(exposureTime)
            self.cameraToExposureTimes[camera] = times
        self.sequencedExposurePanel.SetSizerAndFit(sequenceSizer)
        exposureSizer.Add(self.sequencedExposurePanel, 0, wx.ALL, border=5)
        self.sizer.Add(exposureSizer)

        # Toggle which panel is displayed based on the checkbox.
        self.shouldExposeSimultaneously.Bind(wx.EVT_CHECKBOX,
                                             self.onExposureCheckbox)
        self.shouldExposeSimultaneously.SetValue(
            self.settings['shouldExposeSimultaneously'])
        self.onExposureCheckbox()

        self.filepath_panel = FilepathPanel(self)
        self.filepath_panel.SetTemplate(self.settings['filenameTemplate'])
        self.filepath_panel.UpdateFilename()
        self.Sizer.Add(self.filepath_panel, wx.SizerFlags(1).Expand().Border())

        # Save/load experiment settings buttons.
        saveLoadPanel = wx.Panel(self)
        rowSizer = wx.BoxSizer(wx.HORIZONTAL)
        saveButton = wx.Button(saveLoadPanel, -1,
                               "Save experiment settings...")
        saveButton.Bind(wx.EVT_BUTTON, self.onSaveExperiment)
        rowSizer.Add(saveButton, 0, wx.ALL, 5)
        loadButton = wx.Button(saveLoadPanel, -1,
                               "Load experiment settings...")
        loadButton.Bind(wx.EVT_BUTTON, self.onLoadExperiment)
        rowSizer.Add(loadButton, 0, wx.ALL, 5)
        saveLoadPanel.SetSizerAndFit(rowSizer)
        self.sizer.Add(saveLoadPanel, 0, wx.LEFT, 5)

        self.SetSizerAndFit(self.sizer)
Beispiel #3
0
    def __init__(self, parent):
        super().__init__(parent,
                         title="OMX multi-site experiment",
                         style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)

        ## Whether or not we should abort the current experiment.
        self.shouldAbort = False
        events.subscribe(events.USER_ABORT, self.onAbort)

        ## List of all light handlers.
        self.allLights = depot.getHandlersOfType(depot.LIGHT_TOGGLE)
        ## List of booleans indicating which lights were active at the
        # start of the experiment.
        self.activeLights = [None for l in self.allLights]

        ## User's last-used inputs.
        self.settings = cockpit.util.userConfig.getValue(
            'multiSiteExperiment',
            default={
                'numCycles': '10',
                'cycleDuration': '60',
                'delayBeforeStarting': '0',
                'delayBeforeImaging': '0',
                'fileBase': '',
                'shouldCustomizeLightFrequencies': False,
                'shouldOptimizeSiteOrder': True,
                'lightFrequencies': ['1' for l in self.allLights],
            })

        ## Contains self.panel
        self.sizer = wx.BoxSizer(wx.VERTICAL)

        ## Contains all UI widgets.
        self.panel = wx.Panel(self)
        ## Sizer for self.panel.
        self.panelSizer = wx.BoxSizer(wx.VERTICAL)
        ## Sizer for all controls except the start/cancel/reset buttons.
        controlsSizer = wx.BoxSizer(wx.HORIZONTAL)
        ## Sizer for a single column of controls.
        columnSizer = wx.BoxSizer(wx.VERTICAL)
        ## Panel for selecting sites to visit.
        self.sitesPanel = cockpit.gui.dialogs.enumerateSitesPanel.EnumerateSitesPanel(
            self.panel,
            label="Sites to visit:",
            size=(200, -1),
            minSize=CONTROL_SIZE)
        columnSizer.Add(self.sitesPanel)

        self.numCycles = guiUtils.addLabeledInput(
            self.panel,
            columnSizer,
            label="Number of cycles:",
            defaultValue=self.settings['numCycles'],
            size=FIELD_SIZE,
            minSize=CONTROL_SIZE)

        self.cycleDuration = guiUtils.addLabeledInput(
            self.panel,
            columnSizer,
            label="Min cycle duration (s):",
            defaultValue=self.settings['cycleDuration'],
            size=FIELD_SIZE,
            minSize=CONTROL_SIZE,
            helperString=
            "Minimum amount of time to pass between each cycle. If the " +
            "cycle finishes early, then I will wait until this much " +
            "time has passed. You can enter multiple values here " +
            "separated by commas; I will then use each wait time in " +
            "sequence; e.g. \"60,120,180\" means the first " +
            "cycle takes one minute, the second two, the third three, " +
            "the fourth one, the fifth two, and so on.")

        self.delayBeforeStarting = guiUtils.addLabeledInput(
            self.panel,
            columnSizer,
            label="Delay before starting (min):",
            defaultValue=self.settings['delayBeforeStarting'],
            size=FIELD_SIZE,
            minSize=CONTROL_SIZE,
            helperString=
            "Amount of time to wait before starting the experiment. " +
            "This is useful if you have a lengthy period to wait for " +
            "your cells to reach the stage you're interested in, for " +
            "example.")

        self.delayBeforeImaging = guiUtils.addLabeledInput(
            self.panel,
            columnSizer,
            label="Delay before imaging (s):",
            defaultValue=self.settings['delayBeforeImaging'],
            size=FIELD_SIZE,
            minSize=CONTROL_SIZE,
            helperString="Amount of time to wait after moving to a site before "
            + "I start imaging the site. This is mostly useful if " +
            "your stage needs time to stabilize after moving.")

        self.fileBase = guiUtils.addLabeledInput(
            self.panel,
            columnSizer,
            label="Data file base name:",
            defaultValue=self.settings['fileBase'],
            size=FIELD_SIZE,
            minSize=CONTROL_SIZE)

        controlsSizer.Add(columnSizer, 0, wx.ALL, 5)

        columnSizer = wx.BoxSizer(wx.VERTICAL)
        ## We don't necessarily have this option.
        self.shouldPowerDownWhenDone = None
        powerHandlers = depot.getHandlersOfType(depot.POWER_CONTROL)
        if powerHandlers:
            # There are devices that we could potentially turn off at end of
            # experiment.
            self.shouldPowerDownWhenDone = guiUtils.addLabeledInput(
                self.panel,
                columnSizer,
                label="Power off devices when done:",
                control=wx.CheckBox(self.panel),
                labelHeightAdjustment=0,
                border=3,
                flags=wx.ALL,
                helperString=
                "If checked, then at the end of the experiment, I will " +
                "power down all the devices I can.")

        self.shouldOptimizeSiteOrder = guiUtils.addLabeledInput(
            self.panel,
            columnSizer,
            label="Optimize route:",
            defaultValue=self.settings['shouldOptimizeSiteOrder'],
            control=wx.CheckBox(self.panel),
            labelHeightAdjustment=0,
            border=3,
            flags=wx.ALL,
            helperString=
            "If checked, then I will calculate an ordering of the sites " +
            "that will minimize the total time spent in transit; " +
            "otherwise, I will use the order you specify.")

        self.shouldCustomizeLightFrequencies = guiUtils.addLabeledInput(
            self.panel,
            columnSizer,
            label="Customize light frequencies:",
            defaultValue=self.settings['shouldCustomizeLightFrequencies'],
            control=wx.CheckBox(self.panel),
            labelHeightAdjustment=0,
            border=3,
            flags=wx.ALL,
            helperString=
            "This allows you to set up experiments where different " +
            "light sources are enabled for different cycles. If you " +
            "set a frequency of 5 for a given light, for example, " +
            "then that light will only be used for every 5th pass " +
            "(the 1st, 6th, 11th, etc. cycles). You can specify an " +
            "offset, too: \"5 + 1\" would enable the light for the " +
            "2nd, 7th, 12th, etc. cycles.")
        self.shouldCustomizeLightFrequencies.Bind(
            wx.EVT_CHECKBOX, self.onCustomizeLightFrequencies)
        self.lightFrequenciesPanel = wx.Panel(self.panel,
                                              style=wx.BORDER_SUNKEN
                                              | wx.TAB_TRAVERSAL)
        self.lightFrequencies, sizer = guiUtils.makeLightsControls(
            self.lightFrequenciesPanel,
            [str(l.wavelength) for l in self.allLights],
            self.settings['lightFrequencies'])
        self.lightFrequenciesPanel.SetSizerAndFit(sizer)
        self.lightFrequenciesPanel.Show(
            self.settings['shouldCustomizeLightFrequencies'])
        columnSizer.Add(self.lightFrequenciesPanel, 0,
                        wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)

        controlsSizer.Add(columnSizer, 0, wx.ALL, 5)
        self.panelSizer.Add(controlsSizer)

        ## Controls whether or not the scanning experiment's parameters are
        # shown.
        self.showScanButton = wx.Button(self.panel, -1,
                                        "Show experiment settings")
        self.showScanButton.Bind(wx.EVT_BUTTON, self.onShowScanButton)
        self.panelSizer.Add(self.showScanButton, 0, wx.ALIGN_CENTER | wx.TOP,
                            5)
        ## This panel configures the experiment we perform when visiting sites.
        self.experimentPanel = experimentConfigPanel.ExperimentConfigPanel(
            self.panel,
            resizeCallback=self.onExperimentPanelResize,
            resetCallback=self.onExperimentPanelReset,
            configKey='multiSiteExperimentPanel',
            shouldShowFileControls=False)
        self.panelSizer.Add(self.experimentPanel, 0, wx.ALIGN_CENTER | wx.ALL,
                            5)
        self.experimentPanel.Hide()

        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)

        button = wx.Button(self.panel, -1, "Reset")
        button.SetToolTip(
            wx.ToolTip("Reload this window with all default values"))
        button.Bind(wx.EVT_BUTTON, self.onReset)
        buttonSizer.Add(button, 0, wx.ALL, 5)

        buttonSizer.Add((1, 0), 1, wx.EXPAND)

        button = wx.Button(self.panel, wx.ID_CANCEL, "Cancel")
        buttonSizer.Add(button, 0, wx.ALL, 5)

        button = wx.Button(self.panel, wx.ID_OK, "Start")
        button.SetToolTip(wx.ToolTip("Start the experiment"))
        button.Bind(wx.EVT_BUTTON, self.onStart)
        buttonSizer.Add(button, 0, wx.ALL, 5)

        self.panelSizer.Add(buttonSizer, 0, wx.ALL, 5)
        self.panel.SetSizerAndFit(self.panelSizer)
        self.sizer.Add(self.panel)
        self.SetSizerAndFit(self.sizer)