Пример #1
0
    def __init__(self,
                 name,
                 groupName,
                 callbacks,
                 wavelength,
                 exposureTime,
                 trigHandler=None,
                 trigLine=None):
        # Note we assume all light sources are eligible for experiments.
        # However there's no associated callbacks for a light source.
        super().__init__(name, groupName, True, callbacks, depot.LIGHT_TOGGLE)
        self.wavelength = float(wavelength or 0)
        self.defaultExposureTime = exposureTime
        self.exposureTime = exposureTime
        # Current enabled state
        self.state = deviceHandler.STATES.disabled
        # Set up trigger handling.
        if trigHandler and trigLine:
            h = trigHandler.registerDigital(self, trigLine)
            self.triggerNow = h.triggerNow
            if 'setExposing' not in callbacks:
                cb = lambda name, state: trigHandler.setDigital(
                    trigLine, state)
                callbacks['setExposing'] = cb
        else:
            self.triggerNow = lambda: None

        # Most lasers use bulb-type triggering. Ensure they're not left on after
        # an abort event.
        if trigHandler and trigLine:
            onAbort = lambda *args: trigHandler.setDigital(trigLine, False)
            events.subscribe(events.USER_ABORT, onAbort)
Пример #2
0
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, title = "Camera views",
                          style=wx.FRAME_NO_TASKBAR | wx.CAPTION)
        
        self.numCameras = len(depot.getHandlersOfType(depot.CAMERA))

        self.panel = wx.Panel(self)

        # Make a 2xN grid of camera canvases, with menus above for selecting
        # which camera to use in that location.
        self.sizer = wx.FlexGridSizer(2, 5, 5)
        ## List of ViewPanels we contain.
        self.views = []
        for i in range(self.numCameras):
            view = viewPanel.ViewPanel(self.panel)
            self.views.append(view)

        self.SetPosition((675, 280))

        events.subscribe(events.CAMERA_ENABLE, self.onCameraEnableEvent)
        events.subscribe("image pixel info", self.onImagePixelInfo)
        cockpit.gui.keyboard.setKeyboardHandlers(self)

        self.Bind(wx.EVT_CLOSE, self.onClose)

        self.resetGrid()
        self.SetDropTarget(cockpit.gui.viewFileDropTarget.ViewFileDropTarget(self))
Пример #3
0
    def __init__(self, name, config):
        super().__init__(name, config)
        ## Connection to the XYZ stage controller (serial.Serial instance)
        self.xyzConnection = None
        ## Lock around sending commands to the XYZ stage controller.
        self.xyzLock = threading.Lock()
        ## Cached copy of the stage's position. Initialized to an impossible
        # value; this will be modified in initialize.
        self.xyzPositionCache = (10 ** 100, 10 ** 100, 10 ** 100)
        ## Target positions for movement in X, Y and Z, or None if that ch is 
        # not moving.
        self.xyzMotionTargets = [None, None, None]

        ## If there is a config section for the smaractMCS2, grab the config and
        # subscribe to events.
        try :
            limitString = config.get('softlimits')
            parsed = re.search(LIMITS_PAT, limitString)
            if not parsed:
                # Could not parse config entry.
                raise Exception('Bad config: smaractMCS2XYZ Limits.')
                # No transform tuple
            else:
                lstr = parsed.groupdict()['limits']
                self.softlimits=eval(lstr)
        except:
            print ("No softlimits section setting default limits")
            self.softlimits = ((-15000, -15000, -15000), (15000, 15000, 15000))

        events.subscribe(events.USER_ABORT, self.onAbort)
Пример #4
0
    def __init__(self, name, config={}):
        super().__init__(name, config)
        ## Connection to the XY stage controller (serial.Serial instance).
        self._proxy = Pyro4.Proxy(config.get('uri'))
        ## Lock around sending commands to the XY stage controller.
        self.xyLock = threading.Lock()
        ## Cached copy of the stage's position.
        self.positionCache = (None, None)
        ## Target positions for movement in X and Y.
        self.motionTargets = [None, None]
        ## Flag to show that sendPositionUpdates is running.
        self.sendingPositionUpdates = False
        ## Status dict updated by remote.
        self.status = {}
        ## Keys for status items that should be logged
        self.logger = valueLogger.ValueLogger(
            name, keys=list(map('t_'.__add__, self._temperature_names)))
        try:
            xlim = self._proxy.get_value_limits('MotorSetpointX')
            ylim = self._proxy.get_value_limits('MotorSetpointY')
        except:
            xlim, ylim = zip(*DEFAULT_LIMITS)
        # _proxy may return (0,0) if it can't query the hardware.
        if not any(xlim):
            xlim, _ = zip(*DEFAULT_LIMITS)
        if not any(ylim):
            _, ylim = zip(*DEFAULT_LIMITS)
        self.hardlimits = tuple(zip(xlim, ylim))
        self.softlimits = self.hardlimits

        events.subscribe(events.USER_ABORT, self.onAbort)
 def makeUI(self, parent):
     # TODO - this should probably live in a base deviceHandler.
     self.panel = wx.Panel(parent)
     sizer = wx.BoxSizer(wx.VERTICAL)
     # Readout mode control
     sizer.Add(wx.StaticText(self.panel, label="Readout mode"))
     modeButton = wx.Choice(self.panel, choices=self._modenames)
     self.updateModeButton(modeButton)
     sizer.Add(modeButton, flag=wx.EXPAND)
     events.subscribe(events.SETTINGS_CHANGED % self,
                      lambda: self.updateModeButton(modeButton))
     modeButton.Bind(wx.EVT_CHOICE,
                     lambda evt: self.setReadoutMode(evt.GetSelection()))
     sizer.AddSpacer(4)
     # Gain control
     sizer.Add(wx.StaticText(self.panel, label="Gain"))
     gainButton = wx.Button(self.panel,
                            label="%s" % self.settings.get('gain', None))
     if 'gain' not in self.settings:
         gainButton.Disable()
     gainButton.Bind(wx.EVT_BUTTON, self.onGainButton)
     sizer.Add(gainButton, flag=wx.EXPAND)
     events.subscribe(
         events.SETTINGS_CHANGED % self, lambda: gainButton.SetLabel(
             "%s" % self.settings.get('gain', None)))
     sizer.AddSpacer(4)
     # Settings button
     adv_button = wx.Button(parent=self.panel, label='Settings')
     adv_button.Bind(wx.EVT_LEFT_UP, self.showSettings)
     sizer.Add(adv_button)
     self.panel.SetSizerAndFit(sizer)
     return self.panel
Пример #6
0
    def __init__(self):
        ## Maps axis to the handlers for that axis, sorted by their range of
        # motion.
        self.axisToHandlers = depot.getSortedStageMovers()

        ## XXX: We have a single index for all axis, even though each
        ## axis may have a different number of stages.  While we don't
        ## refactor this assumption, we just make copies of the movers
        ## with the most precise movement (issues #413 and #415)
        self.n_stages = max([len(s) for s in self.axisToHandlers.values()])
        for axis, stages in self.axisToHandlers.items():
            stages.extend([stages[-1]] * (self.n_stages - len(stages)))

        ## Indicates which stage handler is currently under control.
        self.curHandlerIndex = 0
        ## Maps Site unique IDs to Site instances.
        self.idToSite = {}
        ## Maps handler names to events indicating if those handlers
        # have stopped moving.
        self.nameToStoppedEvent = {}
        events.subscribe("stage mover", self.onMotion)
        events.subscribe("stage stopped", self.onStop)
        ## Device-speficic primitives to draw on the macrostage.
        self.primitives = set()
        for h in depot.getHandlersOfType(depot.STAGE_POSITIONER):
            ps = h.getPrimitives()
            if ps:
                self.primitives.update(ps)
        self.primitives.discard(None)
Пример #7
0
    def __init__(self, name, config):
        super().__init__(name, config)
        self.STAGE_CAL = config.get('cal')  # e.g. 13.750
        self.PICO_CONTROLLER = config.get('ipaddress')  # e.g. 172.16.0.30'
        self.PICO_PORT = config.get('port')  # e.g. 23

        ## Maps the cockpit's axis ordering (0: X, 1: Y, 2: Z) to the
        # XY stage's ordering which is
        #x controller 1, motor 1 - '1>1'
        #y controller 1, motor 2 - '1>2'
        #z controller 2, motor 1 - '2>1'
        #Needs moving to config file!
        self.axisMapper = {0: '1>1', 1: '1>2', 2: '2>1'}

        ## Connection to the Z piezo controller (Pyro4.Proxy of a
        # telnetlib.Telnet instance)
        self.zConnection = None
        ## Lock around sending commands to the Z piezo controller.
        self.zLock = threading.Lock()
        ## Connection to the XY stage controller (serial.Serial instance)
        self.xyConnection = None
        ## Lock around sending commands to the XY stage controller.
        self.xyLock = threading.Lock()
        ## Cached copy of the stage's position. Initialized to an impossible
        # value; this will be modified in initialize.
        self.xyPositionCache = [10**100, 10**100, 7500]

        events.subscribe(events.USER_ABORT, self.onAbort)
Пример #8
0
    def __init__(self, name, config={}):
        super().__init__(name, config)
        try:
            limitString = config.get('softlimits', '')
            parsed = re.search(LIMITS_PAT, limitString)
            if not parsed:
                # Could not parse config entry.
                raise Exception('Bad config: Aerotech Limits.')
                # No transform tuple
            else:
                lstr = parsed.groupdict()['limits']
                self.softlimits = eval(lstr)
        except:
            print("No softlimits section setting default limits")
            self.softlimits = (-30000, 7000)

        # Subscribe to abort events.
        events.subscribe(events.USER_ABORT, self.onAbort)
        # The cockpit axis does this stage moves along.
        self.axis = int(config.get('axis', 2))
        # Socket used to communicate with controller.
        self.socket = None
        # Last known position (microns)
        self.position = None
        # Axis acceleration (mm / s^2)
        self.acceleration = 200
        # Axis maximum speed (mm / s^2)
        self.speed = 20
Пример #9
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        ## Handle of the current camera we're controlling.
        self.curCamera = None
        ## Position of the currently displayed image - only updated on dbl-click.
        self.imagePos = None

        columnSizer = wx.BoxSizer(wx.VERTICAL)
        ## Clickable text box showing the name of the currently-selected
        # camera.
        self.selector = wx.StaticText(self,
                                      style=wx.RAISED_BORDER | wx.ALIGN_CENTRE
                                      | wx.ST_NO_AUTORESIZE,
                                      size=(VIEW_WIDTH, 30))
        self.selector.Bind(wx.EVT_LEFT_DOWN, self.onSelector)
        self.selector.SetDoubleBuffered(True)

        columnSizer.Add(self.selector, 0)

        ## Panel for holding our canvas.
        self.canvasPanel = wx.Panel(self)
        self.canvasPanel.SetMinSize((VIEW_WIDTH, VIEW_HEIGHT))
        columnSizer.Add(self.canvasPanel)

        self.SetSizerAndFit(columnSizer)

        ## Canvas we paint the camera's view onto. Created when we connect a
        # camera, and destroyed after.
        self.canvas = None

        self.disable()

        events.subscribe("filter change", self.onFilterChange)
        self.Bind(wx.EVT_LEFT_DCLICK, self.onMouse)
Пример #10
0
 def __init__(self, name, groupName, callbacks, dlines=None, alines=None):
     # \param name: handler name
     # \param groupname: handler and device group name
     # \param callbacks: callbacks, as above
     # \param dlines: optional, number of digital lines
     # \param alines: optional, number of analogue lines
     # Note that even though this device is directly involved in running
     # experiments, it is never itself a part of an experiment, so 
     # we pass False for isEligibleForExperiments here.
     super().__init__(name, groupName, False, callbacks, depot.EXECUTOR)
     # Base class contains empty dicts used by mixins so that methods like
     # getNumRunnableLines can be implemented here for all mixin combos. This
     # works just great, but is probably a horrible abuse of OOP. It might be
     # cleaner to have a single list of clients.
     self.digitalClients = {}
     self.analogClients = {}
     # Number of digital and analogue lines.
     self._dlines = dlines
     self._alines = alines
     if not isinstance(self, DigitalMixin):
         self.registerDigital = self._raiseNoDigitalException
         self.getDigital = self._raiseNoDigitalException
         self.setDigital = self._raiseNoDigitalException
         self.readDigital = self._raiseNoDigitalException
         self.writeDigital = self._raiseNoDigitalException
         self.triggerDigital = self._raiseNoDigitalException
     if not isinstance(self, AnalogMixin):
         self.registerAnalog = self._raiseNoAnalogException
         self.setAnalog = self._raiseNoAnalogException
         self.getAnalog = self._raiseNoAnalogException
         self.setAnalogClient = self._raiseNoAnalogException
         self.getAnalogClient = self._raiseNoAnalogException
     events.subscribe(events.PREPARE_FOR_EXPERIMENT, self.onPrepareForExperiment)
     events.subscribe(events.CLEANUP_AFTER_EXPERIMENT, self.cleanupAfterExperiment)
Пример #11
0
    def __init__(self,
                 name,
                 groupName,
                 callbacks,
                 wavelength,
                 minPower,
                 maxPower,
                 curPower,
                 isEnabled=True,
                 units='mW'):
        # Validation:
        required = set(['getPower', 'setPower'])
        missing = required.difference(callbacks)
        if missing:
            e = Exception('%s %s missing callbacks: %s.' %
                          (self.__class__.__name__, name, ' '.join(missing)))
            raise e

        super().__init__(name, groupName, False, callbacks, depot.LIGHT_POWER)
        LightPowerHandler._instances.append(self)
        self.wavelength = wavelength
        self.minPower = minPower
        self.maxPower = maxPower
        self.lastPower = curPower
        self.powerSetPoint = None
        self.isEnabled = isEnabled
        self.units = units

        events.subscribe('save exposure settings', self.onSaveSettings)
        events.subscribe('load exposure settings', self.onLoadSettings)
Пример #12
0
    def __init__(self,
                 name,
                 groupName,
                 callbacks,
                 exposureMode,
                 trigHandler=None,
                 trigLine=None):
        # Note we assume that cameras are eligible for experiments.
        deviceHandler.DeviceHandler.__init__(self, name, groupName, True,
                                             callbacks, depot.CAMERA)
        ## True if the camera is currently receiving images.
        self.isEnabled = False
        self._exposureMode = exposureMode
        self.wavelength = None
        self.dye = None
        # Set up trigger handling.
        if trigHandler and trigLine:
            h = trigHandler.registerDigital(self, trigLine)
            self.triggerNow = h.triggerNow
        else:
            softTrigger = self.callbacks.get('softTrigger', None)
            self.triggerNow = lambda: softTrigger
            if softTrigger:
                depot.addHandler(
                    cockpit.handlers.imager.ImagerHandler(
                        "%s imager" % name, "imager",
                        {'takeImage': softTrigger}))

        #subscribe to save and load setting calls to enabvle saving and
        #loading of configurations.
        events.subscribe('save exposure settings', self.onSaveSettings)
        events.subscribe('load exposure settings', self.onLoadSettings)
Пример #13
0
    def run(self):
        # For debugging purposes
        experiment.lastExperiment = self
        
        self.sanityCheckEnvironment()
        self.prepareHandlers()

        self.cameraToReadoutTime = dict([(c, c.getTimeBetweenExposures(isExact = True)) for c in self.cameras])
        for camera, readTime in self.cameraToReadoutTime.items():
            if type(readTime) is not decimal.Decimal:
                raise RuntimeError("Camera %s did not provide an exact (decimal.Decimal) readout time" % camera.name)

        for camera, func in self.camToFunc.items():
            events.subscribe(events.NEW_IMAGE % camera.name, func)
        for exposureTime in self.exposureTimes:
            if self.shouldAbort:
                break
            self.camToImages = {}
            self.camToNumImagesReceived = {}
            self.camToLock = {}
            for camera in self.cameras:
                # Prepare a memory buffer to store images in.
                width, height = camera.getImageSize()
                self.camToImages[camera] = numpy.zeros((self.numExposures, height, width))
                self.camToNumImagesReceived[camera] = 0
                self.camToLock[camera] = threading.Lock()
                # Indicate any frame transfer cameras for reset at start of
                # table.
                if camera.getExposureMode() == cockpit.handlers.camera.TRIGGER_AFTER:
                    self.cameraToIsReady[camera] = False
                
            self.table = self.generateActions(exposureTime)
            self.table.sort()
            self.examineActions()
            self.table.sort()
            self.table.enforcePositiveTimepoints()
            self.lastMinuteActions()
            self.doneReceivingThread = threading.Thread(target = self.waiter)
            self.doneReceivingThread.start()
            self.execute()
            
            if self.shouldAbort:
                break
            
            # Wait until it's been a short time after the last received image.
            self.doneReceivingThread.join()
            progress = cockpit.gui.progressDialog.ProgressDialog("Processing images", 
                    "Processing images for exposure time %.4f" % exposureTime,
                    parent = None)
            self.processImages(exposureTime)
            progress.Destroy()

        for camera, func in self.camToFunc.items():
            events.unsubscribe(events.NEW_IMAGE % camera.name, func)

        self.save()
        self.showResults()
        self.cleanup()
Пример #14
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        ## Whether or not to draw the mosaic tiles
        self.shouldDrawMosaic = True
        ## True if we're in the processing of changing the soft motion limits.
        self.amSettingSafeties = False
        ## Position the mouse first clicked when setting safeties, or None if
        # we aren't setting safeties.
        self.firstSafetyMousePos = None
        ## Last seen mouse position
        self.lastMousePos = [0, 0]

        primitive_specs = wx.GetApp().Config['stage'].getlines('primitives', [])
        self._primitives = [Primitive.factory(spec) for spec in primitive_specs]

        hardLimits = cockpit.interfaces.stageMover.getHardLimits()
        self.minX, self.maxX = hardLimits[0]
        self.minY, self.maxY = hardLimits[1]
        ## X extent of the stage, in microns.
        stageWidth = self.maxX - self.minX
        ## Y extent of the stage, in microns.
        stageHeight = self.maxY - self.minY
        ## Max of X or Y stage extents.
        self.maxExtent = max(stageWidth, stageHeight)
        ## X and Y view extent.
        if stageHeight > stageWidth:
            self.viewExtent = 1.2 * stageHeight
            self.viewDeltaY = stageHeight * 0.1
        else:
            self.viewExtent = 1.05 * stageWidth
            self.viewDeltaY = stageHeight * 0.05
        # Push out the min and max values a bit to give us some room around
        # the stage to work with. In particular we need space below the display
        # to show our legend.
        self.centreX = ((self.maxX - self.minX) / 2) + self.minX
        self.centreY = ((self.maxY - self.minY) / 2) + self.minY
        self.minX = self.centreX - self.viewExtent / 2
        self.maxX = self.centreX + self.viewExtent / 2
        self.minY = self.centreY - self.viewExtent / 2 - self.viewDeltaY
        self.maxY = self.centreY + self.viewExtent / 2 - self.viewDeltaY

        ## Size of text to draw. I confess I don't really understand how this
        # corresponds to anything, but it seems to work out.
        self.textSize = .004

        self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
        self.Bind(wx.EVT_LEFT_UP, self.OnLeftClick)
        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDoubleClick)
        self.Bind(wx.EVT_RIGHT_UP, self.OnRightClick)
        self.Bind(wx.EVT_RIGHT_DCLICK, self.OnRightDoubleClick)
        # Bind context menu event to None to prevent main window context menu
        # being displayed in preference to our own.
        self.Bind(wx.EVT_CONTEXT_MENU, lambda event: None)
        events.subscribe("soft safety limit", self.onSafetyChange)
        events.subscribe('objective change', self.onObjectiveChange)
        self.SetToolTip(wx.ToolTip("Left double-click to move the stage. " +
                "Right click for gotoXYZ and double-click to toggle displaying of mosaic " +
                "tiles."))
Пример #15
0
 def __init__(self, name="dummy XY stage", config={}):
     super().__init__(name, config)
     # List of 2 doubles indicating our X/Y position.
     self.curPosition = [1000, 1000]
     events.subscribe(events.USER_ABORT, self.onAbort)
     # Is this device in use?
     self.active = False
     self.deviceType = "stage positioner"
     self.axes = [0, 1]
Пример #16
0
    def startCollecting(self):
        for camera in self.cameras:
            def func(data, timestamp, camera=camera):
                return self.onImage(self.cameraToIndex[camera], data, timestamp)
            self.lambdas.append(func)
            events.subscribe(events.NEW_IMAGE % camera.name, func)

            self.minMaxVals.append((float('inf'), float('-inf')))
        events.subscribe(events.USER_ABORT, self.onAbort)
        self.statusThread.start()
Пример #17
0
    def exposureMode(self, triggerType):
        """Set exposure mode.

        If the device set a softTrigger handler, subscribe to "dummy take image"
        if exposureMode is TRIGGER_SOFT, otherwise unsubscribe."""
        self._exposureMode = triggerType
        softTrigger = self.callbacks.get('softTrigger', None)
        events.unsubscribe("dummy take image", softTrigger)
        if softTrigger:
            events.subscribe("dummy take image", softTrigger)
Пример #18
0
 def finalizeInitialization(self):
     if self.excitation:
         self.setExMode(self.excitation[0])
     self.temperatureConnection.connect(self.receiveTemperatureData)
     #        self.setStageMode('Inverted')
     #set default emission path
     #IMD 20170316 comment out as this is a hack for OMXT
     #        self.setDetMode('w/o AO & 209 nm pixel size')
     #Subscribe to objective change to map new detector path to new pixel sizes via fake objective
     events.subscribe('objective change', self.onObjectiveChange)
Пример #19
0
    def __init__(self, parent, size, id=-1, *args, **kwargs):
        super().__init__(parent, id, size=size, *args, **kwargs)

        ## WX context for drawing.
        self.context = wx.glcanvas.GLContext(self)
        ## Whether or not we have done some one-time-only logic.
        self.haveInitedGL = False
        ## Whether or not we should try to draw
        self.shouldDraw = True
        ## Font for drawing text
        try:
            self.font = ftgl.TextureFont(cockpit.gui.FONT_PATH)
            self.font.setFaceSize(18)
        except Exception as e:
            print("Failed to make font:", e)

        ## X values below this are off the canvas. We leave it up to children
        # to fill in proper values for these.
        self.minX = 0
        ## X values above this are off the canvas
        self.maxX = 1000
        ## Y values below this are off the canvas
        self.minY = 0
        ## Y values above this are off the canvas
        self.maxY = 1000

        ## (X, Y, Z) vector describing the stage position as of the last
        # time we drew ourselves. We need this to display motion deltas.
        self.prevStagePosition = numpy.zeros(3)
        ## As above, but for the current position.
        self.curStagePosition = numpy.zeros(3)
        ## Event used to indicate when drawing is done, so we can update
        # the above.
        self.drawEvent = threading.Event()

        ##objective offset info to get correct position and limits
        self.objective = depot.getHandlersOfType(depot.OBJECTIVE)[0]
        self.listObj = list(self.objective.nameToOffset.keys())
        self.listOffsets = list(self.objective.nameToOffset.values())
        self.offset = self.objective.getOffset()

        ## Boolean to just force a redraw.
        self.shouldForceRedraw = False

        ## Thread that ensures we don't spam redisplaying ourselves.
        self.redrawTimerThread = threading.Thread(target=self.refreshWaiter,
                                                  name="macrostage-refresh")
        self.redrawTimerThread.start()

        self.Bind(wx.EVT_PAINT, self.onPaint)
        self.Bind(wx.EVT_SIZE, lambda event: event)
        self.Bind(wx.EVT_ERASE_BACKGROUND,
                  lambda event: event)  # Do nothing, to avoid flashing
        events.subscribe(events.STAGE_POSITION, self.onMotion)
        events.subscribe("stage step index", self.onStepIndexChange)
Пример #20
0
    def __init__(self, device, parent=None, handler=None):
        wx.Frame.__init__(self,
                          parent,
                          wx.ID_ANY,
                          style=wx.FRAME_FLOAT_ON_PARENT)
        self.device = device
        self.SetTitle("%s settings" % device.name)
        self.settings = {}
        self.current = {}
        self.handler = handler
        #self.handler.addListener(self)
        #self.panel = wx.Panel(self, wx.ID_ANY, style=wx.WANTS_CHARS)
        sizer = wx.BoxSizer(wx.VERTICAL)

        self.grid = wx.propgrid.PropertyGrid(
            self, style=wx.propgrid.PG_SPLITTER_AUTO_CENTER)
        self.grid.SetColumnProportion(0, 2)
        self.grid.SetColumnProportion(1, 1)
        self.populateGrid()
        self.Bind(wx.propgrid.EVT_PG_CHANGED, self.onPropertyChange)
        sizer.Add(self.grid, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.ALIGN_TOP)

        sizer.AddSpacer(2)
        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
        #saveButton = wx.Button(self, id=wx.ID_SAVE)
        #saveButton.SetToolTip(wx.ToolTip("Save current settings as defaults."))
        #saveButton.Bind(wx.EVT_BUTTON, self.onSave)
        #buttonSizer.Add(saveButton, 0, wx.ALIGN_RIGHT, 0, 0)

        okButton = wx.Button(self, id=wx.ID_OK)
        okButton.Bind(wx.EVT_BUTTON, self.onClose)
        okButton.SetToolTip(
            wx.ToolTip("Apply settings and close this window."))
        buttonSizer.Add(okButton, 0, wx.ALIGN_RIGHT)

        cancelButton = wx.Button(self, id=wx.ID_CANCEL)
        cancelButton.Bind(wx.EVT_BUTTON, self.onClose)
        cancelButton.SetToolTip(
            wx.ToolTip("Close this window without applying settings."))
        buttonSizer.Add(cancelButton, 0, wx.ALIGN_RIGHT)

        applyButton = wx.Button(self, id=wx.ID_APPLY)
        applyButton.SetToolTip(wx.ToolTip("Apply these settings."))
        applyButton.Bind(wx.EVT_BUTTON,
                         lambda evt: self.device.updateSettings(self.current))
        buttonSizer.Add(applyButton, 0, wx.ALIGN_RIGHT)

        sizer.Add(buttonSizer, 0, wx.ALIGN_CENTER, 0, 0)
        self.SetSizerAndFit(sizer)
        self.SetMinSize((256, -1))
        events.subscribe(events.SETTINGS_CHANGED % self.device,
                         self.updateGrid)
        self.Bind(wx.EVT_SHOW, lambda evt: self.updateGrid())
Пример #21
0
 def toggleSyncViews(self, event=None):
     self.syncViews = not self.syncViews
     if self.syncViews:
         events.subscribe(
             events.SYNCED_VIEW,
             self.setView,
         )
     else:
         events.unsubscribe(
             events.SYNCED_VIEW,
             self.setView,
         )
Пример #22
0
    def __init__(self, name, groupName, isEligibleForExperiments, callbacks,
                 cameras, lights):
        super().__init__(name, groupName, isEligibleForExperiments, callbacks,
                         depot.LIGHT_FILTER)
        self.cameras = cameras or []
        self.lights = lights or []
        self.lastFilter = None

        #subscribe to save and load setting calls to enabvle saving and
        #loading of configurations.
        events.subscribe('save exposure settings', self.onSaveSettings)
        events.subscribe('load exposure settings', self.onLoadSettings)
    def __init__(self, images, title, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.images = images
        self.title = title
        ## Current image/pixel under examination.
        self.curViewIndex = numpy.zeros(5, dtype=numpy.int)

        ## Panel for holding UI widgets.
        self.panel = wx.Panel(self)
        self.panel.SetBackgroundColour(wx.WHITE)

        # Set up our UI -- just a collection of sliders to change the
        # image we show, plus some keyboard shortcuts.
        ## Maps axes to the Sliders for those axes.
        self.axisToSlider = dict()
        sizer = wx.BoxSizer(wx.VERTICAL)
        sliderSizer = wx.BoxSizer(wx.HORIZONTAL)
        for i, label in enumerate(['Wavelength', 'Time', 'Z']):
            if self.images.shape[i] > 1:
                # We need a slider for this dimension.
                sliderSizer.Add(self.makeSlider(i, label))
        sizer.Add(sliderSizer)

        self.canvas = cockpit.gui.imageViewer.viewCanvas.ViewCanvas(
            self.panel,
            size=(self.images.shape[-1], self.images.shape[-2] + 40))
        sizer.Add(self.canvas)
        self.panel.SetSizerAndFit(sizer)
        temp = wx.BoxSizer(wx.VERTICAL)
        temp.Add(self.panel)
        self.SetSizerAndFit(temp)
        self.Show()
        # For some reason, if we don't do this, then the first time we try
        # to access curViewIndex in self.setCurImage we get strange values.
        self.setCurImage()

        events.subscribe('image pixel info', self.onImagePixelInfo)
        self.Bind(wx.EVT_CLOSE, self.onClose)
        accelTable = wx.AcceleratorTable([(wx.ACCEL_NORMAL,
                                           wx.WXK_NUMPAD_MULTIPLY, 1),
                                          (wx.ACCEL_NORMAL, wx.WXK_LEFT, 2),
                                          (wx.ACCEL_NORMAL, wx.WXK_RIGHT, 3),
                                          (wx.ACCEL_NORMAL, wx.WXK_UP, 4),
                                          (wx.ACCEL_NORMAL, wx.WXK_DOWN, 5)])
        self.SetAcceleratorTable(accelTable)
        self.Bind(wx.EVT_MENU, self.onRescale, id=1)
        for id, delta in [(2, (0, -1)), (3, (0, 1)), (4, (-1, 0)),
                          (5, (1, 0))]:
            self.Bind(wx.EVT_MENU,
                      lambda event, delta=delta: self.shiftView(delta),
                      id=id)
Пример #24
0
 def __init__(self,
              name,
              groupName,
              settings=None,
              settingIndex=None,
              callbacks={}):
     super().__init__(name, groupName, False, callbacks, depot.DRAWER)
     self.settings = settings
     self.settingIndex = settingIndex
     ## List of ToggleButtons, one per setting.
     self.buttons = []
     # Last thing to do is update UI to show default selections.
     events.subscribe('cockpit initialization complete', self.changeDrawer)
Пример #25
0
    def __init__(self, name="dummy XY stage", config={}):
        config['primitives'] = \
            "r 12500 6000 3000 3000\n" \
            "c 5000 6000 3000\n"       \
            "c 20000, 6000, 3000\n"

        super(DummyMover, self).__init__(name, config)
        # List of 2 doubles indicating our X/Y position.
        self.curPosition = [1000, 1000]
        events.subscribe('user abort', self.onAbort)
        # Is this device in use?
        self.active = False
        self.deviceType = "stage positioner"
        self.axes = [0, 1]
Пример #26
0
    def __init__(self, name, groupName, nameToPixelSize, nameToTransform, nameToOffset, nameToColour, nameToLensID, curObjective,
            callbacks = {}):
        super().__init__(name, groupName, False, {}, depot.OBJECTIVE)
        self.nameToPixelSize = nameToPixelSize
        self.nameToTransform = nameToTransform
        self.nameToOffset = nameToOffset
        self.nameToColour = nameToColour
        self.nameToLensID = nameToLensID
        self.curObjective = curObjective
        self.callbacks = callbacks
        ## List of ToggleButtons, one per objective.
        self.buttons = []

        events.subscribe('save exposure settings', self.onSaveSettings)
        events.subscribe('load exposure settings', self.onLoadSettings)
Пример #27
0
    def enable(self, camera):
        self.selector.SetLabel(camera.descriptiveName)
        self.selector.SetBackgroundColour(camera.color)
        self.selector.Refresh()
        self.curCamera = camera

        # NB the 512 here is the largest texture size our graphics card can
        # gracefully handle.
        self.canvas = cockpit.gui.imageViewer.viewCanvas.ViewCanvas(
            self.canvasPanel, size=(VIEW_WIDTH, VIEW_HEIGHT))
        self.canvas.SetSize((VIEW_WIDTH, VIEW_HEIGHT))
        self.canvas.resetView()

        # Subscribe to new image events only after canvas is prepared.
        events.subscribe(events.NEW_IMAGE % self.curCamera.name, self.onImage)
Пример #28
0
    def __init__(self):
        ## Maps axis to the handlers for that axis, sorted by their range of
        # motion.
        self.axisToHandlers = depot.getSortedStageMovers()
        if set(self.axisToHandlers.keys()) != {0, 1, 2}:
            raise ValueError('stage mover requires 3 axis: X, Y, and Z')

        # FIXME: we should have sensible defaults.
        self._saved_top = userConfig.getValue('savedTop', default=3010.0)
        self._saved_bottom = userConfig.getValue('savedBottom', default=3000.0)

        ## XXX: We have a single index for all axis, even though each
        ## axis may have a different number of stages.  While we don't
        ## refactor this assumption, we just make copies of the movers
        ## with the most precise movement (issues #413 and #415)
        self.n_stages = max([len(s) for s in self.axisToHandlers.values()])
        for axis, stages in self.axisToHandlers.items():
            stages.extend([stages[-1]] * (self.n_stages - len(stages)))

        ## Indicates which stage handler is currently under control.
        self.curHandlerIndex = 0
        ## Maps Site unique IDs to Site instances.
        self.idToSite = {}

        # Compute the hard motion limits for each axis as the
        # summation of all limits for handlers on that axis.
        hard_limits = [None] * 3
        for axis in range(3):
            lower = 0.0
            upper = 0.0
            # We need set() to avoid duplicated handlers, and we might
            # have duplicated handlers because of the hack to meet
            # cockpit requirements that all axis have the same number
            # of handlers (see comments on issue #413).
            for handler in set(self.axisToHandlers[axis]):
                handler_limits = handler.getHardLimits()
                lower += handler_limits[0]
                upper += handler_limits[1]
            hard_limits[axis] = (lower, upper)
        # Use a tuple to prevent changes to it, and assemble it like
        # this to enable static code analysis.
        self._hard_limits = (hard_limits[0], hard_limits[1], hard_limits[2])

        ## Maps handler names to events indicating if those handlers
        # have stopped moving.
        self.nameToStoppedEvent = {}
        events.subscribe(events.STAGE_MOVER, self.onMotion)
        events.subscribe(events.STAGE_STOPPED, self.onStop)
Пример #29
0
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, title = "Status information",
                style = wx.RESIZE_BORDER | wx.CAPTION | wx.FRAME_NO_TASKBAR)
        self.panel = wx.Panel(self)

        ## Maps status light names to the lights themselves. Each light is
        # a ToggleButton instance.
        self.nameToLight = {}

        events.subscribe('new status light', self.onNewLight)
        events.subscribe('update status light', self.onNewStatus)

        # Some lights that we know we need.
        self.onNewLight('image count', '')
        self.onNewLight('device waiting', '')
        self.Show()
Пример #30
0
    def __init__(self, parent, size, id=-1, *args, **kwargs):
        super().__init__(parent, id, size=size, *args, **kwargs)

        ## WX context for drawing.
        self.context = wx.glcanvas.GLContext(self)
        ## Whether or not we have done some one-time-only logic.
        self.haveInitedGL = False
        ## Whether or not we should try to draw
        self.shouldDraw = True
        ## Font for drawing text
        self.face = cockpit.gui.freetype.Face(18)

        ## X values below this are off the canvas. We leave it up to children
        # to fill in proper values for these.
        self.minX = 0
        ## X values above this are off the canvas
        self.maxX = 1000
        ## Y values below this are off the canvas
        self.minY = 0
        ## Y values above this are off the canvas
        self.maxY = 1000

        ## (X, Y, Z) vector describing the stage position as of the last
        # time we drew ourselves. We need this to display motion deltas.
        self.prevStagePosition = numpy.zeros(3)
        ## As above, but for the current position.
        self.curStagePosition = numpy.zeros(3)
        ## Event used to indicate when drawing is done, so we can update
        # the above.
        self.drawEvent = threading.Event()

        ## Boolean to just force a redraw.
        self.shouldForceRedraw = False

        ## Thread that ensures we don't spam redisplaying ourselves.
        self.redrawTimerThread = threading.Thread(target=self.refreshWaiter,
                                                  name="macrostage-refresh",
                                                  daemon=True)
        self.redrawTimerThread.start()

        self.Bind(wx.EVT_PAINT, self.onPaint)
        self.Bind(wx.EVT_SIZE, lambda event: event)
        self.Bind(wx.EVT_ERASE_BACKGROUND,
                  lambda event: event)  # Do nothing, to avoid flashing
        events.subscribe(events.STAGE_POSITION, self.onMotion)
        events.subscribe("stage step index", self.onStepIndexChange)