From c20f9c216b69a3cd8655f9e6252ac52d09afebe6 Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauld.mccarthy@gmail.com>
Date: Thu, 24 Sep 2015 15:58:34 +0930
Subject: [PATCH] Started documenting SliceCanvas class. A few minor doco fixes
 elsewhere.

---
 fsl/fsleyes/gl/__init__.py          |   4 +-
 fsl/fsleyes/gl/globject.py          |   4 +-
 fsl/fsleyes/gl/slicecanvas.py       | 359 ++++++++++++++++++----------
 fsl/fsleyes/views/colourbarpanel.py | 145 ++++++-----
 4 files changed, 321 insertions(+), 191 deletions(-)

diff --git a/fsl/fsleyes/gl/__init__.py b/fsl/fsleyes/gl/__init__.py
index e6480376e..bfd07005d 100644
--- a/fsl/fsleyes/gl/__init__.py
+++ b/fsl/fsleyes/gl/__init__.py
@@ -124,7 +124,7 @@ as:
    ~fsl.fsleyes.gl.glrgbvector.GLRGBVector
    ~fsl.fsleyes.gl.glmodel.GLModel
 
-These objects are created and destroyed automatically by :class:`.SliceCanvas
+These objects are created and destroyed automatically by :class:`.SliceCanvas`
 instances, so application code does not need to worry about them too much.
 
 
@@ -525,7 +525,7 @@ class OSMesaCanvasTarget(object):
 
         
     def _postDraw(self):
-        """Does nothing, see :method:`_refresh`."""
+        """Does nothing, see :meth:`_refresh`."""
         pass
 
 
diff --git a/fsl/fsleyes/gl/globject.py b/fsl/fsleyes/gl/globject.py
index c31ce0d7e..210f7a8fb 100644
--- a/fsl/fsleyes/gl/globject.py
+++ b/fsl/fsleyes/gl/globject.py
@@ -117,7 +117,7 @@ class GLObject(object):
           postDraw
 
     Alternately, a sub-class could derive from one of the following classes,
-    instead of deriving directly from the ``GLObject` class:
+    instead of deriving directly from the ``GLObject`` class:
 
     .. autosummary::
        :nosignatures:
@@ -306,7 +306,7 @@ class GLSimpleObject(GLObject):
 
 
 class GLImageObject(GLObject):
-    """The ``GLImageObject` class is the base class for all GL representations
+    """The ``GLImageObject`` class is the base class for all GL representations
     of :class:`.Image` instances.
     """
     
diff --git a/fsl/fsleyes/gl/slicecanvas.py b/fsl/fsleyes/gl/slicecanvas.py
index bce0de051..e65c53fc4 100644
--- a/fsl/fsleyes/gl/slicecanvas.py
+++ b/fsl/fsleyes/gl/slicecanvas.py
@@ -1,24 +1,14 @@
 #!/usr/bin/env python
 #
-# slicecanvas.py - Provides the SliceCanvas class, which contains the
-# functionality to display a single slice from a collection of 3D overlays.
+# slicecanvas.py - The SliceCanvas class.
 #
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
-"""Provides the :class:`SliceCanvas` class, which contains the functionality
-to display a single slice from a collection of 3D overlays.
-
-The :class:`SliceCanvas` class is not intended to be instantiated - use one
-of the subclasses:
-
-  - :class:`.OSMesaSliceCanvas` for static off-screen rendering of a scene.
-    
-  - :class:`.WXGLSliceCanvas` for interactive rendering on a
-    :class:`wx.glcanvas.GLCanvas` canvas.
-
-See also the :class:`.LightBoxCanvas` class.
+"""This module provides the :class:`SliceCanvas` class, which contains the
+functionality to display a 2D slice from a collection of 3D overlays.
 """
 
+
 import copy
 import logging
 
@@ -40,10 +30,122 @@ log = logging.getLogger(__name__)
 
 
 class SliceCanvas(props.HasProperties):
-    """Represens a canvas which may be used to display a single 2D slice from a
-    collection of 3D overlays.
+    """The ``SliceCanvas`` represens a canvas which may be used to display a
+    single 2D slice from a collection of 3D overlays.  See also the
+    :class:`.LightBoxCanvas`, a sub-class of ``SliceCanvas``.
+
+
+    .. note:: The :class:`SliceCanvas` class is not intended to be instantiated
+              directly - use one of these subclasses, depending on your
+              use-case:
+
+               - :class:`.OSMesaSliceCanvas` for static off-screen rendering of
+                 a scene using OSMesa.
+    
+               - :class:`.WXGLSliceCanvas` for interactive rendering on a
+                 :class:`wx.glcanvas.GLCanvas` canvas.
+
+
+    The ``SliceCanvas`` derives from the :class:`.props.HasProperties` class.
+    The settings, and current scene displayed on a ``SliceCanvas`` instance,
+    can be changed through the properties of the ``SliceCanvas``. All of these
+    properties are defined in the :class:`.SliceCanvasOpts` class.
+
+
+    **GL objects**
+
+
+    The ``SliceCanvas`` draws :class:`.GLObject` instances. When created, a
+    ``SliceCanvas`` creates a :class:`.GLObject` instance for every overlay in
+    the :class:`.OverlayList`. When an overlay is added or removed, it
+    creates/destroys ``GLObject`` instances accordingly.  Furthermore,
+    whenever the :class:`.Display.overlayType` for an existing overlay
+    changes, the ``SliceCanvas`` destroys the old ``GLObject`` associated with
+    the overlay, and creates a new one.
+
+
+    The ``SliceCanvas`` also uses an :class:`.Annotations` instance, for
+    drawing simple annotations on top of the overlays.  This ``Annotations``
+    instance can be accessed with the :meth:`getAnnotations` method.
+
+
+    **Performance optimisations**
+
+    
+    The :attr:`renderMode`, :attr:`softwareMode`, and :attr:`resolutionLimit`
+    properties control various ``SliceCanvas`` performance settings, which can
+    be useful when running in a low performance environment (e.g. when only a
+    software based GL driver is available). See also the
+    :attr:`.SceneOpts.performance` setting.
+
+    
+    The :attr:`resolutionLimit` property controls the highest resolution at
+    which :class:`.Image` overlays are displayed on the ``SliceCanvas``. A
+    higher value will result in faster rendering performance. When this
+    property is changed, the :attr:`.ImageOpts.resolution` property for every
+    :class:`.Image` overlay is updated.
+
+
+    The :attr:`softwareMode` property controls the OpenGL shader program that
+    is used to render overlays - several :class:`.GLObject` types have shader
+    programs which are optimised for low-performance environments (at the cost
+    of a reduced feature set). This property is linked to the
+    :attr:`.Display.softwareMode` property.
+
+
+    The :attr:`renderMode` property controls the way in which the
+    ``SliceCanas`` renders :class:`.GLObject` instances. It has three
+    settings:
+
+
+    ============= ============================================================
+    ``onscreen``  ``GLObject`` instances are rendered directly to the canvas.
+    
+    ``offscreen`` ``GLObject`` instances are rendered off-screen to a fixed
+                  size 2D texture (a :class:`.RenderTexture`). This texture
+                  is then rendered to the canvas. One :class:`.RenderTexture`
+                  is used for every overlay  in the :class:`.OverlayList`.
+    
+    ``prerender`` A stack of 2D slices for every ``GLObject`` instance is
+                  pre-generated off-screen, and cached, using a
+                  :class:`.RenderTextureStack`. When the ``SliceCanvas`` needs
+                  to display a particular Z location, it retrieves the
+                  appropriate slice from the stack, and renders it to the
+                  canvas. One :class:`.RenderTextureStack` is used for every
+                  overlay in the :class:`.OverlayList`.
+    ============= ============================================================
+                  
+
+    **Attributes and methods**
+
+    
+    The following attributes are available on a ``SliceCanvas``:
+
+
+    =============== ==========================================
+    ``xax``         Index of the horizontal screen axis
+    ``yax``         Index of the horizontal screen axis
+    ``zax``         Index of the horizontal screen axis
+    ``name``        A unique name for this ``SliceCanvas``
+    ``overlayList`` Reference to the :class:`.OverlayList`.
+    ``displayCtx``  Reference to the :class:`.DisplayContext`.
+    =============== ==========================================
+
+    
+    The following convenience methods are available on a ``SliceCanvas``:
+
+    .. autosummary::
+       :nosignatures:
+    
+       calcPixelDims
+       canvasToWorld
+       panDisplayBy
+       centreDisplayAt
+       panDisplayToShow
+       getAnnotations
     """
 
+    
     pos             = copy.copy(canvasopts.SliceCanvasOpts.pos)
     zoom            = copy.copy(canvasopts.SliceCanvasOpts.zoom)
     displayBounds   = copy.copy(canvasopts.SliceCanvasOpts.displayBounds)
@@ -57,6 +159,120 @@ class SliceCanvas(props.HasProperties):
     softwareMode    = copy.copy(canvasopts.SliceCanvasOpts.softwareMode)
     resolutionLimit = copy.copy(canvasopts.SliceCanvasOpts.resolutionLimit)
     
+        
+    def __init__(self, overlayList, displayCtx, zax=0):
+        """Create a ``SliceCanvas``. 
+
+        :arg overlayList: An :class:`.OverlayList` object containing a
+                          collection of overlays to be displayed.
+        
+        :arg displayCtx:  A :class:`.DisplayContext` object which describes
+                          how the overlays should be displayed.
+        
+        :arg zax:         Display coordinate system axis perpendicular to the
+                          plane to be displayed (the *depth* axis), default 0.
+        """
+
+        props.HasProperties.__init__(self)
+
+        self.overlayList = overlayList
+        self.displayCtx  = displayCtx
+        self.name        = '{}_{}'.format(self.__class__.__name__, id(self))
+
+        # A GLObject instance is created for
+        # every overlay in the overlay list,
+        # and stored in this dictionary
+        self._glObjects = {}
+
+        # If render mode is offscren or prerender, these
+        # dictionaries will contain a RenderTexture or
+        # RenderTextureStack instance for each overlay in
+        # the overlay list
+        self._offscreenTextures = {}
+        self._prerenderTextures = {}
+
+        # The zax property is the image axis which maps to the
+        # 'depth' axis of this canvas. The _zAxisChanged method
+        # also fixes the values of 'xax' and 'yax'.
+        self.zax = zax
+        self.xax = (zax + 1) % 3
+        self.yax = (zax + 2) % 3
+
+        self._annotations = annotations.Annotations(self.xax, self.yax)
+        self._zAxisChanged() 
+
+        # when any of the properties of this
+        # canvas change, we need to redraw
+        self.addListener('zax',           self.name, self._zAxisChanged)
+        self.addListener('pos',           self.name, self._draw)
+        self.addListener('displayBounds', self.name, self._draw)
+        self.addListener('bgColour',      self.name, self._draw)
+        self.addListener('cursorColour',  self.name, self._draw)
+        self.addListener('showCursor',    self.name, self._draw)
+        self.addListener('invertX',       self.name, self._draw)
+        self.addListener('invertY',       self.name, self._draw)
+        self.addListener('zoom',          self.name, self._zoomChanged)
+        self.addListener('renderMode',    self.name, self._renderModeChange)
+        self.addListener('resolutionLimit',
+                         self.name,
+                         self._resolutionLimitChange) 
+        
+        # When the overlay list changes, refresh the
+        # display, and update the display bounds
+        self.overlayList.addListener('overlays',
+                                     self.name,
+                                     self._overlayListChanged)
+        self.displayCtx .addListener('overlayOrder',
+                                     self.name,
+                                     self._refresh) 
+        self.displayCtx .addListener('bounds',
+                                     self.name,
+                                     self._overlayBoundsChanged)
+
+
+    def destroy(self):
+        """This method must be called when this ``SliceCanvas`` is no longer
+        being used.
+
+        It removes listeners from all :class:`.OverlayList`,
+        :class:`.DisplayContext`, and :class:`.Display` instances, and
+        destroys OpenGL representations of all overlays.
+        """
+        self.removeListener('zax',           self.name)
+        self.removeListener('pos',           self.name)
+        self.removeListener('displayBounds', self.name)
+        self.removeListener('showCursor',    self.name)
+        self.removeListener('invertX',       self.name)
+        self.removeListener('invertY',       self.name)
+        self.removeListener('zoom',          self.name)
+        self.removeListener('renderMode',    self.name)
+
+        self.overlayList.removeListener('overlays',     self.name)
+        self.displayCtx .removeListener('bounds',       self.name)
+        self.displayCtx .removeListener('overlayOrder', self.name)
+
+        for overlay in self.overlayList:
+            disp  = self.displayCtx.getDisplay(overlay)
+            globj = self._glObjects[overlay]
+
+            disp.removeListener('overlayType',  self.name)
+            disp.removeListener('enabled',      self.name)
+            disp.unbindProps(   'softwareMode', self)
+
+            globj.destroy()
+
+            rt, rtName = self._prerenderTextures.get(overlay, (None, None))
+            ot         = self._offscreenTextures.get(overlay, None)
+
+            if rt is not None: glresources.delete(rtName)
+            if ot is not None: ot         .destroy()
+
+        self.overlayList        = None
+        self.displayCtx         = None
+        self._glObjects         = None
+        self._prerenderTextures = None
+        self._offscreenTextures = None
+
 
     def calcPixelDims(self):
         """Calculate and return the approximate size (width, height) of one
@@ -187,117 +403,6 @@ class SliceCanvas(props.HasProperties):
         annotate the canvas.
         """
         return self._annotations
-
-        
-    def __init__(self, overlayList, displayCtx, zax=0):
-        """Creates a canvas object. 
-
-        :arg overlayList: An :class:`.OverlayList` object containing a
-                          collection of overlays to be displayed.
-        
-        :arg displayCtx:  A :class:`.DisplayContext` object which describes
-                          how the overlays should be displayed.
-        
-        :arg zax:        Display coordinate system axis perpendicular to the
-                         plane to be displayed (the 'depth' axis), default 0.
-        """
-
-        props.HasProperties.__init__(self)
-
-        self.overlayList = overlayList
-        self.displayCtx  = displayCtx
-        self.name        = '{}_{}'.format(self.__class__.__name__, id(self))
-
-        # A GLObject instance is created for
-        # every overlay in the overlay list,
-        # and stored in this dictionary
-        self._glObjects = {}
-
-        # If render mode is offscren or prerender, these
-        # dictionaries will contain a RenderTexture or
-        # RenderTextureStack instance for each overlay in
-        # the overlay list
-        self._offscreenTextures = {}
-        self._prerenderTextures = {}
-
-        # The zax property is the image axis which maps to the
-        # 'depth' axis of this canvas. The _zAxisChanged method
-        # also fixes the values of 'xax' and 'yax'.
-        self.zax = zax
-        self.xax = (zax + 1) % 3
-        self.yax = (zax + 2) % 3
-
-        self._annotations = annotations.Annotations(self.xax, self.yax)
-        self._zAxisChanged() 
-
-        # when any of the properties of this
-        # canvas change, we need to redraw
-        self.addListener('zax',           self.name, self._zAxisChanged)
-        self.addListener('pos',           self.name, self._draw)
-        self.addListener('displayBounds', self.name, self._draw)
-        self.addListener('bgColour',      self.name, self._draw)
-        self.addListener('cursorColour',  self.name, self._draw)
-        self.addListener('showCursor',    self.name, self._draw)
-        self.addListener('invertX',       self.name, self._draw)
-        self.addListener('invertY',       self.name, self._draw)
-        self.addListener('zoom',          self.name, self._zoomChanged)
-        self.addListener('renderMode',    self.name, self._renderModeChange)
-        self.addListener('resolutionLimit',
-                         self.name,
-                         self._resolutionLimitChange) 
-        
-        # When the overlay list changes, refresh the
-        # display, and update the display bounds
-        self.overlayList.addListener('overlays',
-                                     self.name,
-                                     self._overlayListChanged)
-        self.displayCtx .addListener('overlayOrder',
-                                     self.name,
-                                     self._refresh) 
-        self.displayCtx .addListener('bounds',
-                                     self.name,
-                                     self._overlayBoundsChanged)
-
-
-    def destroy(self):
-        """This method must be called when this ``SliceCanvas`` is no longer
-        being used.
-
-        It removes listeners from all :class:`.OverlayList`,
-        :class:`.DisplayContext`, and :class:`.Display` instances, and
-        destroys OpenGL representations of all overlays.
-        """
-        self.removeListener('zax',           self.name)
-        self.removeListener('pos',           self.name)
-        self.removeListener('displayBounds', self.name)
-        self.removeListener('showCursor',    self.name)
-        self.removeListener('invertX',       self.name)
-        self.removeListener('invertY',       self.name)
-        self.removeListener('zoom',          self.name)
-        self.removeListener('renderMode',    self.name)
-
-        self.overlayList.removeListener('overlays',     self.name)
-        self.displayCtx .removeListener('bounds',       self.name)
-        self.displayCtx .removeListener('overlayOrder', self.name)
-
-        for overlay in self.overlayList:
-            disp  = self.displayCtx.getDisplay(overlay)
-            globj = self._glObjects[overlay]
-
-            disp.removeListener('overlayType',  self.name)
-            disp.removeListener('enabled',      self.name)
-            disp.unbindProps(   'softwareMode', self)
-
-            globj.destroy()
-
-            rt, rtName = self._prerenderTextures.get(overlay, (None, None))
-            ot         = self._offscreenTextures.get(overlay, None)
-
-            if rt is not None: glresources.delete(rtName)
-            if ot is not None: ot         .destroy()
-
-        self.overlayList = None
-        self.displayCxt  = None
             
 
     def _initGL(self):
diff --git a/fsl/fsleyes/views/colourbarpanel.py b/fsl/fsleyes/views/colourbarpanel.py
index bec6a6d2e..6caafc1f2 100644
--- a/fsl/fsleyes/views/colourbarpanel.py
+++ b/fsl/fsleyes/views/colourbarpanel.py
@@ -1,17 +1,13 @@
 #!/usr/bin/env python
 #
-# colourbar.py - Provides the ColourBarPanel, a panel for displaying a colour
-#                bar.
+# colourbar.py - The ColourBarPanel.
 #
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
-"""A :class:`.FSLEyesPanel` which renders a colour bar depicting the colour
-range of the currently selected overlay (if applicable).
-
+"""This module provides the :class:`ColourBarPanel`, a :class:`.FSLEyesPanel`
+which renders a colour bar.
 """
 
-import logging
-log = logging.getLogger(__name__)
 
 import wx
 
@@ -23,17 +19,23 @@ import fsl.fsleyes.gl.wxglcolourbarcanvas     as cbarcanvas
 
 
 class ColourBarPanel(fslpanel.FSLEyesPanel):
-    """A panel which shows a colour bar, depicting the data range of the
-    currently selected overlay.
+    """The ``ColourBarPanel`` is a panel which shows a colour bar, depicting
+    the data range of the currently selected overlay (if applicable). A
+    :class:`.ColourBarCanvas` is used to render the colour bar.
+
+    
+    .. note:: Currently, the ``ColourBarPanel`` will only display a colour bar
+              for :class:`.Image` overlays which are being displayed with a
+              ``'volume'`` overlay type (see the :class:`.VolumeOpts` class).
     """
 
     
     orientation = cbarcanvas.WXGLColourBarCanvas.orientation
-    """Draw the colour bar horizontally or vertically. """
+    """Colour bar orientation - see :attr:`.ColourBarCanvas.orientation`. """
 
     
     labelSide   = cbarcanvas.WXGLColourBarCanvas.labelSide
-    """Draw colour bar labels on the top/left/right/bottom."""
+    """Colour bar label side - see :attr:`.ColourBarCanvas.labelSide`."""
                   
 
     def __init__(self,
@@ -41,52 +43,65 @@ class ColourBarPanel(fslpanel.FSLEyesPanel):
                  overlayList,
                  displayCtx,
                  orientation='horizontal'):
+        """Create a ``ColourBarPanel``.
+
+        :arg parent:      The :mod:`wx` parent object.
+        
+        :arg overlayList: The :class:`.OverlayList` instance.
+        
+        :arg displayCtx:  The :class:`.DisplayContext` instance.
+        
+        :arg orientation: Initial orientation - either ``'horizontal'`` (the
+                          default) or ``'vertical'``.
+        """
 
         fslpanel.FSLEyesPanel.__init__(self, parent, overlayList, displayCtx)
 
-        self._cbPanel = cbarcanvas.WXGLColourBarCanvas(self)
+        self.__cbPanel = cbarcanvas.WXGLColourBarCanvas(self)
 
-        self._sizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.SetSizer(self._sizer)
-        self._sizer.Add(self._cbPanel, flag=wx.EXPAND, proportion=1)
+        self.__sizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.SetSizer(self.__sizer)
+        self.__sizer.Add(self.__cbPanel, flag=wx.EXPAND, proportion=1)
 
-        self.bindProps('orientation', self._cbPanel)
-        self.bindProps('labelSide'  , self._cbPanel)
+        self.bindProps('orientation', self.__cbPanel)
+        self.bindProps('labelSide'  , self.__cbPanel)
 
         self.SetBackgroundColour('black')
 
-        self.addListener('orientation', self._name, self._layout)
+        self.addListener('orientation', self._name, self.__layout)
         
         self._overlayList.addListener('overlays',
                                       self._name,
-                                      self._selectedOverlayChanged)
+                                      self.__selectedOverlayChanged)
         self._displayCtx .addListener('selectedOverlay',
                                       self._name,
-                                      self._selectedOverlayChanged)
+                                      self.__selectedOverlayChanged)
 
-        self._selectedOverlay = None
+        self.__selectedOverlay = None
         
-        self._layout()
-        self._selectedOverlayChanged()
+        self.__layout()
+        self.__selectedOverlayChanged()
 
 
     def getCanvas(self):
         """Returns the :class:`.ColourBarCanvas` which displays the rendered
         colour bar.
         """
-        return self._cbPanel
+        return self.__cbPanel
 
 
     def destroy(self):
-        """Removes all registered listeners from the overlay list, display
-        context, and individual overlays.
+        """Must be called when this ``ColourBarPanel`` is no longer needed.
+
+        Removes all registered listeners from the :class:`.OverlayList`,
+        :class:`.DisplayContext`, and foom individual overlays.
         """
 
         
         self._overlayList.removeListener('overlays',        self._name)
         self._displayCtx .removeListener('selectedOverlay', self._name)
 
-        overlay = self._selectedOverlay
+        overlay = self.__selectedOverlay
 
         if overlay is not None:
             try:
@@ -101,29 +116,37 @@ class ColourBarPanel(fslpanel.FSLEyesPanel):
             except fsldc.InvalidOverlayError:
                 pass
 
-        self._cbPanel        .destroy()
+        self.__cbPanel       .destroy()
         fslpanel.FSLEyesPanel.destroy(self)
  
             
-    def _layout(self, *a):
-        """
+    def __layout(self, *a):
+        """Called when this ``ColourBarPanel`` needs to be laid out.
+        Sets the panel size, and calls the :meth:`__refreshColourBar` method.
         """
 
         # Fix the minor axis of the colour bar to 75 pixels
         if self.orientation == 'horizontal':
-            self._cbPanel.SetSizeHints(-1, 75, -1, 75, -1, -1)
+            self.__cbPanel.SetSizeHints(-1, 75, -1, 75, -1, -1)
         else:
-            self._cbPanel.SetSizeHints(75, -1, 75, -1, -1, -1)
+            self.__cbPanel.SetSizeHints(75, -1, 75, -1, -1, -1)
 
         self.Layout()
-        self._refreshColourBar()
+        self.__refreshColourBar()
                           
 
-    def _selectedOverlayChanged(self, *a):
-        """
+    def __selectedOverlayChanged(self, *a):
+        """Called when the :class:`.OverlayList` or the
+        :attr:`.DisplayContext.selectedOverlay` changes.
+        
+        If the newly selected overlay is an :class:`.Image` which is being
+        displayed as a ``'volume'``, registers some listeners on the
+        properties of the associated :class:`.Display` and
+        :class:`.VolumeOpts` instanaces, and refreshes the
+        :class:`.ColourBarCanvas`.
         """
 
-        overlay = self._selectedOverlay
+        overlay = self.__selectedOverlay
         
         if overlay is not None:
             try:
@@ -141,12 +164,12 @@ class ColourBarPanel(fslpanel.FSLEyesPanel):
             except fsldc.InvalidOverlayError:
                 pass
             
-        self._selectedOverlay = None
+        self.__selectedOverlay = None
             
         overlay = self._displayCtx.getSelectedOverlay()
  
         if overlay is None:
-            self._refreshColourBar()
+            self.__refreshColourBar()
             return
 
         display = self._displayCtx.getDisplay(overlay)
@@ -156,10 +179,10 @@ class ColourBarPanel(fslpanel.FSLEyesPanel):
         # TODO support for other types (where applicable)
         if not isinstance(overlay, fslimage.Image) or \
            not isinstance(opts,    volumeopts.VolumeOpts):
-            self._refreshColourBar()
+            self.__refreshColourBar()
             return
 
-        self._selectedOverlay = overlay
+        self.__selectedOverlay = overlay
 
         # TODO register on overlayType property, in
         # case the overlay type changes to a type
@@ -167,37 +190,40 @@ class ColourBarPanel(fslpanel.FSLEyesPanel):
 
         opts   .addListener('displayRange',
                             self._name,
-                            self._displayRangeChanged)
+                            self.__displayRangeChanged)
         opts   .addListener('cmap',
                             self._name,
-                            self._refreshColourBar)
+                            self.__refreshColourBar)
         display.addListener('name',
                             self._name,
-                            self._overlayNameChanged)
+                            self.__overlayNameChanged)
 
-        self._overlayNameChanged()
-        self._displayRangeChanged()
-        self._refreshColourBar()
+        self.__overlayNameChanged()
+        self.__displayRangeChanged()
+        self.__refreshColourBar()
 
 
-    def _overlayNameChanged(self, *a):
-        """
+    def __overlayNameChanged(self, *a):
+        """Called when the :attr:`.Display.name` of the currently selected
+        overlay changes. Updates the :attr:`.ColourBarCanvas.label`.
         """
 
-        if self._selectedOverlay is not None:
-            display = self._displayCtx.getDisplay(self._selectedOverlay)
+        if self.__selectedOverlay is not None:
+            display = self._displayCtx.getDisplay(self.__selectedOverlay)
             label   = display.name
         else:
             label = ''
             
-        self._cbPanel.label = label
+        self.__cbPanel.label = label
 
         
-    def _displayRangeChanged(self, *a):
-        """
+    def __displayRangeChanged(self, *a):
+        """Called when the :attr:`.VolumeOpts.displayRange` of the currently
+        selected overlay changes. Updates the :attr:`.ColourBarCanavs.vrange`
+        accordingly.
         """
 
-        overlay = self._selectedOverlay
+        overlay = self.__selectedOverlay
 
         if overlay is not None:
             
@@ -206,14 +232,13 @@ class ColourBarPanel(fslpanel.FSLEyesPanel):
         else:
             dmin, dmax = 0.0, 0.0
 
-        self._cbPanel.vrange.x = (dmin, dmax)
+        self.__cbPanel.vrange.x = (dmin, dmax)
 
 
-    def _refreshColourBar(self, *a):
-        """
-        """
+    def __refreshColourBar(self, *a):
+        """Called when the :class:`.ColourBarCanvas` needs to be refreshed. """
 
-        overlay = self._selectedOverlay
+        overlay = self.__selectedOverlay
 
         if overlay is not None:
             opts = self._displayCtx.getOpts(overlay)
@@ -221,4 +246,4 @@ class ColourBarPanel(fslpanel.FSLEyesPanel):
         else:
             cmap = None
 
-        self._cbPanel.cmap = cmap
+        self.__cbPanel.cmap = cmap
-- 
GitLab