#
# layout.py - The layout API (previously called "perspectives").
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides functions for managing *layouts* - stored view and
control panel layouts for *FSLeyes*. Layouts may be persisted using the
:mod:`.settings` module. A few layouts are also *built in*, and are
defined in the :attr:`BUILT_IN_LAYOUTS` dictionary.
.. note:: Prior to FSLeyes 0.24.0, *layouts* were called *perspectives*.
The ``layouts`` module provides the following functions. These are intended
for use by the :class:`.FSLeyesFrame`, but can be used in other ways too:
.. autosummary::
:nosignatures:
getAllLayouts
loadLayout
applyLayout
saveLayout
removeLayout
serialiseLayout
deserialiseLayout
A layout defines a layout for a :class:`.FSLeyesFrame`. It specifies the
type and layout of one or more *views* (defined in the :mod:`.views` module)
and, within each view, the type and layout of one or more *controls* (defined
in the :mod:`.controls` module). See the :mod:`fsleyes` documentation for
an overview of views and controls.
All of this information is stored as a string - see the
:func:`serialiseLayout` function for details on its storage format.
"""
import logging
import textwrap
import collections
import fsl.utils.settings as fslsettings
import fsleyes_widgets.utils.status as status
import fsleyes.strings as strings
log = logging.getLogger(__name__)
[docs]def getAllLayouts():
"""Returns a list containing the names of all saved layouts. The
returned list does not include built-in layouts - these are
accessible in the :attr:`BUILT_IN_LAYOUTS` dictionary.
"""
layouts = fslsettings.read('fsleyes.layouts', []) + \
fslsettings.read('fsleyes.perspectives', [])
uniq = []
for l in layouts:
if l not in uniq:
uniq.append(l)
return uniq
[docs]def loadLayout(frame, name, **kwargs):
"""Load the named layout, and apply it to the given
:class:`.FSLeyesFrame`. The ``kwargs`` are passed through to the
:func:`applyLayout` function.
"""
if name in BUILT_IN_LAYOUTS.keys():
log.debug('Loading built-in layout {}'.format(name))
layout = BUILT_IN_LAYOUTS[name]
else:
log.debug('Loading saved layout {}'.format(name))
layout = fslsettings.read('fsleyes.layouts.{}'.format(name), None)
if layout is None:
fslsettings.read('fsleyes.perspectives.{}'.format(name), None)
if layout is None:
raise ValueError('No layout named "{}" exists'.format(name))
log.debug('Applying layout:\n{}'.format(layout))
applyLayout(frame, name, layout, **kwargs)
[docs]def applyLayout(frame, name, layout, message=None):
"""Applies the given serialised layout string to the given
:class:`.FSLeyesFrame`.
:arg frame: The :class:`.FSLeyesFrame` instance.
:arg name: The layout name.
:arg layout: The serialised layout string.
:arg message: A message to display (using the :mod:`.status` module).
"""
import fsleyes.views.canvaspanel as canvaspanel
layout = deserialiseLayout(layout)
frameChildren = layout[0]
frameLayout = layout[1]
vpChildrens = layout[2]
vpLayouts = layout[3]
vpPanelProps = layout[4]
vpSceneProps = layout[5]
# Show a message while re-configuring the frame
if message is None:
message = strings.messages[
'layout.applyingLayout'].format(
strings.layouts.get(name, name))
status.update(message)
# Clear all existing view
# panels from the frame
frame.removeAllViewPanels()
# Add all of the view panels
# specified in the layout
for vp in frameChildren:
log.debug('Adding view panel {} to frame'.format(vp.__name__))
frame.addViewPanel(vp)
# Apply the layout to those view panels
frame.auiManager.LoadPerspective(frameLayout)
# For each view panel, add all of the
# control panels, and lay them out
viewPanels = frame.viewPanels
for i in range(len(viewPanels)):
vp = viewPanels[ i]
children = vpChildrens[ i]
vpLayout = vpLayouts[ i]
panelProps = vpPanelProps[i]
sceneProps = vpSceneProps[i]
for child in children:
log.debug('Adding control panel {} to {}'.format(
child.__name__, type(vp).__name__))
_addControlPanel(vp, child)
vp.auiManager.LoadPerspective(vpLayout)
# Apply saved property values
# to the view panel.
for name, val in panelProps.items():
log.debug('Setting {}.{} = {}'.format(
type(vp).__name__, name, val))
vp.deserialise(name, val)
# And, if it is a CanvasPanel,
# to its SceneOpts instance.
if isinstance(vp, canvaspanel.CanvasPanel):
opts = vp.sceneOpts
for name, val in sceneProps.items():
log.debug('Setting {}.{} = {}'.format(
type(opts).__name__, name, val))
opts.deserialise(name, val)
[docs]def saveLayout(frame, name):
"""Serialises the layout of the given :class:`.FSLeyesFrame` and saves
it as a layout with the given name.
"""
if name in BUILT_IN_LAYOUTS.keys():
raise ValueError('A built-in layout named "{}" '
'already exists'.format(name))
log.debug('Saving current layout with name {}'.format(name))
layout = serialiseLayout(frame)
fslsettings.write('fsleyes.layouts.{}'.format(name), layout)
_addToLayoutList(name)
log.debug('Serialised layout:\n{}'.format(layout))
[docs]def removeLayout(name):
"""Deletes the named layout. """
log.debug('Deleting layout with name {}'.format(name))
fslsettings.delete('fsleyes.layouts.{}' .format(name))
fslsettings.delete('fsleyes.perspectives.{}'.format(name))
_removeFromLayoutList(name)
[docs]def serialiseLayout(frame):
"""Serialises the layout of the given :class:`.FSLeyesFrame`, and returns
it as a string.
.. note:: This function was written against wx.lib.agw.aui.AuiManager as
it exists in wxPython 3.0.2.0.
*FSLeyes* uses a hierarchy of ``wx.lib.agw.aui.AuiManager`` instances for
its layout - the :class:`.FSLeyesFrame` uses an ``AuiManager`` to lay out
:class:`.ViewPanel` instances, and each of these ``ViewPanels`` use their
own ``AuiManager`` to lay out control panels.
The layout for a single ``AuiManager`` can be serialised to a string via
the ``AuiManager.SavePerspective`` and ``AuiManager.SavePaneInfo``
methods. One of these strings consists of:
- A name, `'layout1'` or `'layout2'`, specifying the AUI version
(this will always be at least `'layout2'` for *FSLeyes*).
- A set of key-value set of key-value pairs defining the top level
panel layout.
- A set of key-value pairs for each pane, defining its layout. the
``AuiManager.SavePaneInfo`` method returns this for a single pane.
These are all encoded in a single string, with the above components
separated with '|' characters, and the pane-level key-value pairs
separated with a ';' character. For example:
layout2|key1=value1|name=Pane1;caption=Pane 1|\
name=Pane2;caption=Pane 2|doc_size(5,0,0)=22|
This function queries each of the AuiManagers, and extracts the following:
- A layout string for the :class:`.FSLeyesFrame`.
- A string containing a comma-separated list of :class:`.ViewPanel`
class names, in the same order as they are specified in the frame
layout string.
- For each ``ViewPanel``:
- A layout string for the ``ViewPanel``
- A string containing a comma-separated list of control panel class
names, in the same order as specified in the ``ViewPanel`` layout
string.
Each of these pieces of information are then concatenated into a single
newline separated string.
"""
# We'll start by defining this silly function, which
# takes an ``AuiManager`` layout string, and a list
# of the children which are being managed by the
# AuiManager, and makes sure that the order of the
# child pane layout specifications in the string is
# the same as the order of the children in the list.
#
# If the 'rename' argument is True, this function
# performs an additional step.
#
# The FSLeyesFrame gives each of its view panels a
# unique name of the form "ClassName index", where
# the 'index' is a sequentially increasing identifier
# number (so that multiple views of the same type can
# be differentiated). If the 'rename' argument to
# this function is True, these names are adjusted so
# that they begin at 1 and increase sequentially. This
# is done by the patchPanelName function, defined
# below.
#
# This name adjustment is required to handle
# situations where the indices of existing view panels
# are not sequential, as when a layout is applied, the
# view panel names given by the FSLeyesFrame must
# match the names that are specified in the layout
# string.
#
# In addition to patching the name of each panel,
# the 'rename' argument will also cause the panel
# caption (its display title) to be adjusted so that
# it is in line with the name.
def patchLayoutString(auiMgr, panels, rename=False):
layoutStr = auiMgr.SavePerspective()
# The different sections of the string
# returned by SavePerspective are
# separated with a '|' character.
sections = layoutStr.split('|')
sections = [s.strip() for s in sections]
sections = [s for s in sections if s != '']
# Here, we identify sections which specify
# the layout of a child pane, remove them,
# and patch them back in, in the order that
# the child panels are specified in the list.
pi = 0
for si, s in enumerate(sections):
if s.find('name=') > -1:
panel = panels[pi]
panelInfo = auiMgr.GetPane(panel)
panelLayout = auiMgr.SavePaneInfo(panelInfo)
pi += 1
sections[si] = panelLayout
if rename:
sections[si] = patchPanelName(sections[si], pi)
# Now the panel layouts in our layout string
# are in the same order as our list of view
# panels - we can re-join the layout string
# sections, and we're done.
return '|'.join(sections) + '|'
# The purpose of this function is described above.
def patchPanelName(layoutString, index):
# In each AUI layout section, 'key=value'
# pairs are separated with a semi-colon
kvps = layoutString.split(';')
# And each 'key=value' pair is separated
# with an equals character
kvps = [kvp.split('=') for kvp in kvps]
kvps = collections.OrderedDict(kvps)
# We need to update the indices contained
# in the 'name' and 'caption' values
name = kvps['name']
caption = kvps['caption']
# Strip off the old index
name = ' '.join(name .split()[:-1])
caption = ' '.join(caption.split()[:-1])
# Patch in the new index
name = '{} {}'.format(name, index)
caption = '{} {}'.format(caption, index)
kvps['name'] = name
kvps['caption'] = caption
# Reconstruct the layout string
kvps = ['='.join((k, v)) for k, v in kvps.items()]
kvps = ';'.join(kvps)
return kvps
# Now we can start extracting the layout information.
# We start with the FSLeyesFrame layout.
auiMgr = frame.auiManager
viewPanels = frame.viewPanels
# Generate the frame layout string, and a
# list of the children of the frame
frameLayout = patchLayoutString(auiMgr, viewPanels, True)
frameChildren = [type(vp).__name__ for vp in viewPanels]
frameChildren = ','.join(frameChildren)
# We are going to build a list of layout strings,
# one for each ViewPanel, and a corresponding list
# of control panels displayed on each ViewPanel.
vpLayouts = []
vpConfigs = []
for vp in viewPanels:
# Get the auiManager and layout for this view panel.
# This is a little bit complicated, as ViewPanels
# differentiate between the main 'centre' panel, and
# all other secondary (control) panels. The layout
# string needs to contain layout information for
# all of these panels, but we only care about the
# control panels.
vpAuiMgr = vp.auiManager
ctrlPanels = vp.getPanels()
centrePanel = vp.centrePanel
# As above for the frame, generate a layout
# string and a list of control panels - the
# children of the view panel.
vpLayout = patchLayoutString(vpAuiMgr, [centrePanel] + ctrlPanels)
vpChildren = [type(cp).__name__ for cp in ctrlPanels]
vpChildren = ','.join(vpChildren)
# Get the panel and scene settings
panelProps, sceneProps = _getPanelProps(vp)
# And turn them into comma-separated key-value pairs.
panelProps = ['{}={}'.format(k, v) for k, v in panelProps.items()]
sceneProps = ['{}={}'.format(k, v) for k, v in sceneProps.items()]
panelProps = ','.join(panelProps)
sceneProps = ','.join(sceneProps)
# Build the config string - the children,
# the panel settings and the scene settings.
vpConfig = ';'.join([vpChildren, panelProps, sceneProps])
vpLayouts.append(vpLayout)
vpConfigs.append(vpConfig)
# We serialise all of these pieces of information
# as a single newline-separated string.
layout = [frameChildren, frameLayout]
for vpConfig, vpLayout in zip(vpConfigs, vpLayouts):
layout.append(vpConfig)
layout.append(vpLayout)
# And we're done!
return '\n'.join(layout)
[docs]def deserialiseLayout(layout):
"""Deserialises a layout string which was created by the
:func:`serialiseLayout` string.
:returns: A tuple containing the following:
- A list of :class:`.ViewPanel` class types - the
children of the :class:`.FSLeyesFrame`.
- An ``aui`` layout string for the :class:`.FSLeyesFrame`
- A list of lists, one for each ``ViewPanel``, with each
list containing a collection of control panel class
types - the children of the corresponding ``ViewPanel``.
- A list of strings, one ``aui`` layout string for each
``ViewPanel``.
- A list of dictionaries, one for each ``ViewPanel``,
containing property ``{name : value}`` pairs to be
applied to the ``ViewPanel``.
- A list of dictionaries, one for each ``ViewPanel``,
containing property ``{name : value}`` pairs to be applied
to the :class:`.SceneOpts` instance associated with the
``ViewPanel``. If the ``ViewPanel`` is not a
:class:`.CanvasPanel`, the dictionary will be empty.
"""
from fsleyes.views.orthopanel import OrthoPanel
from fsleyes.views.lightboxpanel import LightBoxPanel
from fsleyes.views.scene3dpanel import Scene3DPanel
from fsleyes.views.timeseriespanel import TimeSeriesPanel
from fsleyes.views.histogrampanel import HistogramPanel
from fsleyes.views.powerspectrumpanel import PowerSpectrumPanel
from fsleyes.views.shellpanel import ShellPanel
from fsleyes.controls.atlaspanel import AtlasPanel
from fsleyes.controls.canvassettingspanel import CanvasSettingsPanel
from fsleyes.controls.clusterpanel import ClusterPanel
from fsleyes.controls.histogramcontrolpanel import \
HistogramControlPanel
from fsleyes.controls.histogramtoolbar import HistogramToolBar
from fsleyes.controls.lightboxtoolbar import LightBoxToolBar
from fsleyes.controls.locationpanel import LocationPanel
from fsleyes.controls.lookuptablepanel import LookupTablePanel
from fsleyes.controls.melodicclassificationpanel import \
MelodicClassificationPanel
from fsleyes.controls.orthoeditactiontoolbar import \
OrthoEditActionToolBar
from fsleyes.controls.orthoedittoolbar import OrthoEditToolBar
from fsleyes.controls.orthotoolbar import OrthoToolBar
from fsleyes.controls.overlaydisplaypanel import OverlayDisplayPanel
from fsleyes.controls.overlaydisplaytoolbar import \
OverlayDisplayToolBar
from fsleyes.controls.overlayinfopanel import OverlayInfoPanel
from fsleyes.controls.overlaylistpanel import OverlayListPanel
from fsleyes.controls.plotlistpanel import PlotListPanel
from fsleyes.controls.plottoolbar import PlotToolBar
from fsleyes.controls.powerspectrumcontrolpanel import \
PowerSpectrumControlPanel
from fsleyes.controls.powerspectrumtoolbar import \
PowerSpectrumToolBar
from fsleyes.controls.scene3dtoolbar import Scene3DToolBar
from fsleyes.controls.timeseriescontrolpanel import \
TimeSeriesControlPanel
from fsleyes.controls.timeseriestoolbar import TimeSeriesToolBar
from fsleyes.controls.filetreepanel import FileTreePanel
views = {
'OrthoPanel' : OrthoPanel,
'LightBoxPanel' : LightBoxPanel,
'Scene3DPanel' : Scene3DPanel,
'TimeSeriesPanel' : TimeSeriesPanel,
'HistogramPanel' : HistogramPanel,
'PowerSpectrumPanel' : PowerSpectrumPanel,
'ShellPanel' : ShellPanel
}
controls = {
'AtlasPanel' : AtlasPanel,
'CanvasSettingsPanel' : CanvasSettingsPanel,
'ClusterPanel' : ClusterPanel,
'HistogramControlPanel' : HistogramControlPanel,
'HistogramToolBar' : HistogramToolBar,
'LightBoxToolBar' : LightBoxToolBar,
'LocationPanel' : LocationPanel,
'LookupTablePanel' : LookupTablePanel,
'MelodicClassificationPanel' : MelodicClassificationPanel,
'OrthoEditActionToolBar' : OrthoEditActionToolBar,
'OrthoEditToolBar' : OrthoEditToolBar,
'OrthoToolBar' : OrthoToolBar,
'OverlayDisplayPanel' : OverlayDisplayPanel,
'OverlayDisplayToolBar' : OverlayDisplayToolBar,
'OverlayInfoPanel' : OverlayInfoPanel,
'OverlayListPanel' : OverlayListPanel,
'PlotListPanel' : PlotListPanel,
'PlotToolBar' : PlotToolBar,
'PowerSpectrumControlPanel' : PowerSpectrumControlPanel,
'PowerSpectrumToolBar' : PowerSpectrumToolBar,
'Scene3DToolBar' : Scene3DToolBar,
'TimeSeriesControlPanel' : TimeSeriesControlPanel,
'TimeSeriesToolBar' : TimeSeriesToolBar,
'FileTreePanel' : FileTreePanel,
}
lines = layout.split('\n')
lines = [line.strip() for line in lines]
lines = [line for line in lines if line != '']
frameChildren = lines[0]
frameLayout = lines[1]
# The children strings are comma-separated
# class names. The frame children are ViewPanels,
# which are all defined in the fsleyes.views
# package.
frameChildren = frameChildren.split(',')
frameChildren = [fc.strip() for fc in frameChildren]
frameChildren = [fc for fc in frameChildren if fc != '']
frameChildren = [views[fc] for fc in frameChildren]
# Collate the children/layouts for each view panel
vpChildren = []
vpLayouts = []
vpPanelProps = []
vpSceneProps = []
for i in range(len(frameChildren)):
linei = (i * 2) + 2
config = lines[linei]
layout = lines[linei + 1]
children, panelProps, sceneProps = config.split(';')
vpChildren .append(children)
vpLayouts .append(layout)
vpPanelProps .append(panelProps)
vpSceneProps .append(sceneProps)
# The ViewPanel children string is a comma-separated
# list of control panel class names. All control panels
# should be defined in the fsleyes.controls package.
for i in range(len(vpChildren)):
children = vpChildren[i].split(',')
children = [vpc.strip() for vpc in children]
children = [vpc for vpc in children if vpc != '']
children = [controls[vpc] for vpc in children]
vpChildren[i] = children
# The panel props and scene props strings are
# comma-separated lists of 'prop=value' pairs.
# We'll turn them into a dict for convenience.
for i in range(len(vpPanelProps)):
props = vpPanelProps[i].split(',')
props = [p for p in props if p != '']
props = [p.split('=') for p in props]
vpPanelProps[i] = collections.OrderedDict(props)
for i in range(len(vpSceneProps)):
props = vpSceneProps[i].split(',')
props = [p for p in props if p != '']
props = [p.split('=') for p in props]
vpSceneProps[i] = collections.OrderedDict(props)
return (frameChildren,
frameLayout,
vpChildren,
vpLayouts,
vpPanelProps,
vpSceneProps)
[docs]def _addToLayoutList(layout):
"""Adds the given layout name to the list of saved layouts. """
layout = layout.strip()
layouts = getAllLayouts()
if layout not in layouts:
layouts.append(layout)
log.debug('Updating stored layout list: {}'.format(layout))
fslsettings.write('fsleyes.layouts', layouts)
[docs]def _removeFromLayoutList(layout):
"""Removes the given layout name from the list of saved layouts.
"""
layouts = getAllLayouts()
try: layouts.remove(layout)
except ValueError: return
log.debug('Updating stored layout list: {}'.format(layouts))
fslsettings.write('fsleyes.layouts', layouts)
[docs]def _addControlPanel(viewPanel, panelType):
"""Adds a control panel to the given :class:`.ViewPanel`.
:arg viewPanel: A :class:`.ViewPanel` instance.
:arg panelType: A control panel type.
"""
from fsleyes.views.plotpanel import OverlayPlotPanel
from fsleyes.views.orthopanel import OrthoPanel
from fsleyes.controls.canvassettingspanel import CanvasSettingsPanel
from fsleyes.controls.histogramcontrolpanel import \
HistogramControlPanel
from fsleyes.controls.histogramtoolbar import HistogramToolBar
from fsleyes.controls.locationpanel import LocationPanel
from fsleyes.controls.lightboxtoolbar import LightBoxToolBar
from fsleyes.controls.melodicclassificationpanel import \
MelodicClassificationPanel
from fsleyes.controls.orthoeditactiontoolbar import \
OrthoEditActionToolBar
from fsleyes.controls.orthoedittoolbar import OrthoEditToolBar
from fsleyes.controls.orthotoolbar import OrthoToolBar
from fsleyes.controls.overlaydisplaytoolbar import \
OverlayDisplayToolBar
from fsleyes.controls.overlaylistpanel import OverlayListPanel
from fsleyes.controls.plotlistpanel import PlotListPanel
from fsleyes.controls.plottoolbar import PlotToolBar
from fsleyes.controls.powerspectrumcontrolpanel import \
PowerSpectrumControlPanel
from fsleyes.controls.powerspectrumtoolbar import \
PowerSpectrumToolBar
from fsleyes.controls.scene3dtoolbar import Scene3DToolBar
from fsleyes.controls.timeseriescontrolpanel import \
TimeSeriesControlPanel
from fsleyes.controls.timeseriestoolbar import TimeSeriesToolBar
args = {
CanvasSettingsPanel : {'canvasPanel' : viewPanel},
MelodicClassificationPanel : {'canvasPanel' : viewPanel},
HistogramControlPanel : {'plotPanel' : viewPanel},
HistogramToolBar : {'histPanel' : viewPanel},
LightBoxToolBar : {'lb' : viewPanel},
OrthoEditActionToolBar : {'ortho' : viewPanel},
OrthoEditToolBar : {'ortho' : viewPanel},
OrthoToolBar : {'ortho' : viewPanel},
OverlayDisplayToolBar : {'viewPanel' : viewPanel},
PlotListPanel : {'plotPanel' : viewPanel},
PlotToolBar : {'plotPanel' : viewPanel},
PowerSpectrumControlPanel : {'plotPanel' : viewPanel},
PowerSpectrumToolBar : {'psPanel' : viewPanel},
Scene3DToolBar : {'panel' : viewPanel},
TimeSeriesControlPanel : {'plotPanel' : viewPanel},
TimeSeriesToolBar : {'tsPanel' : viewPanel},
}
args = args.get(panelType, {})
# Slightly hacky ... some views
# customies certain controls a
# bit, so we call specific
# methods to add them.
if isinstance(viewPanel, OverlayPlotPanel) and \
panelType == OverlayListPanel:
viewPanel.toggleOverlayList()
elif isinstance(viewPanel, OrthoPanel) and \
panelType == LocationPanel:
viewPanel.toggleLocationPanel()
else:
viewPanel.togglePanel(panelType, **args)
[docs]def _getPanelProps(panel):
"""Creates and returns two dictionaries, containing properties of the given
:class:`.ViewPanel` (and its associated :class:`.SceneOpts` instance, if
it is a :class:`.CanvasPanel`), which are to be saved as part of a
seriaised *FSLeyes* layout. The properties to be saved are listed in
the :data:`VIEWPANEL_PROPS` dictionary.
"""
import fsleyes.views.canvaspanel as canvaspanel
import fsleyes.views.plotpanel as plotpanel
if not isinstance(panel, (canvaspanel.CanvasPanel, plotpanel.PlotPanel)):
return {}, {}
panelType = type(panel).__name__
panelProps = VIEWPANEL_PROPS[panelType]
sceneProps = {}
if isinstance(panel, canvaspanel.CanvasPanel):
opts = panel.sceneOpts
panelProps, sceneProps = panelProps
sceneProps = {name : opts .serialise(name) for name in sceneProps}
panelProps = {name : panel.serialise(name) for name in panelProps}
return panelProps, sceneProps
VIEWPANEL_PROPS = {
'OrthoPanel' : [['syncLocation',
'syncOverlayOrder',
'syncOverlayDisplay',
'syncOverlayVolume',
'movieRate',
'movieAxis'],
['showCursor',
'bgColour',
'fgColour',
'cursorColour',
'cursorGap',
'showColourBar',
'colourBarLocation',
'colourBarLabelSide',
'showXCanvas',
'showYCanvas',
'showZCanvas',
'showLabels',
'labelSize',
'layout',
'xzoom',
'yzoom',
'zzoom',
'highDpi']],
'LightBoxPanel' : [['syncLocation',
'syncOverlayOrder',
'syncOverlayDisplay',
'syncOverlayVolume',
'movieRate',
'movieAxis'],
['showCursor',
'bgColour',
'fgColour',
'cursorColour',
'showColourBar',
'colourBarLocation',
'colourBarLabelSide',
'zax',
'showGridLines',
'highlightSlice',
'highDpi']],
'Scene3DPanel' : [['syncLocation',
'syncOverlayOrder',
'syncOverlayDisplay',
'syncOverlayVolume'],
['showCursor',
'bgColour',
'fgColour',
'cursorColour',
'showColourBar',
'colourBarLocation',
'colourBarLabelSide',
'occlusion',
'light',
'lightPos',
'offset',
'rotation',
'showLegend']],
'TimeSeriesPanel' : ['legend',
'xAutoScale',
'yAutoScale',
'xLogScale',
'yLogScale',
'ticks',
'grid',
'gridColour',
'bgColour',
'smooth',
'usePixdim',
'plotMode',
'plotMelodicICs'],
'HistogramPanel' : ['legend',
'xAutoScale',
'yAutoScale',
'xLogScale',
'yLogScale',
'ticks',
'grid',
'gridColour',
'bgColour',
'smooth',
'histType',
'plotType'],
'PowerSpectrumPanel' : ['legend',
'xAutoScale',
'yAutoScale',
'xLogScale',
'yLogScale',
'ticks',
'grid',
'gridColour',
'bgColour',
'smooth',
'plotMelodicICs',
'plotFrequencies']}
# The order in which properties are defined in
# a layout is the order in which they will
# be applied. This is important to remember when
# considering properties that have side effects
# (e.g. setting SceneOpts.bgColour will clobber
# SceneOpts.fgColour).
BUILT_IN_LAYOUTS = collections.OrderedDict((
('default',
textwrap.dedent("""
OrthoPanel
layout2|name=OrthoPanel 1;caption=Ortho View 1;state=67376064;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=22|
OrthoToolBar,OverlayDisplayToolBar,OverlayListPanel,LocationPanel;syncOverlayOrder=True,syncLocation=True,syncOverlayDisplay=True,movieRate=400;colourBarLocation=top,showCursor=True,bgColour=#000000ff,layout=horizontal,colourBarLabelSide=top-left,cursorGap=False,fgColour=#ffffffff,cursorColour=#00ff00ff,showXCanvas=True,showYCanvas=True,showColourBar=False,showZCanvas=True,showLabels=True
layout2|name=Panel;caption=;state=768;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=OrthoToolBar;caption=Ortho view toolbar;state=67382012;dir=1;layer=10;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=OverlayDisplayToolBar;caption=Display toolbar;state=67382012;dir=1;layer=11;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=OverlayListPanel;caption=Overlay list;state=67373052;dir=3;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=1;minh=1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=LocationPanel;caption=Location;state=67373052;dir=3;layer=0;row=0;pos=1;prop=100000;bestw=-1;besth=-1;minw=1;minh=1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=22|dock_size(3,0,0)=176|dock_size(1,10,0)=49|dock_size(1,11,0)=67|
""")), # noqa
('melodic',
textwrap.dedent("""
LightBoxPanel,TimeSeriesPanel,PowerSpectrumPanel
layout2|name=LightBoxPanel 1;caption=Lightbox View 1;state=67377088;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=TimeSeriesPanel 2;caption=Time series 2;state=67377148;dir=3;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=PowerSpectrumPanel 3;caption=Power spectra 3;state=67377148;dir=3;layer=0;row=0;pos=1;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=22|dock_size(3,0,0)=224|
LocationPanel,OverlayListPanel,MelodicClassificationPanel,LightBoxToolBar,OverlayDisplayToolBar;syncLocation=True,syncOverlayOrder=True,movieRate=750,syncOverlayDisplay=True;bgColour=#000000ff,fgColour=#ffffffff,showCursor=True,cursorColour=#00ff00ff,highlightSlice=False,zax=2,showColourBar=False,showGridLines=False,colourBarLocation=top
layout2|name=Panel;caption=;state=768;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=LocationPanel;caption=Location;state=67373052;dir=3;layer=0;row=0;pos=1;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=OverlayListPanel;caption=Overlay list;state=67373052;dir=3;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=MelodicClassificationPanel;caption=Melodic IC classification;state=67373052;dir=2;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=LightBoxToolBar;caption=Lightbox view toolbar;state=67382012;dir=1;layer=10;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=OverlayDisplayToolBar;caption=Display toolbar;state=67382012;dir=1;layer=11;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=22|dock_size(3,0,0)=130|dock_size(1,10,0)=45|dock_size(1,11,0)=51|dock_size(2,0,0)=402|
TimeSeriesToolBar;;
layout2|name=FigureCanvasWxAgg;caption=;state=768;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=TimeSeriesToolBar;caption=Time series toolbar;state=67382012;dir=1;layer=10;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=642|dock_size(1,10,0)=36|
PowerSpectrumToolBar;;
layout2|name=FigureCanvasWxAgg;caption=;state=768;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=PowerSpectrumToolBar;caption=Plot toolbar;state=67382012;dir=1;layer=10;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=642|dock_size(1,10,0)=36|
""")), # noqa
('feat',
textwrap.dedent("""
OrthoPanel,TimeSeriesPanel
layout2|name=OrthoPanel 1;caption=Ortho View 1;state=67377088;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=TimeSeriesPanel 2;caption=Time series 2;state=67377148;dir=3;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=22|dock_size(3,0,0)=282|
OverlayListPanel,OverlayDisplayToolBar,OrthoToolBar,LocationPanel,ClusterPanel;syncLocation=True,syncOverlayOrder=True,movieRate=750,syncOverlayDisplay=True;layout=horizontal,showLabels=True,bgColour=#000000ff,fgColour=#ffffffff,showCursor=True,showZCanvas=True,cursorColour=#00ff00ff,showColourBar=False,showYCanvas=True,showXCanvas=True,colourBarLocation=top
layout2|name=Panel;caption=;state=768;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=OverlayListPanel;caption=Overlay list;state=67373052;dir=3;layer=2;row=0;pos=0;prop=87792;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=OverlayDisplayToolBar;caption=Display toolbar;state=67382012;dir=1;layer=10;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=OrthoToolBar;caption=Ortho view toolbar;state=67382012;dir=1;layer=10;row=1;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=LocationPanel;caption=Location;state=67373052;dir=3;layer=2;row=0;pos=1;prop=98544;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=ClusterPanel;caption=Cluster browser;state=67373052;dir=2;layer=1;row=0;pos=0;prop=114760;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=10|dock_size(2,1,0)=566|dock_size(1,10,0)=51|dock_size(1,10,1)=36|dock_size(3,2,0)=130|
OverlayListPanel,TimeSeriesToolBar;;
layout2|name=FigureCanvasWxAgg;caption=;state=768;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=OverlayListPanel;caption=Overlay list;state=67373052;dir=4;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=TimeSeriesToolBar;caption=Time series toolbar;state=67382012;dir=1;layer=10;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=642|dock_size(1,10,0)=36|dock_size(4,0,0)=206|
""")), # noqa
('ortho',
textwrap.dedent("""
OrthoPanel
layout2|name=OrthoPanel 1;caption=Ortho View 1;state=67376064;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=22|
;syncLocation=True,syncOverlayOrder=True,syncOverlayDisplay=True;layout=horizontal,showLabels=True,bgColour=#000000ff,fgColour=#ffffffff,showCursor=True,showZCanvas=True,cursorColour=#00ff00ff,showColourBar=False,showYCanvas=True,showXCanvas=True,colourBarLocation=top
layout2|name=Panel;caption=;state=768;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=22|
""")), # noqa
('3d',
textwrap.dedent("""
Scene3DPanel
layout2|name=Scene3DPanel 1;caption=3D View 1;state=67376064;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=24|
;syncOverlayOrder=True,syncOverlayDisplay=True,syncLocation=True;showColourBar=False,showLegend=True,cursorColour=#00ff00ff,colourBarLocation=top,showCursor=True,colourBarLabelSide=top-left,bgColour=#9999c0ff,fgColour=#00ff00ff
layout2|name=Panel;caption=;state=768;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=22|
""")), # noqa
('lightbox',
textwrap.dedent("""
LightBoxPanel
layout2|name=LightBoxPanel 1;caption=Lightbox View 1;state=67376064;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=22|
;syncLocation=True,syncOverlayOrder=True,syncOverlayDisplay=True;bgColour=#000000ff,fgColour=#ffffffff,showCursor=True,cursorColour=#00ff00ff,highlightSlice=False,zax=2,showColourBar=False,showGridLines=False,colourBarLocation=top
layout2|name=Panel;caption=;state=768;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=-1;besth=-1;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(5,0,0)=10|
""")))) # noqa