diff --git a/doc/images/lightboxtoolbar.png b/doc/images/lightboxtoolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..13241307998c01d8a195cb99b9eeee145b91fff8 Binary files /dev/null and b/doc/images/lightboxtoolbar.png differ diff --git a/doc/images/locationpanel.png b/doc/images/locationpanel.png new file mode 100644 index 0000000000000000000000000000000000000000..a55a2be384f9df50ac8c020e1e1114621210d029 Binary files /dev/null and b/doc/images/locationpanel.png differ diff --git a/doc/images/orthotoolbar.png b/doc/images/orthotoolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..3854d22a759ea73347637c01e5c3d1f9ae297f72 Binary files /dev/null and b/doc/images/orthotoolbar.png differ diff --git a/fsl/fsleyes/controls/lightboxtoolbar.py b/fsl/fsleyes/controls/lightboxtoolbar.py index 67b6f7b5bb870504715ffb3a345c9642fbd5d3b2..0e4289f6e27637e6327d2765a01c8484a5c5b573 100644 --- a/fsl/fsleyes/controls/lightboxtoolbar.py +++ b/fsl/fsleyes/controls/lightboxtoolbar.py @@ -1,9 +1,12 @@ #!/usr/bin/env python # -# lightboxtoolbar.py - +# lightboxtoolbar.py - The LightBoxToolBar class. # # Author: Paul McCarthy <pauldmccarthy@gmail.com> # +"""This module provides the :class:`LightBoxToolBar` class, which is a +:class:`.FSLEyesToolBar` for use with the :class:`.LightBoxPanel`. +""" import wx @@ -18,8 +21,30 @@ import fsl.data.strings as strings class LightBoxToolBar(fsltoolbar.FSLEyesToolBar): - + """The ``LightBoxToolBar`` is a :class:`.FSLEyesToolBar` for use with the + :class:`.LightBoxPanel`. A ``LightBoxToolBar`` looks something like this: + + + .. image:: images/lightboxtoolbar.png + :scale: 50% + :align: center + + + The ``LightBoxToolBar`` allows the user to control important parts of the + :class:`.LightBoxPanel` display, and also to display a + :class:`.CanvasSettingsPanel`, which allows control over all aspects of a + ``LightBoxPanel``. + """ + + def __init__(self, parent, overlayList, displayCtx, lb): + """Create a ``LightBoxToolBar``. + + :arg parent: The :mod:`wx` parent object. + :arg overlayList: The :class:`.OverlayList` instance. + :arg displayCtx: The :class:`.DisplayContext` instance. + :arg lb: The :class:`.LightBoxPanel` instance. + """ actionz = {'more' : self.showMoreSettings} @@ -123,6 +148,12 @@ class LightBoxToolBar(fsltoolbar.FSLEyesToolBar): def showMoreSettings(self, *a): + """Opens a :class:`.CanvasSettingsPanel` for the + :class:`.LightBoxPanel` that owns this ``LightBoxToolBar``. + + The ``CanvasSettingsPanel`` is opened as a floating pane - see the + :meth:`.ViewPanel.togglePanel` method. + """ import canvassettingspanel self.lightBoxPanel.togglePanel( canvassettingspanel.CanvasSettingsPanel, diff --git a/fsl/fsleyes/controls/locationpanel.py b/fsl/fsleyes/controls/locationpanel.py index ee9a357dd31e83cc9405076ee9e43dff6c40d23a..d788b5d34c8c151d7ab2200dba99272489fb645f 100644 --- a/fsl/fsleyes/controls/locationpanel.py +++ b/fsl/fsleyes/controls/locationpanel.py @@ -4,17 +4,11 @@ # # Author: Paul McCarthy <pauldmccarthy@gmail.com> # -"""This module provides the :class:`LocationPanel` class, a panel which -displays controls allowing the user to change the currently displayed location -in both world and local coordinates, both in the space of the currently -selected overlay. - -These changes are propagated to the current display coordinate system -location, managed by the display context (and external changes to the display -context location are propagated back to the local/world location properties -managed by a :class:`LocationPanel`). +"""This module provides the :class:`LocationPanel` class, a *FSLeyes control* +panel which shows information about the current display location. """ + import logging import wx @@ -37,24 +31,69 @@ log = logging.getLogger(__name__) class LocationPanel(fslpanel.FSLEyesPanel): - """ - A wx.Panel which displays information about the current location, - for each overlay in the overlay list. + """The ``LocationPanel`` is a panel which contains controls allowing the + user to view and modify the :attr:`.DisplayContext.location` property. A + ``LocationPanel`` is intended to be contained within a + :class:`.CanvasPanel`, and looks something like this: + + .. image:: images/locationpanel.png + :scale: 50% + :align: center + + + The ``LocationPanel`` contains two main sections: + + - A collection of controls which show the current + :attr:`.DisplayContext.location` + + - A ``wx.html.HtmlWindow`` which displays information about the current + :attr:`.DisplayContext.location` for all overlays in the + :class:`.OverlayList`. + + + **NIFTI overlays** + + + The ``LocationPanel`` is primarily designed to work with :class:`.Image` + overlays. If the :attr:`.DisplayContext.selectedOverlay` is an + :class:`.Image`, or has an associated reference image (see the + :meth:`.DisplayOpts.getReferenceImage` method), the ``LocationPanel`` + will display the current :class:`.DisplayContext.location` in both the + the voxel coordinates and world coordinates of the ``Image`` instance. + + + **Other overlays** + + + If the :attr:`.DisplayContext.selectedOverlay` is not an :class:`.Image`, + or does not have an associated reference image, the ``LocationPanel`` will + display the current :attr:`.DisplayContext.location` as-is (i.e. in the + display coordinate system); furthermore, the voxel location controls will + be disabled. """ voxelLocation = props.Point(ndims=3, real=False) - """If the currently selected overlay is a :class:`.Image`, this property - tracks the current display location in voxel coordinates. + """If the currently selected overlay is a :class:`.Image` instance , this + property tracks the current :attr:`.DisplayContext.location` in voxel + coordinates. """ + worldLocation = props.Point(ndims=3, real=True) + """For :class:`.Image` overlays, this property tracks the current + :attr:`.DisplayContext.location` in the image world coordinates. For other + overlay types, this property tracks the current location in display + coordinates. + """ def __init__(self, parent, overlayList, displayCtx): - """ - Creates and lays out the LocationPanel, and sets up a few property - event listeners. + """Creat a ``LocationPanel``. + + :arg parent: The :mod:`wx` parent object. + :arg overlayList: The :class:`.OverlayList` instance. + :arg displayCtx: The :class:`.DisplayContext` instance. """ fslpanel.FSLEyesPanel.__init__(self, parent, overlayList, displayCtx) @@ -68,7 +107,7 @@ class LocationPanel(fslpanel.FSLEyesPanel): # When the current overlay is either an Image instance, or has # an associated reference image, this attributes is used to # store a reference to the image. - self._refImage = None + self.__refImage = None # When the currently selected overlay is 4D, # this attribute will refer to the @@ -76,27 +115,27 @@ class LocationPanel(fslpanel.FSLEyesPanel): # has a volume property that controls the # volume - see e.g. the ImageOpts class. This # attribute is set in _selectedOverlayChanged. - self.volumeTarget = None + self.__volumeTarget = None - self.column1 = wx.Panel(self) - self.column2 = wx.Panel(self) - self.info = wxhtml.HtmlWindow(self) + self.__column1 = wx.Panel(self) + self.__column2 = wx.Panel(self) + self.__info = wxhtml.HtmlWindow(self) # HTMLWindow does not use # the parent font by default, # so we force it to at least # have the parent font size - self.info.SetStandardFonts(self.GetFont().GetPointSize()) + self.__info.SetStandardFonts(self.GetFont().GetPointSize()) - self.worldLabel = wx.StaticText( - self.column1, label=strings.labels[self, 'worldLocation']) - self.volumeLabel = wx.StaticText( - self.column1, label=strings.labels[self, 'volume']) - self.voxelLabel = wx.StaticText( - self.column2, label=strings.labels[self, 'voxelLocation']) + self.__worldLabel = wx.StaticText( + self.__column1, label=strings.labels[self, 'worldLocation']) + self.__volumeLabel = wx.StaticText( + self.__column1, label=strings.labels[self, 'volume']) + self.__voxelLabel = wx.StaticText( + self.__column2, label=strings.labels[self, 'voxelLocation']) worldX, worldY, worldZ = props.makeListWidgets( - self.column1, + self.__column1, self, 'worldLocation', slider=False, @@ -105,7 +144,7 @@ class LocationPanel(fslpanel.FSLEyesPanel): mousewheel=True) voxelX, voxelY, voxelZ = props.makeListWidgets( - self.column2, + self.__column2, self, 'voxelLocation', slider=False, @@ -113,69 +152,82 @@ class LocationPanel(fslpanel.FSLEyesPanel): showLimits=False, mousewheel=True) - self.worldX = worldX - self.worldY = worldY - self.worldZ = worldZ - self.voxelX = voxelX - self.voxelY = voxelY - self.voxelZ = voxelZ - self.volume = floatspin.FloatSpinCtrl( - self.column2, + self.__worldX = worldX + self.__worldY = worldY + self.__worldZ = worldZ + self.__voxelX = voxelX + self.__voxelY = voxelY + self.__voxelZ = voxelZ + self.__volume = floatspin.FloatSpinCtrl( + self.__column2, style=floatspin.FSC_MOUSEWHEEL | floatspin.FSC_INTEGER) - self.column1Sizer = wx.BoxSizer(wx.VERTICAL) - self.column2Sizer = wx.BoxSizer(wx.VERTICAL) - self.sizer = wx.BoxSizer(wx.HORIZONTAL) - - self.column1Sizer.Add(self.worldLabel, flag=wx.EXPAND) - self.column1Sizer.Add(self.worldX, flag=wx.EXPAND) - self.column1Sizer.Add(self.worldY, flag=wx.EXPAND) - self.column1Sizer.Add(self.worldZ, flag=wx.EXPAND) - self.column1Sizer.Add(self.volumeLabel, flag=wx.ALIGN_RIGHT) - - self.column2Sizer.Add(self.voxelLabel, flag=wx.EXPAND) - self.column2Sizer.Add(self.voxelX, flag=wx.EXPAND) - self.column2Sizer.Add(self.voxelY, flag=wx.EXPAND) - self.column2Sizer.Add(self.voxelZ, flag=wx.EXPAND) - self.column2Sizer.Add(self.volume, flag=wx.EXPAND) + self.__column1Sizer = wx.BoxSizer(wx.VERTICAL) + self.__column2Sizer = wx.BoxSizer(wx.VERTICAL) + self.__sizer = wx.BoxSizer(wx.HORIZONTAL) + + self.__column1Sizer.Add(self.__worldLabel, flag=wx.EXPAND) + self.__column1Sizer.Add(self.__worldX, flag=wx.EXPAND) + self.__column1Sizer.Add(self.__worldY, flag=wx.EXPAND) + self.__column1Sizer.Add(self.__worldZ, flag=wx.EXPAND) + self.__column1Sizer.Add(self.__volumeLabel, flag=wx.ALIGN_RIGHT) + + self.__column2Sizer.Add(self.__voxelLabel, flag=wx.EXPAND) + self.__column2Sizer.Add(self.__voxelX, flag=wx.EXPAND) + self.__column2Sizer.Add(self.__voxelY, flag=wx.EXPAND) + self.__column2Sizer.Add(self.__voxelZ, flag=wx.EXPAND) + self.__column2Sizer.Add(self.__volume, flag=wx.EXPAND) - self.sizer.Add(self.column1, flag=wx.EXPAND) - self.sizer.Add((5, -1)) - self.sizer.Add(self.column2, flag=wx.EXPAND) - self.sizer.Add((5, -1)) - self.sizer.Add(self.info, flag=wx.EXPAND, proportion=1) - - self.column1.SetSizer(self.column1Sizer) - self.column2.SetSizer(self.column2Sizer) - self .SetSizer(self.sizer) + self.__sizer.Add(self.__column1, flag=wx.EXPAND) + self.__sizer.Add((5, -1)) + self.__sizer.Add(self.__column2, flag=wx.EXPAND) + self.__sizer.Add((5, -1)) + self.__sizer.Add(self.__info, flag=wx.EXPAND, proportion=1) + + self.__column1.SetSizer(self.__column1Sizer) + self.__column2.SetSizer(self.__column2Sizer) + self .SetSizer(self.__sizer) self._overlayList.addListener('overlays', self._name, - self._selectedOverlayChanged) + self.__selectedOverlayChanged) self._displayCtx .addListener('selectedOverlay', self._name, - self._selectedOverlayChanged) + self.__selectedOverlayChanged) self._displayCtx .addListener('location', self._name, - self._displayLocationChanged) + self.__displayLocationChanged) self.addListener( 'voxelLocation', self._name, - self._voxelLocationChanged) + self.__voxelLocationChanged) self.addListener( 'worldLocation', self._name, - self._worldLocationChanged) + self.__worldLocationChanged) - self._selectedOverlayChanged() + self.__selectedOverlayChanged() - self.worldLabel.SetMinSize(self.__calcWorldLabelMinSize()) - self.info .SetMinSize((150, 100)) + self.__worldLabel.SetMinSize(self.__calcWorldLabelMinSize()) + self.__info .SetMinSize((150, 100)) self.Layout() - self.SetMinSize(self.sizer.GetMinSize()) + self.SetMinSize(self.__sizer.GetMinSize()) + + + def destroy(self): + """Must be called when this ``LocationPanel`` is no longer needed. + Removes property listeners and calls :meth:`.FSLEyesPanel.destroy`. + """ + + self._overlayList.removeListener('overlays', self._name) + self._displayCtx .removeListener('selectedOverlay', self._name) + self._displayCtx .removeListener('location', self._name) + + fslpanel.FSLEyesPanel.destroy(self) def __calcWorldLabelMinSize(self): """Calculates the minimum size that the world label (the label which shows the coordinate space of the currently selected overlay) needs. + Called by the :meth:`__init__` method. The world label displays different things depending on the currently selected overlay. But we want it to be a fixed size. So this method @@ -184,7 +236,7 @@ class LocationPanel(fslpanel.FSLEyesPanel): minimum size for the world label. """ - dc = wx.ClientDC(self.worldLabel) + dc = wx.ClientDC(self.__worldLabel) width, height = 0, 0 @@ -217,33 +269,24 @@ class LocationPanel(fslpanel.FSLEyesPanel): return width + 5, height + 5 - - def destroy(self): - """Deregisters property listeners.""" - - self._overlayList.removeListener('overlays', self._name) - self._displayCtx .removeListener('selectedOverlay', self._name) - self._displayCtx .removeListener('location', self._name) - - fslpanel.FSLEyesPanel.destroy(self) - - def _selectedOverlayChanged(self, *a): - """Called when the selected overlay is changed. Updates the voxel label - (which contains the overlay name), and sets the voxel location limits. + def __selectedOverlayChanged(self, *a): + """Called when the :attr:`.DisplayContext.selectedOverlay` or + :class:`.OverlayList` is changed. Refreshes the ``LocationPanel`` + interface accordingly. """ - self._updateReferenceImage() - self._updateWidgets() + self.__updateReferenceImage() + self.__updateWidgets() if len(self._overlayList) == 0: - self._updateLocationInfo() + self.__updateLocationInfo() return # Register a listener on the DisplayOpts # instance of the currently selected overlay, # so we can update the location if the - # overlay transforms/reference image change + # overlay bounds change. overlay = self._displayCtx.getSelectedOverlay() for ovl in self._overlayList: display = self._displayCtx.getDisplay(ovl) @@ -252,31 +295,32 @@ class LocationPanel(fslpanel.FSLEyesPanel): if ovl is overlay: opts.addListener('bounds', self._name, - self._overlayBoundsChanged, + self.__overlayBoundsChanged, overwrite=True) else: opts.removeListener('bounds', self._name) # Refresh the world/voxel location properties - self._displayLocationChanged() + self.__displayLocationChanged() - def _overlayBoundsChanged(self, *a): + def __overlayBoundsChanged(self, *a): + """Called when the :attr:`.DisplayOpts.bounds` property associated + with the currently selected overlay changes. Updates the + ``LocationPanel`` interface accordingly. + """ - self._updateReferenceImage() - self._updateWidgets() - self._displayLocationChanged() + self.__updateReferenceImage() + self.__updateWidgets() + self.__displayLocationChanged() - def _updateReferenceImage(self): - """Called by the :meth:`_selectedOverlayChanged` and - :meth:`_overlayOptsChanged` methods. Looks at the currently selected - overlay, and figures out if there is a reference image that can be - used to transform between display, world, and voxel coordinate - systems. - - Returns ``True`` if the reference image has changed from its - previous value, ``False`` otherwise. + def __updateReferenceImage(self): + """Called by the :meth:`__selectedOverlayChanged` and + :meth:`__overlayBoundsChanged` methods. Looks at the currently + selected overlay, and figures out if there is a reference image + that can be used to transform between display, world, and voxel + coordinate systems. """ refImage = None @@ -292,19 +336,24 @@ class LocationPanel(fslpanel.FSLEyesPanel): log.debug('Reference image for overlay {}: {}'.format( overlay, refImage)) - self._refImage = refImage + self.__refImage = refImage - def _updateWidgets(self): + def __updateWidgets(self): + """Called by the :meth:`__selectedOverlayChanged` and + :meth:`__overlayBoundsChanged` methods. Enables/disables the + voxel/world location and volume controls depending on the currently + selected overlay (or reference image). + """ - refImage = self._refImage + refImage = self.__refImage haveRef = refImage is not None - self.voxelX .Enable(haveRef) - self.voxelY .Enable(haveRef) - self.voxelZ .Enable(haveRef) - self.voxelLabel .Enable(haveRef) + self.__voxelX .Enable(haveRef) + self.__voxelY .Enable(haveRef) + self.__voxelZ .Enable(haveRef) + self.__voxelLabel .Enable(haveRef) ###################### # World location label @@ -319,7 +368,7 @@ class LocationPanel(fslpanel.FSLEyesPanel): 'worldLocation', 'unknown'] - self.worldLabel.SetLabel(label) + self.__worldLabel.SetLabel(label) #################################### # Voxel/world location widget limits @@ -327,10 +376,10 @@ class LocationPanel(fslpanel.FSLEyesPanel): # Figure out the limits for the # voxel/world location widgets - if self._refImage is not None: - opts = self._displayCtx.getOpts(self._refImage) + if haveRef: + opts = self._displayCtx.getOpts(refImage) v2w = opts.getTransform('voxel', 'world') - shape = self._refImage.shape[:3] + shape = refImage.shape[:3] vlo = [0, 0, 0] vhi = np.array(shape) - 1 wlo, whi = transform.axisBounds(shape, v2w) @@ -363,15 +412,15 @@ class LocationPanel(fslpanel.FSLEyesPanel): # Unbind any listeners between the previous # reference image and the volume widget - if self.volumeTarget is not None: - props.unbindWidget(self.volume, - self.volumeTarget, + if self.__volumeTarget is not None: + props.unbindWidget(self.__volume, + self.__volumeTarget, 'volume', floatspin.EVT_FLOATSPIN) - self.volumeTarget = None - self.volume.SetValue(0) - self.volume.SetRange(0, 0) + self.__volumeTarget = None + self.__volume.SetValue(0) + self.__volume.SetRange(0, 0) # Enable/disable the volume widget if the # overlay is a 4D image, and bind/unbind @@ -379,22 +428,86 @@ class LocationPanel(fslpanel.FSLEyesPanel): # the associated ImageOpts instance if haveRef and refImage.is4DImage(): opts = self._displayCtx.getOpts(refImage) - self.volumeTarget = opts + self.__volumeTarget = opts props.bindWidget( - self.volume, opts, 'volume', floatspin.EVT_FLOATSPIN) + self.__volume, opts, 'volume', floatspin.EVT_FLOATSPIN) - self.volume.SetRange(0, refImage.shape[3] - 1) - self.volume.SetValue(opts.volume) + self.__volume.SetRange(0, refImage.shape[3] - 1) + self.__volume.SetValue(opts.volume) - self.volume .Enable() - self.volumeLabel.Enable() + self.__volume .Enable() + self.__volumeLabel.Enable() else: - self.volume .Disable() - self.volumeLabel.Disable() + self.__volume .Disable() + self.__volumeLabel.Disable() - def _prePropagate(self): + def __displayLocationChanged(self, *a): + """Called when the :attr:`.DisplayContext.location` changes. + Propagates the change on to the :attr:`voxelLocation` + and :attr:`worldLocation` properties. + + .. note:: Because the :attr:`.DisplayContext.location`, + :attr:`voxelLocation` and :attr:`worldLocation` properties + are all linked through property listeners (see + :meth:`props.HasProperties.addListener`), we need to be a + bit careful to avoid circular updates. Therefore, each of + the :meth:`__displayLocationChanged`, + :meth:`__worldLocationChanged` and + :meth:`__voxelLocationChanged` methods use the + :meth:`__prePropagate`, :meth:`__propagate`, and + :meth:`__postPropagate` methods to propagate changes + between the three location properties. + """ + + if len(self._overlayList) == 0: return + + self.__prePropagate() + self.__propagate('display', 'voxel') + self.__propagate('display', 'world') + self.__postPropagate() + self.__updateLocationInfo() + + + def __worldLocationChanged(self, *a): + """Called when the :attr:`worldLocation` changes. Propagates the + change on to the :attr:`voxelLocation` and + :attr:`.DisplayContext.location` properties. + """ + + if len(self._overlayList) == 0: return + + self.__prePropagate() + self.__propagate('world', 'voxel') + self.__propagate('world', 'display') + self.__postPropagate() + self.__updateLocationInfo() + + + def __voxelLocationChanged(self, *a): + """Called when the :attr:`voxelLocation` changes. Propagates the + change on to the :attr:`worldLocation` and + :attr:`.DisplayContext.location` properties. + """ + + if len(self._overlayList) == 0: return + + self.__prePropagate() + self.__propagate('voxel', 'world') + self.__propagate('voxel', 'display') + self.__postPropagate() + self.__updateLocationInfo() + + + def __prePropagate(self): + """Called by the :meth:`__displayLocationChanged`, + :meth:`__worldLocationChanged` and :meth:`__voxelLocationChanged` + methods. + + Disables notification of all location property listeners, so + circular updates do not occur. + """ self .disableNotification('voxelLocation') self .disableNotification('worldLocation') @@ -403,14 +516,26 @@ class LocationPanel(fslpanel.FSLEyesPanel): self.Freeze() - def _propagate(self, source, target): + def __propagate(self, source, target): + """Called by the :meth:`__displayLocationChanged`, + :meth:`__worldLocationChanged` and :meth:`__voxelLocationChanged` + methods. Copies the coordinates from the ``source`` location to the + ``target`` location. Valid values for the ``source`` and ``target`` + are: + + =========== ============================================== + ``display`` The :attr:`.DisplayContext.location` property. + ``voxel`` The :attr:`voxelLocation` property. + ``world`` The :attr:`worldLocation` property. + =========== ============================================== + """ if source == 'display': coords = self._displayCtx.location.xyz elif source == 'voxel': coords = self.voxelLocation.xyz elif source == 'world': coords = self.worldLocation.xyz - if self._refImage is not None: - opts = self._displayCtx.getOpts(self._refImage) + if self.__refImage is not None: + opts = self._displayCtx.getOpts(self.__refImage) xformed = opts.transformCoords([coords], source, target)[0] else: xformed = coords @@ -423,7 +548,14 @@ class LocationPanel(fslpanel.FSLEyesPanel): elif target == 'world': self.worldLocation.xyz = xformed - def _postPropagate(self): + def __postPropagate(self): + """Called by the :meth:`__displayLocationChanged`, + :meth:`__worldLocationChanged` and :meth:`__voxelLocationChanged` + methods. + + Re-enables the property listeners that were disabled by the + :meth:`__postPropagate` method. + """ self .enableNotification('voxelLocation') self .enableNotification('worldLocation') self._displayCtx.enableListener( 'location', self._name) @@ -432,48 +564,15 @@ class LocationPanel(fslpanel.FSLEyesPanel): self.Refresh() self.Update() - - def _displayLocationChanged(self, *a): - """Called when the :attr:`.DisplayContext.location` changes. - Propagates the change on to the :attr:`voxelLocation` - and :attr:`worldLocation` properties. - """ - - if len(self._overlayList) == 0: return - - self._prePropagate() - self._propagate('display', 'voxel') - self._propagate('display', 'world') - self._postPropagate() - self._updateLocationInfo() - - - def _worldLocationChanged(self, *a): - - if len(self._overlayList) == 0: return - - self._prePropagate() - self._propagate('world', 'voxel') - self._propagate('world', 'display') - self._postPropagate() - self._updateLocationInfo() - - - def _voxelLocationChanged(self, *a): - - if len(self._overlayList) == 0: return - - self._prePropagate() - self._propagate('voxel', 'world') - self._propagate('voxel', 'display') - self._postPropagate() - self._updateLocationInfo() - - def _updateLocationInfo(self): + def __updateLocationInfo(self): + """Called whenever the :attr:`.DisplayContext.location` changes. + Updates the HTML panel which displays information about all overlays + in the :class:`.OverlayList`. + """ if len(self._overlayList) == 0: - self.info.SetPage('') + self.__info.SetPage('') return overlays = self._displayCtx.getOrderedOverlays() @@ -520,5 +619,5 @@ class LocationPanel(fslpanel.FSLEyesPanel): if info is not None: lines.append(info) - self.info.SetPage('<br>'.join(lines)) - self.info.Refresh() + self.__info.SetPage('<br>'.join(lines)) + self.__info.Refresh() diff --git a/fsl/fsleyes/controls/orthotoolbar.py b/fsl/fsleyes/controls/orthotoolbar.py index 7e5655dc84d2df1a720fb52748590892937b99d6..8ad584f39a032f7b5fd7c1b9913a0237314b95f3 100644 --- a/fsl/fsleyes/controls/orthotoolbar.py +++ b/fsl/fsleyes/controls/orthotoolbar.py @@ -1,9 +1,12 @@ #!/usr/bin/env python # -# orthotoolbar.py - +# orthotoolbar.py - The OrthoToolBar class. # # Author: Paul McCarthy <pauldmccarthy@gmail.com> # +"""This module provides the :class:`OrthoToolBar` class, which is a +:class:`.FSLEyesToolBar` for use with the :class:`.OrthoPanel`. +""" import props @@ -16,9 +19,40 @@ import fsl.data.strings as strings class OrthoToolBar(fsltoolbar.FSLEyesToolBar): + """The ``OrthoToolBar`` is a :class:`.FSLEyesToolBar` for use with the + :class:`.OrthoPanel`. An ``OrthoToolBar`` looks something like this: + + + .. image:: images/orthotoolbar.png + :scale: 50% + :align: center + + + The ``OrthoToolBar`` allows the user to control important parts of the + :class:`.OrthoPanel` display, and also to display a + :class:`.CanvasSettingsPanel`, which allows control over all aspects of + an ``OrthoPanel``. + + The ``OrthoToolBar`` contains controls which modify properties, or run + actions, defined on the following classes: + + .. autosummary:: + :nosignatures: + + ~fsl.fsleyes.views.orthopanel.OrthoPanel + ~fsl.fsleyes.displaycontext.orthoopts.OrthoOpts + ~fsl.fsleyes.profiles.orthoviewprofile.OrthoViewProfile + """ def __init__(self, parent, overlayList, displayCtx, ortho): + """Create an ``OrthoToolBar``. + + :arg parent: The :mod:`wx` parent object. + :arg overlayList: The :class:`.OverlayList` instance. + :arg displayCtx: The :class:`.DisplayContext` instance. + :arg ortho: The :class:`.OrthoPanel` instance. + """ actionz = {'more' : self.showMoreSettings} @@ -39,6 +73,11 @@ class OrthoToolBar(fsltoolbar.FSLEyesToolBar): def __makeTools(self, *a): + """Called by :meth:`__init__`, and whenever the + :attr:`.ViewPanel.profile` property changes. + + Re-creates all tools shown on this ``OrthoToolBar``. + """ ortho = self.orthoPanel orthoOpts = ortho.getSceneOptions() @@ -139,6 +178,13 @@ class OrthoToolBar(fsltoolbar.FSLEyesToolBar): def showMoreSettings(self, *a): + """Opens a :class:`.CanvasSettingsPanel` for the + :class:`.OrthoPanel` that owns this ``OrthoToolBar``. + + The ``CanvasSettingsPanel`` is opened as a floating pane - see the + :meth:`.ViewPanel.togglePanel` method. + """ + import canvassettingspanel self.orthoPanel.togglePanel(canvassettingspanel.CanvasSettingsPanel, self.orthoPanel,