def applyCommandLineArgs(overlayList, displayCtx, argv, panel=None, applyOverlayArgs=True, **kwargs): """Applies the command line arguments stored in ``argv`` to the :class:`.CanvasPanel` ``panel``. If ``panel is None``, it is assumed that ``argv`` only contains overlay arguments. :arg overlayList: The :class:`.OverlayList`. :arg displayCtx: The :class:`.DisplayContext`. If a ``panel`` is provided, this should be the ``DisplayContext`` associated with that panel. :arg argv: List of command line arguments to apply. :arg panel: Optional :class:`.CanvasPanel` to apply the arguments to. :arg applyOverlayArgs: If ``False``, overlay arguments are not applied. All other keyword arguments are passed to the :func:`.parseargs.applyOverlayArgs` function. """ # We patch sys.stdout/stderr # while parseargs.parseArgs is # called so we can capture its # output. stdout = six.StringIO() stderr = six.StringIO() if argv[0] == 'fsleyes': argv = argv[1:] parser = argparse.ArgumentParser(add_help=False) try: real_stdout = sys.stdout real_stderr = sys.stderr sys.stdout = stdout sys.stderr = stderr namespace = parseargs.parseArgs(parser, argv, 'fsleyes') except SystemExit as e: raise ApplyCLIExit(e.code, stdout.getvalue(), stderr.getvalue()) finally: sys.stdout = real_stdout sys.stderr = real_stderr if applyOverlayArgs: parseargs.applyOverlayArgs(namespace, overlayList, displayCtx, **kwargs) if panel is not None: sceneOpts = panel.sceneOpts parseargs.applySceneArgs(namespace, overlayList, displayCtx, sceneOpts)
def applyCommandLineArgs(overlayList, displayCtx, argv, panel=None): """Applies the command line arguments stored in ``argv`` to the :class:`.CanvasPanel` ``panel``. If ``panel is None``, it is assumed that ``argv`` only contains overlay arguments. """ # We patch sys.stdout/stderr # while parseargs.parseArgs is # called so we can capture its # output. stdout = six.StringIO() stderr = six.StringIO() if argv[0] == 'fsleyes': argv = argv[1:] parser = argparse.ArgumentParser(add_help=False) try: real_stdout = sys.stdout real_stderr = sys.stderr sys.stdout = stdout sys.stderr = stderr namespace = parseargs.parseArgs(parser, argv, 'fsleyes') except SystemExit as e: raise ApplyCLIExit(e.code, stdout.getvalue(), stderr.getvalue()) finally: sys.stdout = real_stdout sys.stderr = real_stderr parseargs.applyOverlayArgs(namespace, overlayList, displayCtx) # No panel, no need to do anything else if panel is None: return sceneOpts = panel.sceneOpts parseargs.applySceneArgs(namespace, overlayList, displayCtx, sceneOpts)
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
def makeFrame(namespace, displayCtx, overlayList, splash): """Creates the *FSLeyes* interface. This function does the following: 1. Creates the :class:`.FSLeyesFrame` the top-level frame for ``fsleyes``. 2. Configures the frame according to the command line arguments (e.g. ortho or lightbox view). 3. Destroys the splash screen that was created by the :func:`context` function. :arg namespace: Parsed command line arguments, as returned by :func:`parseArgs`. :arg displayCtx: The :class:`.DisplayContext`, as created and returned by :func:`makeDisplayContext`. :arg overlayList: The :class:`.OverlayList`, as created and returned by :func:`makeDisplayContext`. :arg splash: The :class:`.FSLeyesSplash` frame. :returns: the :class:`.FSLeyesFrame` that was created. """ import fsl.utils.idle as idle import fsleyes_widgets.utils.status as status import fsleyes.parseargs as parseargs import fsleyes.frame as fsleyesframe import fsleyes.displaycontext as fsldisplay import fsleyes.layouts as layouts import fsleyes.views.canvaspanel as canvaspanel # Set up the frame scene (a.k.a. layout) # The scene argument can be: # # - The name of a saved (or built-in) layout # # - None, in which case the default or previous # layout is restored, unless a custom script # has been provided. script = namespace.runscript scene = namespace.scene # If a scene/layout or custom script # has not been specified, the default # behaviour is to restore the previous # frame layout. restore = (scene is None) and (script is None) status.update('Creating FSLeyes interface...') frame = fsleyesframe.FSLeyesFrame(None, overlayList, displayCtx, restore, True, fontSize=namespace.fontSize) # Allow files to be dropped # onto FSLeyes to open them dt = fsleyesframe.OverlayDropTarget(overlayList, displayCtx) frame.SetDropTarget(dt) # Make sure the new frame is shown # before destroying the splash screen frame.Show(True) frame.Refresh() frame.Update() # In certain instances under Linux/GTK, # closing the splash screen will crash # the application. No idea why. So we # leave the splash screen hidden, but # not closed, and close it when the main # frame is closed. This also works under # OSX. splash.Hide() splash.Refresh() splash.Update() def onFrameDestroy(ev): ev.Skip() # splash screen may already # have been destroyed try: splash.Close() except Exception: pass frame.Bind(wx.EVT_WINDOW_DESTROY, onFrameDestroy) status.update('Setting up scene...') # Set the default SceneOpts.performance # level so that all created SceneOpts # instances will default to it if namespace.performance is not None: fsldisplay.SceneOpts.performance.setAttribute(None, 'default', namespace.performance) # If a layout has been specified, # we load the layout if namespace.scene is not None: layouts.loadLayout(frame, namespace.scene) # Apply any view-panel specific arguments viewPanels = frame.viewPanels for viewPanel in viewPanels: if not isinstance(viewPanel, canvaspanel.CanvasPanel): continue displayCtx = viewPanel.displayCtx viewOpts = viewPanel.sceneOpts parseargs.applySceneArgs(namespace, overlayList, displayCtx, viewOpts) # If a script has been specified, we run # the script. This has to be done on the # idle loop, because overlays specified # on the command line are loaded on the # idle loop. Therefore, if we schedule the # script on idle (which is a queue), the # script can assume that all overlays have # already been loaded. from fsleyes.actions.runscript import RunScriptAction if script is not None: idle.idle(frame.menuActions[RunScriptAction], script) return frame
def applyCommandLineArgs(overlayList, displayCtx, argv, panel=None, applyOverlayArgs=True, baseDir=None, **kwargs): """Applies the command line arguments stored in ``argv`` to the :class:`.CanvasPanel` ``panel``. If ``panel is None``, it is assumed that ``argv`` only contains overlay arguments. :arg overlayList: The :class:`.OverlayList`. :arg displayCtx: The :class:`.DisplayContext`. If a ``panel`` is provided, this should be the ``DisplayContext`` associated with that panel. :arg argv: List of command line arguments to apply. :arg panel: Optional :class:`.CanvasPanel` to apply the arguments to. :arg applyOverlayArgs: If ``False``, overlay arguments are not applied. :arg baseDir: Directory from which to interpret the arguments, in case this is different from the current working directory, and overlays have been specified with relative paths. All other keyword arguments are passed to the :func:`.parseargs.applyOverlayArgs` function. """ # We patch sys.stdout/stderr # while parseargs.parseArgs is # called so we can capture its # output. stdout = six.StringIO() stderr = six.StringIO() if argv[0] == 'fsleyes': argv = argv[1:] parser = argparse.ArgumentParser(add_help=False) try: real_stdout = sys.stdout real_stderr = sys.stderr sys.stdout = stdout sys.stderr = stderr with chdir(baseDir): namespace = parseargs.parseArgs(parser, argv, 'fsleyes') except SystemExit as e: raise ApplyCLIExit(e.code, stdout.getvalue(), stderr.getvalue()) finally: sys.stdout = real_stdout sys.stderr = real_stderr if baseDir is not None: for o in namespace.overlays: if not op.isabs(o.overlay): o.overlay = op.join(baseDir, o.overlay) if applyOverlayArgs: parseargs.applyOverlayArgs(namespace, overlayList, displayCtx, **kwargs) if panel is not None: sceneOpts = panel.sceneOpts parseargs.applySceneArgs(namespace, overlayList, displayCtx, sceneOpts)