def __init__(self, parent, overlayList, displayCtx, frame): """Create a ``LightBoxPanel``. :arg parent: A :mod:`wx` parent object. :arg overlayList: A :class:`.OverlayList` instance. :arg displayCtx: A :class:`.DisplayContext` instance. :arg frame: The :class:`.FSLeyesFrame` instance. """ sceneOpts = lightboxopts.LightBoxOpts(self) canvaspanel.CanvasPanel.__init__(self, parent, overlayList, displayCtx, frame, sceneOpts) self.__scrollbar = wx.ScrollBar(self.centrePanel, style=wx.SB_VERTICAL) self.__lbCanvas = lightboxcanvas.WXGLLightBoxCanvas( self.contentPanel, overlayList, displayCtx) lbopts = self.__lbCanvas.opts lbopts.bindProps('pos', displayCtx, 'location') lbopts.bindProps('zax', sceneOpts) lbopts.bindProps('bgColour', sceneOpts) lbopts.bindProps('cursorColour', sceneOpts) lbopts.bindProps('showCursor', sceneOpts) lbopts.bindProps('showGridLines', sceneOpts) lbopts.bindProps('highlightSlice', sceneOpts) lbopts.bindProps('renderMode', sceneOpts) lbopts.bindProps('highDpi', sceneOpts) # Bind these properties the other way around, # so that the sensible values calcualted by # the LBCanvas during its initialisation are # propagated to the LBOpts instance, rather # than the non-sensible default values in the # LBOpts instance. sceneOpts.bindProps('nrows', lbopts) sceneOpts.bindProps('ncols', lbopts) sceneOpts.bindProps('topRow', lbopts) sceneOpts.bindProps('sliceSpacing', lbopts) sceneOpts.bindProps('zrange', lbopts) self.__canvasSizer = wx.BoxSizer(wx.HORIZONTAL) self.contentPanel.SetSizer(self.__canvasSizer) self.__canvasSizer.Add(self.__lbCanvas, flag=wx.EXPAND, proportion=1) self.displayCtx.addListener('selectedOverlay', self.name, self.__selectedOverlayChanged) self.displayCtx.addListener('displaySpace', self.name, self.__radioOrientationChanged) self.displayCtx.addListener('radioOrientation', self.name, self.__radioOrientationChanged) self.overlayList.addListener('overlays', self.name, self.__selectedOverlayChanged) # When any lightbox properties change, # make sure the scrollbar is updated sceneOpts.addListener('ncols', self.name, self.__ncolsChanged) sceneOpts.addListener('nrows', self.name, self.__onLightBoxChange) sceneOpts.addListener('topRow', self.name, self.__onLightBoxChange) sceneOpts.addListener('sliceSpacing', self.name, self.__onLightBoxChange) sceneOpts.addListener('zrange', self.name, self.__onLightBoxChange) sceneOpts.addListener('zax', self.name, self.__onLightBoxChange) sceneOpts.addListener('zoom', self.name, self.__onZoom) # When the scrollbar is moved, # update the canvas display self.__scrollbar.Bind(wx.EVT_SCROLL, self.__onScroll) self.Bind(wx.EVT_SIZE, self.__onResize) sceneOpts.zoom = 750 self.__onLightBoxChange() self.__onZoom() self.__selectedOverlayChanged() self.centrePanelLayout() self.initProfile()
def makeDisplayContext(namespace): """Creates :class:`.OverlayList`, :class:`.DisplayContext``, and :class:`.SceneOpts` instances which represent the scene to be rendered, as described by the arguments in the given ``namespace`` object. """ # Create an overlay list and display context. # The DisplayContext, Display and DisplayOpts # classes are designed to be created in a # parent-child hierarchy. So we need to create # a 'dummy' master display context to make # things work properly. overlayList = fsloverlay.OverlayList() masterDisplayCtx = displaycontext.DisplayContext(overlayList) childDisplayCtx = displaycontext.DisplayContext(overlayList, parent=masterDisplayCtx) # We have to artificially create a ref to the # master display context, otherwise it may get # gc'd arbitrarily. The parent reference in the # child creation above is ultimately stored as # a weakref, so we need to create a real one. childDisplayCtx.masterDisplayCtx = masterDisplayCtx # The handleOverlayArgs function uses the # fsleyes.overlay.loadOverlays function, # which will call these functions as it # goes through the list of overlay to be # loaded. def load(ovl): log.info('Loading overlay {} ...'.format(ovl)) def error(ovl, error): log.info('Error loading overlay {}: '.format(ovl, error)) # Load the overlays specified on the command # line, and configure their display properties parseargs.applyOverlayArgs(namespace, overlayList, masterDisplayCtx, loadFunc=load, errorFunc=error) # Create a SceneOpts instance describing # the scene to be rendered. The parseargs # module assumes that GL canvases have # already been created, so we use mock # objects to trick it. The options applied # to these mock objects are applied to the # real canvases later on, in the render # function below. if namespace.scene == 'ortho': sceneOpts = orthoopts.OrthoOpts(MockCanvasPanel(3)) elif namespace.scene == 'lightbox': sceneOpts = lightboxopts.LightBoxOpts(MockCanvasPanel(1)) elif namespace.scene == '3d': sceneOpts = scene3dopts.Scene3DOpts(MockCanvasPanel(1)) # 3D views default to # world display space if namespace.scene == '3d': childDisplayCtx.displaySpace = 'world' parseargs.applySceneArgs(namespace, overlayList, childDisplayCtx, sceneOpts) # Centre the location. The DisplayContext # will typically centre its location on # initialisation, but this may not work # if any overlay arguments change the bounds # of an overlay (e.g. mesh reference image) if namespace.worldLoc is None and namespace.voxelLoc is None: b = childDisplayCtx.bounds childDisplayCtx.location = [ b.xlo + 0.5 * b.xlen, b.ylo + 0.5 * b.ylen, b.zlo + 0.5 * b.zlen ] # This has to be applied after applySceneArgs, # in case the user used the '-std'/'-std1mm' # options. if namespace.selectedOverlay is not None: masterDisplayCtx.selectedOverlay = namespace.selectedOverlay if len(overlayList) == 0: raise RuntimeError('At least one overlay must be specified') return overlayList, childDisplayCtx, sceneOpts