Example #1
0
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)
Example #2
0
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)
Example #3
0
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
Example #4
0
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
Example #5
0
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)