From 08cbd7c841ce1cb4950753a097343cd0b9e6c905 Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauld.mccarthy@gmail.com>
Date: Fri, 4 Sep 2015 10:53:48 +0100
Subject: [PATCH] Documented widgets package. Currently, only the ImagePanel is
 actually being used. I'll keep the other things in, as I might use them in
 the future.

---
 doc/fsl.fsleyes.widgets.rst        | 13 -------
 fsl/fsleyes/widgets/__init__.py    | 15 ++++----
 fsl/fsleyes/widgets/imagepanel.py  | 42 +++++++++++++++++-----
 fsl/fsleyes/widgets/swappanel.py   | 42 +++++++++++++++++-----
 fsl/fsleyes/widgets/textpanel.py   | 57 +++++++++++++++++++-----------
 fsl/fsleyes/widgets/togglepanel.py | 51 +++++++++++++-------------
 6 files changed, 137 insertions(+), 83 deletions(-)

diff --git a/doc/fsl.fsleyes.widgets.rst b/doc/fsl.fsleyes.widgets.rst
index 18cbb7ab1..0041edee0 100644
--- a/doc/fsl.fsleyes.widgets.rst
+++ b/doc/fsl.fsleyes.widgets.rst
@@ -1,19 +1,6 @@
 fsl.fsleyes.widgets package
 ===========================
 
-Submodules
-----------
-
-.. toctree::
-
-   fsl.fsleyes.widgets.imagepanel
-   fsl.fsleyes.widgets.swappanel
-   fsl.fsleyes.widgets.textpanel
-   fsl.fsleyes.widgets.togglepanel
-
-Module contents
----------------
-
 .. automodule:: fsl.fsleyes.widgets
     :members:
     :undoc-members:
diff --git a/fsl/fsleyes/widgets/__init__.py b/fsl/fsleyes/widgets/__init__.py
index 81e45d264..58fc471de 100644
--- a/fsl/fsleyes/widgets/__init__.py
+++ b/fsl/fsleyes/widgets/__init__.py
@@ -4,12 +4,13 @@
 #
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
-"""This package contains a collection of generic custom WX widgets. No more,
-no less.
-"""
+"""This package contains a collection of generic custom :mod:`wx` widgets. No
+more, no less.
 
-import logging
-log = logging.getLogger(__name__)
+.. autosummary::
 
-from textpanel  import TextPanel
-from imagepanel import ImagePanel
+   ~fsl.fsleyes.widgets.imagepanel
+   ~fsl.fsleyes.widgets.swappanel
+   ~fsl.fsleyes.widgets.togglepanel
+   ~fsl.fsleyes.widgets.textpanel
+"""
diff --git a/fsl/fsleyes/widgets/imagepanel.py b/fsl/fsleyes/widgets/imagepanel.py
index f42086cc2..cf74b453f 100644
--- a/fsl/fsleyes/widgets/imagepanel.py
+++ b/fsl/fsleyes/widgets/imagepanel.py
@@ -9,46 +9,70 @@
 """
 
 import logging
-log = logging.getLogger(__name__)
 
 import wx
 
+
+log = logging.getLogger(__name__)
+
+
 class ImagePanel(wx.PyPanel):
-    """A :class:`wx.Panel` which may be used to display a resizeable
+    """A :class:`wx.PyPanel` which may be used to display a resizeable
     :class:`wx.Image`. The image is scaled to the size of the panel.
     """
 
     def __init__(self, parent, image=None):
+        """Create an ``ImagePanel``.
+
+        If the ``image`` is not passed in here, it can be set later with the
+        :meth:`SetImage` method.
+
+        :arg parent: The :mod:`wx` parent object.
+
+        :arg image:  The :class:`wx.Image` object to display.
+        """
 
         wx.PyPanel.__init__(self, parent)
 
         self.Bind(wx.EVT_PAINT, self.Draw)
-        self.Bind(wx.EVT_SIZE,  self._onSize)
+        self.Bind(wx.EVT_SIZE,  self.__onSize)
 
         self.SetImage(image)
 
 
     def SetImage(self, image):
-        self._image = image
+        """Set the image that is displayed on this ``ImagePanel``.
+
+        :arg image: The :class:`wx.Image` object to display.
+        """
+        self.__image = image
         self.Refresh()
 
         
-    def _onSize(self, ev):
+    def __onSize(self, ev):
+        """Redraw this panel when it is sized, so the image is scaled
+        appropriately - see the :meth:`Draw` method.
+        """
         self.Refresh()
         ev.Skip()
 
 
     def DoGetBestSize(self):
+        """Returns the size of the image being displayed.
+        """
 
-        if self._image is None: return (0, 0)
-        else:                   return self._image.GetSize()
+        if self.__image is None: return (0, 0)
+        else:                    return self.__image.GetSize()
         
         
     def Draw(self, ev=None):
+        """Draws this ``ImagePanel``. The image is scaled to the current panel
+        size.
+        """
 
         self.ClearBackground()
 
-        if self._image is None:
+        if self.__image is None:
             return
 
         if ev is None: dc = wx.ClientDC(self)
@@ -62,6 +86,6 @@ class ImagePanel(wx.PyPanel):
         if width == 0 or height == 0:
             return
 
-        bitmap = wx.BitmapFromImage(self._image.Scale(width, height))
+        bitmap = wx.BitmapFromImage(self.__image.Scale(width, height))
         
         dc.DrawBitmap(bitmap, 0, 0, False)
diff --git a/fsl/fsleyes/widgets/swappanel.py b/fsl/fsleyes/widgets/swappanel.py
index 6b864ed64..2ef34e1c8 100644
--- a/fsl/fsleyes/widgets/swappanel.py
+++ b/fsl/fsleyes/widgets/swappanel.py
@@ -1,27 +1,37 @@
 #!/usr/bin/env python
 #
 # swappanel.py - A wx.Panel which can contain many panels, but only displays
-# one at a time. Pushing a button toggles the panel that is displayed.
+# one at a time.
 #
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
+"""This module provides the :class:`SwapPanel` class, which is a
+:class:`wx.PyPanel` that can contain many child panels, but only displays one
+at a time.
+"""
 
 
 import wx
-import wx.lib.newevent as wxevent
 
-_SwapPanelEvent, _EVT_SWAPPANEL_EVENT = wxevent.NewEvent()
 
-EVT_SWAPPANEL_EVENT = _EVT_SWAPPANEL_EVENT
-
-SwapPanelEvent = _SwapPanelEvent
+class SwapPanel(wx.PyPanel):
+    """The ``SwapPanel`` is a panel which can contain many cvhild panels, but
+    only displays one of them at a time. A button push allows the user to
+    change the currently displayed child panel.
+    """
+    
 
+    def __init__(self, parent, buttonSide=wx.TOP):
+        """Create a ``SwapPanel``.
 
-class SwapPanel(wx.Panel):
+        :arg parent:     The :mod:`wx` parent object.
 
-    def __init__(self, parent, buttonSide=wx.TOP):
+        :arg buttonSide: Which side to put the toggle button - one of
+                         ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, or
+                         ``wx.RIGHT``.
+        """
 
-        wx.Panel.__init__(self, parent)
+        wx.PyPanel.__init__(self, parent)
         
         self.__panels     = []
         self.__labels     = []
@@ -46,14 +56,25 @@ class SwapPanel(wx.Panel):
 
 
     def Add(self, panel, label):
+        """Add a new panel to this ``SwapPanel``.
+
+        :arg panel: The panel.
+
+        :arg label: An identifier label for the panel - this may be passed to
+                    the :meth:`Remove` and :meth:`Show` methods to refer to 
+                    this panel.
+        """
         self.__panels.append(panel)
         self.__labels.append(label)
 
+        panel.Reparent(self)
+
         if len(self.__panels) == 1:
             self.__Show(0)
 
         
     def Remove(self, label):
+        """Remove the panel with the specified ``label``. """
         idx = self.__labels.index(label)
 
         self.__panels.pop(idx)
@@ -61,11 +82,13 @@ class SwapPanel(wx.Panel):
 
 
     def Show(self, label):
+        """Show the panel with the specified ``label``. """
         idx = self.__labels.index(label)
         self.__Show(idx)
 
 
     def __Show(self, index):
+        """Show the panel at the specified ``index``. """
 
         panel = self.__panels[index]
 
@@ -83,4 +106,5 @@ class SwapPanel(wx.Panel):
 
 
     def __onSwap(self, ev):
+        """Called when the toggle button is pushed. Shows the next panel."""
         self.__Show((self.__showing + 1) % len(self.__labels))
diff --git a/fsl/fsleyes/widgets/textpanel.py b/fsl/fsleyes/widgets/textpanel.py
index f1d48a131..76e4ddad7 100644
--- a/fsl/fsleyes/widgets/textpanel.py
+++ b/fsl/fsleyes/widgets/textpanel.py
@@ -8,44 +8,59 @@
 some text, oriented either horizontally or vertically.
 """
 
-import logging
-log = logging.getLogger(__name__)
 
 import wx
 
-class TextPanel(wx.Panel):
-    """A :class:`wx.Panel` which may be used to display a string of
+
+class TextPanel(wx.PyPanel):
+    """A :class:`wx.PyPanel` which may be used to display a string of
     text, oriented either horizotnally or vertically.
     """
 
-    def __init__(self, parent, text=None, orient='horizontal'):
-        wx.Panel.__init__(self, parent)
+    def __init__(self, parent, text=None, orient=wx.HORIZONTAL):
+        """Create a ``TextPanel``.
+
+        :arg parent: The :mod:`wx` parent object.
+
+        :arg text:   The text to display. This can be changed via
+                     :meth:`SetText`.
+
+        :arg orient: Text orientation - either ``wx.HORIZONTAL`` (the
+                     default) or ``wx.VERTICAL``. This can be changed
+                     later via :meth:`SetOrient`.
+        """
+        wx.PyPanel.__init__(self, parent)
 
         self.Bind(wx.EVT_PAINT, self.Draw)
-        self.Bind(wx.EVT_SIZE,  self._onSize)
+        self.Bind(wx.EVT_SIZE,  self.__onSize)
 
-        self._text = text
+        self.__text = text
         self.SetOrient(orient)
 
 
     def SetOrient(self, orient):
+        """Sets the orientatino of the text on this ``TextPanel``.
+
+        :arg orient: Either ``wx.HORIZONTAL`` or ``wx.VERTICAL``.
+        """
 
-        if orient not in ('horizontal', 'vertical'):
-            raise RuntimeError('TextPanel orient must be '
-                               'horizontal or vertical')
+        if orient not in (wx.HORIZONTAL, wx.VERTICAL):
+            raise ValueError('TextPanel orient must be '
+                             'wx.HORIZONTAL or wx.VERTICAL')
         
-        self._orient = orient
+        self.__orient = orient
 
         # trigger re-calculation of
         # text extents and a refresh
-        self.SetText(self._text)
+        self.SetText(self.__text)
 
         
     def SetText(self, text):
+        """Sets the text shown on this ``TextPanel``."""
         
         dc = wx.ClientDC(self)
 
-        self._text = text
+        self.__text = text
 
         if text is None:
             self.SetMinSize((0, 0))
@@ -56,23 +71,25 @@ class TextPanel(wx.Panel):
         if self._orient == 'vertical':
             width, height = height, width
 
-        self._textExtent = (width, height)
+        self.__textExtent = (width, height)
 
         self.SetMinSize((width, height))
 
         self.Refresh()
 
 
-    def _onSize(self, ev):
+    def __onSize(self, ev):
+        """Called when this ``TextPanel`` is resized. Triggers a refresh. """
         self.Refresh()
         ev.Skip()
 
         
     def Draw(self, ev=None):
+        """Draws this ``TextPanel``. """
 
         self.ClearBackground()
 
-        if self._text is None or self._text == '':
+        if self.__text is None or self.__text == '':
             return
 
         if ev is None: dc = wx.ClientDC(self)
@@ -82,12 +99,12 @@ class TextPanel(wx.Panel):
             return
 
         paneW, paneH = dc.GetSize().Get()
-        textW, textH = self._textExtent
+        textW, textH = self.__textExtent
 
         x = (paneW - textW) / 2.0
         y = (paneH - textH) / 2.0
 
         if self._orient == 'vertical':
-            dc.DrawRotatedText(self._text, x, paneH - y, 90)
+            dc.DrawRotatedText(self.__text, x, paneH - y, 90)
         else:
-            dc.DrawText(self._text, x, y)
+            dc.DrawText(self.__text, x, y)
diff --git a/fsl/fsleyes/widgets/togglepanel.py b/fsl/fsleyes/widgets/togglepanel.py
index 9093a1d13..d42d7d416 100644
--- a/fsl/fsleyes/widgets/togglepanel.py
+++ b/fsl/fsleyes/widgets/togglepanel.py
@@ -6,7 +6,7 @@
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
 """This module provides the :class:`TogglePanel` class, which is a
-:class:`wx.Panel` that contains a button and some content. Pushing
+:class:`wx.PyPanel` that contains a button and some content. Pushing
 the button toggles the visibility of the content.
 """
 
@@ -15,32 +15,17 @@ import wx
 import wx.lib.newevent as wxevent
 
 
-_TogglePanelEvent, _EVT_TOGGLEPANEL_EVENT = wxevent.NewEvent()
-
-
-EVT_TOGGLEPANEL_EVENT = _EVT_TOGGLEPANEL_EVENT
-"""Identifier for the :data:`TogglePanelEvent` event."""
-
-
-TogglePanelEvent = _TogglePanelEvent
-"""Event emitted when the toggle button is pushed. Contains the
-following attributes:
-
-  - ``newState``: The new visibility state of the toggle panel - ``True``
-                  corresponds to visible, ``False`` to invisible.
-"""
-
-
-class TogglePanel(wx.Panel):
-    """A  :class:`TogglePanel` is a :class:`wx.Panel` that contains
+class TogglePanel(wx.PyPanel):
+    """A  :class:`TogglePanel` is a :class:`wx.PyPanel` that contains
     a button and some content.
 
     Pushing the button toggles the visibility of the content.
     
-    All of the content should be added to the :class:`wx.Panel` which
-    is returned by the :meth:`getContentPanel` method.
+    All of the content should be added to the :class:`wx.PyPanel` which
+    is returned by the :meth:`GetContentPanel` method.
     """
 
+    
     def __init__(self,
                  parent,
                  toggleSide=wx.TOP,
@@ -60,7 +45,7 @@ class TogglePanel(wx.Panel):
         :arg label:        A label to be displayed on the toggle button.
         """
 
-        wx.Panel.__init__(self, parent)
+        wx.PyPanel.__init__(self, parent)
 
         self.__contentPanel = wx.Panel(self)
 
@@ -86,7 +71,7 @@ class TogglePanel(wx.Panel):
         elif toggleSide == wx.BOTTOM: showLabel = u'\u25B2' 
         elif toggleSide == wx.LEFT:   showLabel = u'\u25B6' 
         elif toggleSide == wx.RIGHT:  showLabel = u'\u25C0' 
-
+ 
         self.__showLabel = showLabel
         self.__hideLabel = hideLabel
 
@@ -108,7 +93,7 @@ class TogglePanel(wx.Panel):
             self.toggle()
 
 
-    def toggle(self, ev=None):
+    def Toggle(self, ev=None):
         """Toggles visibility of the panel content."""
         
         isShown = self.__sizer.IsShown(self.__contentPanel)
@@ -124,8 +109,24 @@ class TogglePanel(wx.Panel):
         self.__contentPanel.Layout()
 
     
-    def getContentPanel(self):
+    def GetContentPanel(self):
         """Returns the :class:`wx.Panel` to which all content should be
         added.
         """
         return self.__contentPanel
+
+
+_TogglePanelEvent, _EVT_TOGGLEPANEL_EVENT = wxevent.NewEvent()
+
+
+EVT_TOGGLEPANEL_EVENT = _EVT_TOGGLEPANEL_EVENT
+"""Identifier for the :data:`TogglePanelEvent` event."""
+
+
+TogglePanelEvent = _TogglePanelEvent
+"""Event emitted when the toggle button is pushed. Contains the
+following attributes:
+
+  - ``newState``: The new visibility state of the toggle panel - ``True``
+                  corresponds to visible, ``False`` to invisible.
+"""
-- 
GitLab