def __init__(self, parent, overlayList, displayCtx, frame): """Create an ``OrthoPanel``. :arg parent: The :mod:`wx` parent. :arg overlayList: An :class:`.OverlayList` instance. :arg displayCtx: A :class:`.DisplayContext` instance. :arg displayCtx: A :class:`.FSLeyesFrame` instance. """ sceneOpts = orthoopts.OrthoOpts(self) canvaspanel.CanvasPanel.__init__(self, parent, overlayList, displayCtx, frame, sceneOpts) name = self.name contentPanel = self.contentPanel # The canvases themselves - each one displays a # slice along each of the three world axes self.__xcanvas = slicecanvas.WXGLSliceCanvas(contentPanel, overlayList, displayCtx, zax=0) self.__ycanvas = slicecanvas.WXGLSliceCanvas(contentPanel, overlayList, displayCtx, zax=1) self.__zcanvas = slicecanvas.WXGLSliceCanvas(contentPanel, overlayList, displayCtx, zax=2) self.__labelMgr = ortholabels.OrthoLabels(overlayList, displayCtx, sceneOpts, self.__xcanvas, self.__ycanvas, self.__zcanvas) # If an edit menu is added when in # 'edit' profile (see __profileChanged), # its name is stored here. self.__editMenuTitle = None xopts = self.__xcanvas.opts yopts = self.__ycanvas.opts zopts = self.__zcanvas.opts xopts.bindProps('pos', displayCtx, 'location') yopts.bindProps('pos', displayCtx, 'location') zopts.bindProps('pos', displayCtx, 'location') xopts.bindProps('showCursor', sceneOpts) yopts.bindProps('showCursor', sceneOpts) zopts.bindProps('showCursor', sceneOpts) xopts.bindProps('cursorGap', sceneOpts) yopts.bindProps('cursorGap', sceneOpts) zopts.bindProps('cursorGap', sceneOpts) xopts.bindProps('bgColour', sceneOpts) yopts.bindProps('bgColour', sceneOpts) zopts.bindProps('bgColour', sceneOpts) xopts.bindProps('cursorColour', sceneOpts) yopts.bindProps('cursorColour', sceneOpts) zopts.bindProps('cursorColour', sceneOpts) xopts.bindProps('zoom', sceneOpts, 'xzoom') yopts.bindProps('zoom', sceneOpts, 'yzoom') zopts.bindProps('zoom', sceneOpts, 'zzoom') xopts.bindProps('renderMode', sceneOpts) yopts.bindProps('renderMode', sceneOpts) zopts.bindProps('renderMode', sceneOpts) # Callbacks for ortho panel layout options sceneOpts.addListener('layout', name, self.__refreshLayout) self.toggleCursor.bindProps('toggled', sceneOpts, 'showCursor') self.toggleLabels.bindProps('toggled', sceneOpts, 'showLabels') self.toggleXCanvas.bindProps('toggled', sceneOpts, 'showXCanvas') self.toggleYCanvas.bindProps('toggled', sceneOpts, 'showYCanvas') self.toggleZCanvas.bindProps('toggled', sceneOpts, 'showZCanvas') # Callbacks for overlay list/selected overlay changes overlayList.addListener('overlays', name, self.__overlayListChanged) displayCtx.addListener('bounds', name, self.__refreshLayout) displayCtx.addListener('displaySpace', name, self.__radioOrientationChanged) displayCtx.addListener('radioOrientation', name, self.__radioOrientationChanged) displayCtx.addListener('selectedOverlay', name, self.__overlayListChanged) # Callbacks for toggling x/y/z canvas display sceneOpts.addListener('showXCanvas', name, self.__toggleCanvas) sceneOpts.addListener('showYCanvas', name, self.__toggleCanvas) sceneOpts.addListener('showZCanvas', name, self.__toggleCanvas) # Callbacks which just need to refresh def refresh(*a): self.Refresh() sceneOpts.addListener('labelSize', name, refresh, weak=False) sceneOpts.addListener('fgColour', name, refresh, weak=False) sceneOpts.addListener('showLabels', name, refresh, weak=False) self.addListener('profile', name, self.__profileChanged) from fsleyes.actions.correlate import PearsonCorrelateAction self.__pCorrAction = PearsonCorrelateAction(self.overlayList, self.displayCtx, self) self.pearsonCorrelation.bindProps('enabled', self.__pCorrAction) # Call the __onResize method to refresh # the slice canvases when the canvas # panel is resized, so aspect ratio # is maintained contentPanel.Bind(wx.EVT_SIZE, self.__onResize) # Initialise the panel self.__radioOrientationChanged() self.__refreshLayout(refresh=False) self.__overlayListChanged() 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