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)
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)