diff --git a/doc/fsl.utils.colourbarbitmap.rst b/doc/fsl.utils.colourbarbitmap.rst
deleted file mode 100644
index 0b1f2ab90806d31e73a33e55ea9e0312b1085300..0000000000000000000000000000000000000000
--- a/doc/fsl.utils.colourbarbitmap.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-:orphan:
-
-fsl.utils.colourbarbitmap module
-================================
-
-.. automodule:: fsl.utils.colourbarbitmap
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/doc/fsl.utils.dialog.rst b/doc/fsl.utils.dialog.rst
deleted file mode 100644
index f303a8ba51502decea3e7b6cb504a46e1362bea3..0000000000000000000000000000000000000000
--- a/doc/fsl.utils.dialog.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-:orphan:
-
-fsl.utils.dialog module
-=======================
-
-.. automodule:: fsl.utils.dialog
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/doc/fsl.utils.imagepanel.rst b/doc/fsl.utils.imagepanel.rst
deleted file mode 100644
index 8816d5f4456d575ccc38033ffae2ac59e29aa09e..0000000000000000000000000000000000000000
--- a/doc/fsl.utils.imagepanel.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-:orphan:
-
-fsl.utils.imagepanel module
-===========================
-
-.. automodule:: fsl.utils.imagepanel
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/doc/fsl.utils.layout.rst b/doc/fsl.utils.layout.rst
deleted file mode 100644
index 334875be2f483915e1062f8ebd39b367ac675f39..0000000000000000000000000000000000000000
--- a/doc/fsl.utils.layout.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-:orphan:
-
-fsl.utils.layout module
-=======================
-
-.. automodule:: fsl.utils.layout
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/doc/fsl.utils.runwindow.rst b/doc/fsl.utils.runwindow.rst
deleted file mode 100644
index b99c474f04750e38298d7c568805d87b8492d47d..0000000000000000000000000000000000000000
--- a/doc/fsl.utils.runwindow.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-:orphan:
-
-fsl.utils.runwindow module
-==========================
-
-.. automodule:: fsl.utils.runwindow
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/doc/fsl.utils.status.rst b/doc/fsl.utils.status.rst
deleted file mode 100644
index 2ab0edfd96dc4af3772c05a2f462214abc51ecad..0000000000000000000000000000000000000000
--- a/doc/fsl.utils.status.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-:orphan:
-
-fsl.utils.status module
-=======================
-
-.. automodule:: fsl.utils.status
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/doc/fsl.utils.textbitmap.rst b/doc/fsl.utils.textbitmap.rst
deleted file mode 100644
index 47d11d0b3262754a895539b9c021966295a9bd0b..0000000000000000000000000000000000000000
--- a/doc/fsl.utils.textbitmap.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-:orphan:
-
-fsl.utils.textbitmap module
-===========================
-
-.. automodule:: fsl.utils.textbitmap
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/doc/fsl.utils.typedict.rst b/doc/fsl.utils.typedict.rst
deleted file mode 100644
index f5359c8c6bb372e220e3efd4362b5103fa6774d3..0000000000000000000000000000000000000000
--- a/doc/fsl.utils.typedict.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-:orphan:
-
-fsl.utils.typedict module
-=========================
-
-.. automodule:: fsl.utils.typedict
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/doc/fsl.utils.webpage.rst b/doc/fsl.utils.webpage.rst
deleted file mode 100644
index ffbc0ddb1b3bf23b229faf7c47c20d5e08acf794..0000000000000000000000000000000000000000
--- a/doc/fsl.utils.webpage.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-:orphan:
-
-fsl.utils.webpage module
-========================
-
-.. automodule:: fsl.utils.webpage
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/doc/images/colourbarbitmap.png b/doc/images/colourbarbitmap.png
deleted file mode 100644
index a94c44e75d587321f1c585f429bf491727e17934..0000000000000000000000000000000000000000
Binary files a/doc/images/colourbarbitmap.png and /dev/null differ
diff --git a/doc/images/fsldirdialog.png b/doc/images/fsldirdialog.png
deleted file mode 100644
index 4641d8b30fa34feec9d45eb1a41a5fc8731c52c2..0000000000000000000000000000000000000000
Binary files a/doc/images/fsldirdialog.png and /dev/null differ
diff --git a/doc/images/simplemessagedialog.png b/doc/images/simplemessagedialog.png
deleted file mode 100644
index 01771580c87137b9ffa16434aa2c9ced59bd7c73..0000000000000000000000000000000000000000
Binary files a/doc/images/simplemessagedialog.png and /dev/null differ
diff --git a/doc/images/texteditdialog.png b/doc/images/texteditdialog.png
deleted file mode 100644
index e2001ae7f2d53abacea0d485bfeb30f3c90df221..0000000000000000000000000000000000000000
Binary files a/doc/images/texteditdialog.png and /dev/null differ
diff --git a/fsl/utils/colourbarbitmap.py b/fsl/utils/colourbarbitmap.py
deleted file mode 100644
index 76fb9b7a32b7b4a072c264d479310ab8ba6f907a..0000000000000000000000000000000000000000
--- a/fsl/utils/colourbarbitmap.py
+++ /dev/null
@@ -1,224 +0,0 @@
-#!/usr/bin/env python
-#
-# colourbarbitmap.py - A function which renders a colour bar using
-# matplotlib as an RGBA bitmap.
-#
-# Author: Paul McCarthy <pauldmccarthy@gmail.com>
-#
-"""This module provides a single function, :func:`colourBarBitmap`, which uses
-:mod:`matplotlib` to plot a colour bar. The colour bar is rendered off-screen
-and returned as an RGBA bitmap.
-"""
-
-
-def colourBarBitmap(cmap,
-                    width,
-                    height,
-                    cmapResolution=256,
-                    negCmap=None,
-                    invert=False,
-                    ticks=None,
-                    ticklabels=None,
-                    tickalign=None,
-                    label=None,
-                    orientation='vertical',
-                    labelside='top',
-                    alpha=1.0,
-                    fontsize=10,
-                    bgColour=None,
-                    textColour='#ffffff'):
-    """Plots a colour bar using :mod:`matplotlib`.
-
-    
-    The rendered colour bar is returned as a RGBA bitmap within a
-    ``numpy.uint8`` array of size :math:`w \\times h \\times 4`, with the
-    top-left pixel located at index ``[0, 0, :]``.
-
-
-    A rendered colour bar will look something like this:
-
-    .. image:: images/colourbarbitmap.png
-       :scale: 50%
-       :align: center
-    
-    
-    :arg cmap:         Name of a registered :mod:`matplotlib` colour map.
-
-    :arg width:        Colour bar width in pixels.
-    
-    :arg height:       Colour bar height in pixels.
-
-    :arg negCmap:      If provided, two colour maps are drawn, centered at 0.
-
-    :arg invert:       If ``True``, the colour map is inverted.
-
-    :arg ticks:        Locations of tick labels. 
-
-    :arg ticklabels:   Tick labels.
-
-    :arg tickalign:    Tick alignment (one for each tick, either ``'left'`` or
-                       ``'right'``).
-
-    :arg label:        Text label to show next to the colour bar.
-    
-    :arg orientation:  Either ``vertical`` or ``horizontal``.
-    
-    :arg labelside:    If ``orientation`` is ``vertical`` ``labelSide`` may
-                       be either ``left`` or ``right``. Otherwise, if
-                       ``orientation`` is ``horizontal``, ``labelSide`` may
-                       be ``top`` or ``bottom``.
-    
-    :arg alpha:        Colour bar transparency, in the range ``[0.0 - 1.0]``.
-    
-    :arg fontsize:     Label font size in points.
-    
-    :arg bgColour:     Background colour - can be any colour specification
-                       that is accepted by :mod:`matplotlib`.
-    
-    :arg textColour:   Label colour - can be any colour specification that
-                       is accepted by :mod:`matplotlib`.
-    """
-
-    # These imports are expensive, so we're
-    # importing at the function level.
-    import numpy                           as np
-    import matplotlib.backends.backend_agg as mplagg
-    import matplotlib.figure               as mplfig
-
-    if orientation not in ['vertical', 'horizontal']:
-        raise ValueError('orientation must be vertical or horizontal')
-
-    if orientation == 'horizontal':
-        if labelside not in ['top', 'bottom']:
-            raise ValueError('labelside must be top or bottom')
-    else:
-        if labelside not in ['left', 'right']:
-            raise ValueError('labelside must be left or right')
-
-    # vertical plots are rendered horizontally,
-    # and then simply rotated at the end
-    if orientation == 'vertical':
-        width, height = height, width
-        if labelside == 'left': labelside = 'top'
-        else:                   labelside = 'bottom'
-
-    dpi   = 96.0
-    ncols = cmapResolution
-    data  = genColours(cmap, ncols, invert, alpha)
-
-    if negCmap is not None:
-        ndata  = genColours(negCmap, ncols, not invert, alpha)
-        data   = np.concatenate((ndata, data), axis=1)
-        ncols *= 2
-
-    fig    = mplfig.Figure(figsize=(width / dpi, height / dpi), dpi=dpi)
-    canvas = mplagg.FigureCanvasAgg(fig)
-    ax     = fig.add_subplot(111)
-    
-    if bgColour is not None:
-        fig.patch.set_facecolor(bgColour)
-    else:
-        fig.patch.set_alpha(0)
-
-    # draw the colour bar
-    ax.imshow(data,
-              aspect='auto',
-              origin='lower',
-              interpolation='nearest')
-
-    ax.set_xlim((0, ncols - 1))
-
-    ax.set_yticks([])
-    ax.tick_params(colors=textColour, labelsize=fontsize, length=0)
-    
-    if labelside == 'top':
-        ax.xaxis.tick_top()
-        ax.xaxis.set_label_position('top')
-        va = 'top'
-    else:
-        ax.xaxis.tick_bottom()
-        ax.xaxis.set_label_position('bottom')
-        va = 'bottom'
-
-    if label is not None:
-        ax.set_xlabel(label,
-                      fontsize=fontsize,
-                      color=textColour,
-                      va=va)
-        label = ax.xaxis.get_label()
-
-    if ticks is None or ticklabels is None:
-        ax.set_xticks([])
-    else:
-        
-        ax.set_xticks(np.array(ticks) * ncols)
-        ax.set_xticklabels(ticklabels)
-        ticklabels = ax.xaxis.get_ticklabels()
-
-    try:
-        fig.tight_layout()
-    except:
-        pass
-
-    # Adjust the x label after tight_layout,
-    # otherwise it will overlap with the tick
-    # labels. I don't understand why, but I
-    # have to set va to the opposite of what
-    # I would have thought.
-    if label is not None and ticklabels is not None:
-        if labelside == 'top':
-            label.set_va('bottom')
-            label.set_position((0.5, 0.97))
-        else:
-            label.set_va('top')
-            label.set_position((0.5, 0.03))
-
-    # This must be done *after* calling
-    # tick_top/tick_bottom, as I think
-    # the label bjects get recreated.
-    if ticklabels is not None and tickalign is not None:
-        for l, a in zip(ticklabels, tickalign):
-            l.set_horizontalalignment(a)
-    
-    canvas.draw()
-
-    buf = canvas.tostring_argb()
-    ncols, nrows = canvas.get_width_height()
-
-    bitmap = np.fromstring(buf, dtype=np.uint8)
-    bitmap = bitmap.reshape(nrows, ncols, 4).transpose([1, 0, 2])
-
-    # the bitmap is in argb order,
-    # but we want it in rgba
-    rgb = bitmap[:, :, 1:]
-    a   = bitmap[:, :, 0]
-    bitmap = np.dstack((rgb, a))
-
-    if orientation == 'vertical':
-        bitmap = np.flipud(bitmap.transpose([1, 0, 2]))
-        bitmap = np.rot90(bitmap, 2)
-
-    return bitmap
-
-
-def genColours(cmap, cmapResolution, invert, alpha):
-    """Generate an array containing ``cmapResolution`` colours from the given
-    colour map object/function.
-    """
-
-    import numpy         as np
-    import matplotlib.cm as cm
-    
-    ncols         = cmapResolution
-    cmap          = cm.get_cmap(cmap)
-    data          = np.linspace(0.0, 1.0, ncols)
-    
-    if invert:
-        data = data[::-1]
-    
-    data          = np.repeat(data.reshape(ncols, 1), 2, axis=1)
-    data          = data.transpose()
-    data          = cmap(data)
-    data[:, :, 3] = alpha
-
-    return data
diff --git a/fsl/utils/dialog.py b/fsl/utils/dialog.py
deleted file mode 100644
index 429531dc2a225812485287dca0ef3f33bd5bc1e9..0000000000000000000000000000000000000000
--- a/fsl/utils/dialog.py
+++ /dev/null
@@ -1,962 +0,0 @@
-#!/usr/bin/env python
-#
-# dialog.py - Miscellaneous dialogs.
-#
-# Author: Paul McCarthy <pauldmccarthy@gmail.com>
-#
-"""This module contains a collection of basic dialog classes, available for
-use throughout ``fslpy``. The available dialogs are:
-
-.. autosummary::
-   :nosignatures:
-
-   SimpleMessageDialog
-   TimeoutDialog
-   ProcessingDialog
-   TextEditDialog
-   FSLDirDialog
-"""
-
-
-import            os
-import os.path as op
-import            threading
-
-import            six
-import            wx
-
-from .platform import platform as fslplatform
-
-
-class SimpleMessageDialog(wx.Dialog):
-    """A simple, no-frills :class:`wx.Dialog` for displaying a message. The
-    message can be updated via the :meth:`SetMessage` method. As a simple
-    usage example::
-
-        import fsl.utils.dialog as fsldlg
-        dlg = fsldlg.SimpleMessageDialog(message='Loading data ...')
-
-        dlg.Show()
-    
-        # load the data, like
-        # you said you would
-
-        # Data is loaded, so we
-        # can kill the dialog
-        dlg.Close()
-        dlg.Destroy()
-
-    
-    The ``SimpleMessageDialog`` class supports the following styles:
-
-    .. autosummary::
-       SMD_KEEP_CENTERED
-    
-
-    a ``SimpleMessageDialog`` looks something like this:
-
-    .. image:: images/simplemessagedialog.png
-       :scale: 50%
-       :align: center
-    """
-
-    
-    def __init__(self, parent=None, message='', style=None):
-        """Create a ``SimpleMessageDialog``.
-
-        :arg parent:  The :mod:`wx` parent object. 
-
-        :arg message: The initial message to show.
-
-        :arg style:   Only one style flag  is supported,
-                      :data:`SMD_KEEP_CENTERED`. This flag is enabled by
-                      default.
-        """
-
-        
-        if style is None:
-            style = SMD_KEEP_CENTERED
-
-        if parent is None:
-            parent = wx.GetApp().GetTopWindow()
-
-        wx.Dialog.__init__(self,
-                           parent,
-                           style=wx.STAY_ON_TOP | wx.FULL_REPAINT_ON_RESIZE)
-
-        
-        self.__style = style
-        
-        self.__message = wx.StaticText(
-            self,
-            style=(wx.ST_ELLIPSIZE_MIDDLE     |
-                   wx.ALIGN_CENTRE_HORIZONTAL |
-                   wx.ALIGN_CENTRE_VERTICAL))
-        
-        self.__sizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.__sizer.Add(self.__message,
-                         border=25,
-                         proportion=1,
-                         flag=wx.EXPAND | wx.CENTRE | wx.ALL)
-
-        self.SetTransparent(240)
-        self.SetBackgroundColour((225, 225, 255))
-        
-        self.SetSizer(self.__sizer)
-
-        self.SetMessage(message)
-
-
-    def Show(self):
-        """Overrides ``wx.Dialog.Show``. Calls that method, and calls
-        ``wx.Yield``.
-        """
-        wx.Dialog.Show(self)
-        wx.Yield()
-
-        
-    def SetMessage(self, msg):
-        """Updates the message shown on this ``SimpleMessageDialog``.
-
-        If the :data:`SMD_KEEP_CENTERED` style is set, the dialog is
-        re-centered on its parent, to account for changes in the message width.
-        """
-
-        msg = str(msg)
-
-        self.__message.SetLabel(msg)
-
-        # Figure out the dialog size
-        # required to fit the message
-        dc = wx.ClientDC(self.__message)
-        
-        width, height = dc.GetTextExtent(msg)
-
-        # +50 to account for sizer borders (see __init__),
-        # plus a bit more for good measure. In particular,
-        # under GTK, the message seems to be vertically
-        # truncated if we don't add some extra padding
-        width  += 60
-        height += 70
-
-        self.SetMinClientSize((width, height))
-        self.SetClientSize((   width, height))
-
-        self.Layout()
-        self.__message.Layout()
-
-        if self.__style & SMD_KEEP_CENTERED:
-            self.CentreOnParent()
-
-        # This ridiculousness seems to be
-        # necessary to force a repaint on
-        # all platforms (OSX, GTK, GTK/SSH)
-        wx.Yield()
-        self.Refresh()
-        self.Update()
-        self.__message.Refresh()
-        self.__message.Update() 
-        wx.Yield()
-
-
-# SimpleMessageDialog style flags
-SMD_KEEP_CENTERED = 1
-"""If set, the dialog will be re-centred on its parent whenever its message
-changes.
-"""
-            
-
-class TimeoutDialog(SimpleMessageDialog):
-    """A :class:`SimpleMessageDialog` which automatically destroys itself
-    after a specified timeout period.
-
-     .. note:: The timeout functionality will not work if you show the dialog
-               by any means other than the :meth:`wx.Dialog.Show` or
-               :meth:`wx.Dialog.ShowModal` methods ... but is there any other
-               way of showing a :class:`wx.Dialog`?
-    """
-
-
-    def __init__(self, parent, message, timeout=1000, **kwargs):
-        """Create a ``TimeoutDialog``.
-
-        :arg parent:  The :mod:`wx` parent object.
-
-        :arg message: The initial message to display.
-
-        :arg timeout: Timeout period in milliseconds. 
-
-        :arg kwargs:  Passed through to :meth:`SimpleMessageDialog.__init__`.
-        """
-
-        SimpleMessageDialog.__init__(self, parent, message, **kwargs)
-        self.__timeout = timeout
-
-
-    def __close(self):
-        """Closes and destroys this ``TimeoutDialog``. """
-        self.Close()
-        self.Destroy()
-
-        
-    def Show(self):
-        """Shows this ``TimeoutDialog``, and sets up a callback to
-        close it after the specified ``timeout``.
-        """
-        wx.CallLater(self.__timeout, self.__close)
-        SimpleMessageDialog.Show(self)
-
-
-    def ShowModal(self):
-        """Shows this ``TimeoutDialog``, and sets up a callback to
-        close it after the specified ``timeout``.
-        """ 
-        wx.CallLater(self.__timeout, self.__close)
-        SimpleMessageDialog.ShowModal(self)
-
-        
-class ProcessingDialog(SimpleMessageDialog):
-    """A :class:`SimpleMessageDialog` which displays a message and runs a
-    task in the background. User interaction is blocked while the task runs,
-    and the dialog closes and destroys itself automatically on task
-    completion.
-
-    
-    The task is simply passed in as a function. If the task supports it,
-    the ``ProcessingDialog`` will pass it two message-updating functions,
-    which can be used by the task to update the message being displayed.
-    This functionality is controlled by the ``passFuncs``, ``messageFunc``
-    and ``errorFunc`` parameters to :meth:`__init__`.
-
-    
-    A ``ProcessingDialog`` must be displayed via the :meth:`Run` method,
-    *not* with the :meth:`wx.Dialog.Show` or :meth:`wx.Dialog.ShowModal`
-    methods.
-    """
-
-    def __init__(self, parent, message, task, *args, **kwargs):
-        """Create a ``ProcessingDialog``.
-
-        :arg parent:       The :mod:`wx` parent object.
-        
-        :arg message:      Initial message to display.
-        
-        :arg task:         The function to run.
-
-        :arg args:         Positional arguments passed to the ``task``
-                           function.
-
-        :arg kwargs:       Keyword arguments passed to the ``task`` function.
-
-        
-        Some special keyword arguments are also accepted:
-
-        ===============  =================================================
-        Name             Description
-        ===============  =================================================
-        ``passFuncs``    If ``True``, two extra keyword arguments  are
-                         passed to the ``task`` function - ``messageFunc``
-                         and ``errorFunc``.
-
-                         ``messageFunc`` is a function which accepts a
-                         single string as its argument; when it is called,
-                         the dialog  message is updated to display the
-                         string.
-
-                         ``errorFunc`` is a function which accepts two
-                         arguemnts - a message string and an
-                         :exc:`Exception` instance. If the task detects
-                         an error, it may call this function. A new
-                         dialog is shown, containing the details of the
-                         error, to inform the user.
-        ``messageFunc``  Overrides the default ``messageFunc`` described
-                         above.
-        ``errorFunc``    Overrides the default ``errorFunc`` described
-                         above.
-        ===============  =================================================
-        """
-
-        passFuncs = kwargs.get('passFuncs', False)
-        
-        if not passFuncs:
-            kwargs.pop('messageFunc', None)
-            kwargs.pop('errorFunc',   None)
-        else:
-            kwargs['messageFunc'] = kwargs.get('messageFunc',
-                                               self.__defaultMessageFunc)
-            kwargs['errortFunc']  = kwargs.get('errorFunc',
-                                               self.__defaultErrorFunc)
-
-        self.task    = task
-        self.args    = args
-        self.kwargs  = kwargs
-        self.message = message
-
-        style = kwargs.pop('style', None)
-
-        SimpleMessageDialog.__init__(self, parent, style=style)
-
-
-    def Run(self, mainThread=False):
-        """Shows this ``ProcessingDialog``, and runs the ``task`` function
-        passed to :meth:`__init__`. When the task completes, this dialog
-        is closed and destroyed.
-
-        :arg mainThread: If ``True`` the task is run in the current thread.
-                         Otherwise, the default behaviour is to run the
-                         task in a separate thread.
-
-        :returns: the return value of the ``task`` function.
-
-        .. note:: If ``mainThread=True``, the task should call
-                  :func:`wx.Yield` periodically - under GTK, there is a
-                  chance that this ``ProcessingDialog`` will not get drawn
-                  before the task begins.
-        """
-
-        self.SetMessage(self.message)
-        wx.Dialog.Show(self)
-        self.SetFocus()
-
-        self.Refresh()
-        self.Update()
-        wx.Yield()
-
-        if mainThread:
-            try:
-                result = self.task(*self.args, **self.kwargs)
-            except:
-                self.Close()
-                self.Destroy()
-                raise
-        else:
-            returnVal = [None]
-
-            def wrappedTask():
-                returnVal[0] = self.task(*self.args, **self.kwargs)
-
-            thread = threading.Thread(target=wrappedTask)
-            thread.start()
-
-            while thread.isAlive():
-                thread.join(0.2)
-                wx.Yield()
-
-            result = returnVal[0]
-
-        self.Close()
-        self.Destroy()
-        
-        return result
-
-    
-    def Show(self):
-        """Raises a :exc:`NotImplementedError`."""
-        raise NotImplementedError('Use the Run method')
-
-    
-    def ShowModal(self):
-        """Raises a :exc:`NotImplementedError`."""
-        raise NotImplementedError('Use the Run method') 
-
-        
-    def __defaultMessageFunc(self, msg):
-        """Default ``messageFunc``. Updates the message which is displayed
-        on this ``ProcessingDialog``. See :meth:`SetMessage`.
-        """
-        self.SetMessage(msg)
-
-    
-    def __defaultErrorFunc(self, msg, err):
-        """Default ``errorFunc``. Opens a new dialog (a :class:`wx.MessageBox`)
-        which contains a description of the error.
-        """
-        err   = str(err)
-        msg   = 'An error hass occurred: {}\n\nDetails: {}'.format(msg, err)
-        title = 'Error'
-        wx.MessageBox(msg, title, wx.ICON_ERROR | wx.OK) 
-
-
-class TextEditDialog(wx.Dialog):
-    """A dialog which shows an editable/selectable text field.
-
-
-    ``TextEditDialog`` supports the following styles:
-
-    .. autosummary::
-       TED_READONLY
-       TED_MULTILINE
-       TED_OK
-       TED_CANCEL
-       TED_OK_CANCEL
-       TED_COPY
-       TED_COPY_MESSAGE
-
-    A ``TextEditDialog`` looks something like this:
-
-    .. image:: images/texteditdialog.png
-       :scale: 50%
-       :align: center
-    """
-
-    def __init__(self,
-                 parent,
-                 title='',
-                 message='',
-                 text='',
-                 icon=None,
-                 style=None):
-        """Create a ``TextEditDialog``.
-
-        :arg parent:  The :mod:`wx` parent object.
-
-        :arg title:   Dialog title.
-        
-        :arg message: Dialog message.
-        
-        :arg text:    String  to display in the text field.
-        
-        :arg icon:    A :mod:`wx` icon identifier, such as 
-                      :data:`wx.ICON_INFORMATION` or :data:`wx.ICON_WARNING`.
-        
-        :arg style:   A combination of :data:`TED_READONLY`,
-                      :data:`TED_MULTILINE`, :data:`TED_OK`, 
-                      :data:`TED_CANCEL`, :data:`TED_OK_CANCEL`, 
-                      :data:`TED_COPY` and :data:`TED_COPY_MESSAGE` . Defaults
-                      to :data:`TED_OK`.
-        """
-
-        if style is None:
-            style = TED_OK
-
-        wx.Dialog.__init__(self,
-                           parent,
-                           title=title,
-                           style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
-
-        textStyle = 0
-        if style & TED_READONLY:  textStyle |= wx.TE_READONLY
-        if style & TED_MULTILINE: textStyle |= wx.TE_MULTILINE
-
-        self.__message  = wx.StaticText(self)
-        self.__textEdit = wx.TextCtrl(  self, style=textStyle)
-
-        self.__message .SetLabel(message)
-        self.__textEdit.SetValue(text)
-
-        self.__showCopyMessage = style & TED_COPY_MESSAGE
-
-        # set the min size of the text 
-        # ctrl so it can fit a few lines
-        self.__textEdit.SetMinSize((-1, 120))
-        self.__textEdit.SetMaxSize((600, -1))
-
-        self.__ok      = (-1, -1)
-        self.__copy    = (-1, -1)
-        self.__cancel  = (-1, -1)
-        self.__icon    = (-1, -1)
-        self.__buttons = []
-
-        if icon is not None:
-            
-            icon = wx.ArtProvider.GetMessageBoxIcon(icon)
-
-            if fslplatform.wxFlavour == fslplatform.WX_PHOENIX:
-                bmp = wx.Bitmap()
-            else:
-                bmp = wx.EmptyBitmap(icon.GetWidth(), icon.GetHeight())
-                
-            bmp.CopyFromIcon(icon)
-            self.__icon = wx.StaticBitmap(self)
-            self.__icon.SetBitmap(bmp)
-
-        if style & TED_OK:
-            self.__ok = wx.Button(self, id=wx.ID_OK)
-            self.__ok.Bind(wx.EVT_BUTTON, self.__onOk)
-            self.__buttons.append(self.__ok)
-            
-        if style & TED_CANCEL:
-            self.__cancel = wx.Button(self, id=wx.ID_CANCEL)
-            self.__cancel.Bind(wx.EVT_BUTTON, self.__onCancel)
-            self.__buttons.append(self.__cancel)
-
-        if style & TED_COPY:
-            self.__copy = wx.Button(self, label='Copy to clipboard')
-            self.__copy.Bind(wx.EVT_BUTTON, self.__onCopy)
-            self.__buttons.append(self.__copy)
-
-        self.__textEdit.Bind(wx.EVT_CHAR_HOOK, self.__onCharHook)
-
-        textSizer = wx.BoxSizer(wx.VERTICAL)
-        iconSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer  = wx.BoxSizer(wx.HORIZONTAL)
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-
-        textSizer.Add(self.__message,
-                      flag=wx.ALL | wx.CENTRE,
-                      border=20)
-        textSizer.Add(self.__textEdit,
-                      flag=wx.ALL | wx.EXPAND,
-                      border=20,
-                      proportion=1)
-
-        iconSizer.Add(self.__icon, flag=wx.ALL | wx.CENTRE, border=20)
-        iconSizer.Add(textSizer, flag=wx.EXPAND, proportion=1)
-
-        btnSizer.AddStretchSpacer()
-        btnSizer.Add(self.__ok,
-                     flag=wx.ALL | wx.CENTRE,
-                     border=10)
-        btnSizer.Add(self.__copy,
-                     flag=wx.ALL | wx.CENTRE,
-                     border=10) 
-        btnSizer.Add(self.__cancel,
-                     flag=wx.ALL | wx.CENTRE,
-                     border=10)
-        btnSizer.Add((-1, 20))
-
-        mainSizer.Add(iconSizer, flag=wx.EXPAND, proportion=1)
-        mainSizer.Add(btnSizer,  flag=wx.EXPAND)
-
-        self.SetSizer(mainSizer)
-        self.Fit()
-
-
-    def __onCharHook(self, ev):
-        """Called on ``EVT_CHAR_HOOK`` events generated by the ``TextCtrl``.
-        Implements tab-navigation, and makes the enter key behave as if
-        the user had clicked the OK button.
-        """
-
-        key = ev.GetKeyCode()
-
-        if key not in (wx.WXK_TAB, wx.WXK_RETURN):
-            ev.Skip()
-            return
-
-        # Dodgy, but I've had loads of trouble
-        # under OSX - Navigate/HandleAsNavigationKey
-        # do not work.
-        if key == wx.WXK_TAB and len(self.__buttons) > 0:
-            self.__buttons[0].SetFocus()
-
-        elif key == wx.WXK_RETURN:
-            self.__onOk(None)
-
-        
-    def __onOk(self, ev):
-        """Called when the *Ok* button is pressed. Ends the dialog. """
-        self.EndModal(wx.ID_OK)
-
-        
-    def __onCancel(self, ev):
-        """Called when the *Cancel* button is pressed. Ends the dialog. """
-        self.EndModal(wx.ID_CANCEL)
-
-        
-    def __onCopy(self, ev):
-        """Called when the *Copy* button is pressed. Copies the text
-        to the system clipboard, and pops up a :class:`TimeoutDialog`
-        informing the user.
-        """
-        text = self.__textEdit.GetValue()
-
-        cb = wx.TheClipboard
-
-        if cb.Open():
-            cb.SetData(wx.TextDataObject(text))
-            cb.Close()
-
-            if self.__showCopyMessage:
-                td = TimeoutDialog(self, 'Copied!', 1000)
-                td.Show()
-
-            
-    def SetMessage(self, message):
-        """Set the message displayed on the dialog."""
-        self.__message.SetLabel(message)
-
-        
-    def SetOkLabel(self, label):
-        """Set the label to show on the *Ok* button."""
-        self.__ok.SetLabel(label)
-
-        
-    def SetCopyLabel(self, label):
-        """Sets the label to show on the *Copy* button."""
-        self.__copy.SetLabel(label)
-
-        
-    def SetCancelLabel(self, label):
-        """Sets the label to show on the *Cancel* button."""
-        self.__cancel.SetLabel(label)
-
-
-    def SetText(self, text):
-        """Sets the text to show in the text field."""
-        self.__textEdit.SetValue(text)
-
-
-    def GetText(self):
-        """Returns the text shown in the text field."""
-        return self.__textEdit.GetValue()
-
-
-# TextEditDialog style flags
-
-
-TED_READONLY = 1
-"""If set, the user will not be able to change the text field contents."""
-
-
-TED_MULTILINE = 2
-"""If set, the text field will span multiple lines. """
-
-
-TED_OK = 4
-"""If set, an *Ok* button will be shown. """
-
-
-TED_CANCEL = 8
-"""If set, a *Cancel* button will be shown. """
-
-
-TED_OK_CANCEL = 12
-"""If set, *Ok* and *Cancel* buttons will be shown. Equivalent to
-``TED_OK | TED_CANCEL``.
-"""
-
-
-TED_COPY = 16
-"""If set, a *Copy* button will be shown, allowing the use to copy
-the text to the system clipboard.
-"""
-
-
-TED_COPY_MESSAGE = 32
-"""If set, and if :attr:`TED_COPY` is also set, when the user chooses
-to copy the text to the system clipboard, a popup message is displayed.
-"""
-
-
-class FSLDirDialog(wx.Dialog):
-    """A dialog which warns the user that the ``$FSLDIR`` environment
-    variable is not set, and prompts them to identify the FSL
-    installation directory.
-
-    If the user selects a directory, the :meth:`getFSLDir` method can be
-    called to retrieve their selection after the dialog has been closed.
-
-    A ``FSLDirDialog`` looks something like this:
-
-    .. image:: images/fsldirdialog.png
-       :scale: 50%
-       :align: center
-    """
-
-    def __init__(self, parent, toolName):
-        """Create a ``FSLDirDialog``.
-
-        :arg parent:   The :mod:`wx` parent object.
-
-        :arg toolName: The name of the tool which is running.
-        """
-
-        wx.Dialog.__init__(self, parent, title='$FSLDIR is not set')
-
-        self.__fsldir  = None
-        self.__icon    = wx.StaticBitmap(self)
-        self.__message = wx.StaticText(  self)
-        self.__locate  = wx.Button(      self, id=wx.ID_OK)
-        self.__skip    = wx.Button(      self, id=wx.ID_CANCEL)
-
-        icon = wx.ArtProvider.GetMessageBoxIcon(wx.ICON_EXCLAMATION)
-
-        if fslplatform.wxFlavour == fslplatform.WX_PYTHON:
-            bmp  = wx.EmptyBitmap(icon.GetWidth(), icon.GetHeight())
-        else:
-            bmp = wx.Bitmap()
-            
-        bmp.CopyFromIcon(icon)
-
-        self.__icon.SetBitmap(bmp)
-        self.__message.SetLabel(
-            'The $FSLDIR environment variable is not set - {} '
-            'may not behave correctly.'.format(toolName))
-        self.__locate .SetLabel('Locate $FSLDIR')
-        self.__skip   .SetLabel('Skip')
-
-        self.__skip  .Bind(wx.EVT_BUTTON, self.__onSkip)
-        self.__locate.Bind(wx.EVT_BUTTON, self.__onLocate)
-
-        self.__mainSizer    = wx.BoxSizer(wx.HORIZONTAL)
-        self.__contentSizer = wx.BoxSizer(wx.VERTICAL)
-        self.__buttonSizer  = wx.BoxSizer(wx.HORIZONTAL)
-
-        self.__buttonSizer.Add((1, 1), flag=wx.EXPAND, proportion=1)
-        self.__buttonSizer.Add(self.__locate)
-        self.__buttonSizer.Add((20, 1))
-        self.__buttonSizer.Add(self.__skip)
-
-        self.__contentSizer.Add(self.__message, flag=wx.EXPAND, proportion=1)
-        self.__contentSizer.Add((1, 20))
-        self.__contentSizer.Add(self.__buttonSizer, flag=wx.EXPAND)
-
-        # If running on OSX, add a message
-        # telling the user about the
-        # cmd+shift+g shortcut
-        if fslplatform.os == 'Darwin':
-
-            self.__hint = wx.StaticText(
-                self,
-                label=six.u('Hint: Press \u2318+\u21e7+G in the file '
-                            'dialog to manually type in a location.'))
-
-            self.__hint.SetForegroundColour('#888888')
-
-            self.__contentSizer.Insert(2, self.__hint, flag=wx.EXPAND)
-            self.__contentSizer.Insert(3, (1, 20))
-            
-        else:
-            self.__hint = None
-            
-        self.__mainSizer.Add(self.__icon,
-                             flag=wx.ALL | wx.CENTRE,
-                             border=20)
-        self.__mainSizer.Add(self.__contentSizer,
-                             flag=wx.EXPAND | wx.ALL,
-                             proportion=1,
-                             border=20)
-
-        self.__message.Wrap(self.GetSize().GetWidth())
-
-        self.SetSizer(self.__mainSizer)
-        self.__mainSizer.Layout()
-        self.__mainSizer.Fit(self)
-
-        self.CentreOnParent()
-
-        
-    def GetFSLDir(self):
-        """If the user selected a directory, this method returns their
-        selection. Otherwise, it returns ``None``.
-        """
-        return self.__fsldir
- 
-
-    def __onSkip(self, ev):
-        """called when the *Skip* button is pushed. """
-        self.EndModal(wx.ID_CANCEL)
-
-
-    def __onLocate(self, ev):
-        """Called when the *Locate* button is pushed. Opens a
-        :class:`wx.DirDialog` which allows the user to locate the
-        FSL installation directory.
-        """
-
-        dlg = wx.DirDialog(
-            self,
-            message='Select the directory in which FSL is installed',
-            defaultPath=op.join(os.sep, 'usr', 'local'),
-            style=wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST)
-
-        # If the user cancels the file
-        # dialog, focus returns to the
-        # original 'Choose dir' / 'Skip'
-        # dialog.
-        if dlg.ShowModal() != wx.ID_OK:
-            return
-
-        self.__fsldir = dlg.GetPath()
- 
-        self.EndModal(wx.ID_OK)
-
-
-class CheckBoxMessageDialog(wx.Dialog):
-    """A ``wx.Dialog`` which displays a message, one or more ``wx.CheckBox``
-    widgets, with associated messages, an *Ok* button, and (optionally) a
-    *Cancel* button.
-    """
-
-    
-    def __init__(self,
-                 parent,
-                 title=None,
-                 message=None,
-                 cbMessages=None,
-                 cbStates=None,
-                 yesText=None,
-                 noText=None,
-                 cancelText=None,
-                 hintText=None,
-                 focus=None,
-                 icon=None,
-                 style=None):
-        """Create a ``CheckBoxMessageDialog``.
-
-        :arg parent:        A ``wx`` parent object.
-        
-        :arg title:         The dialog frame title.
-        
-        :arg message:       Message to show on the dialog.
-        
-        :arg cbMessages:    A list of labels, one for each ``wx.CheckBox``.
-        
-        :arg cbStates:      A list of initial states (boolean values) for
-                            each ``wx.CheckBox``.
-        
-        :arg yesText:       Text to show on the *yes*/confirm button. Defaults 
-                            to *OK*.
-
-        :arg noText:        Text to show on the *no* button. If not provided,
-                            there will be no *no* button.
-
-        :arg cancelText:    Text to show on the *cancel* button. If not 
-                            provided, there will be no cancel button.
-
-        :arg hintText:      If provided, shown as a "hint", in a slightly 
-                            faded font, between the checkboxes and the buttons.
-
-        :arg focus:         One of ``'yes'``, ``'no'```, or ``'cancel'``,
-                            specifying which button should be given initial
-                            focus.
-        
-        :arg icon:          A ``wx`` icon identifier (e.g. 
-                            ``wx.ICON_EXCLAMATION``).
-        
-        :arg style:         Passed through to the ``wx.Dialog.__init__``
-                            method. Defaults to ``wx.DEFAULT_DIALOG_STYLE``.
-        """
-
-        if style      is None: style      = wx.DEFAULT_DIALOG_STYLE
-        if title      is None: title      = ''
-        if message    is None: message    = ''
-        if cbMessages is None: cbMessages = ['']
-        if cbStates   is None: cbStates   = [False] * len(cbMessages)
-        if yesText    is None: yesText    = 'OK'
-
-        wx.Dialog.__init__(self, parent, title=title, style=style)
-
-        if icon is not None:
-            icon = wx.ArtProvider.GetMessageBoxIcon(icon) 
-            self.__icon = wx.StaticBitmap(self)
-
-            if fslplatform.wxFlavour == fslplatform.WX_PYTHON:
-                bmp = wx.EmptyBitmap(icon.GetWidth(), icon.GetHeight())
-            else:
-                bmp = wx.Bitmap()
-                
-            bmp.CopyFromIcon(icon)
-            self.__icon.SetBitmap(bmp)
-        else:
-            self.__icon = (1, 1)
-
-        self.__checkboxes = []
-        for msg, state in zip(cbMessages, cbStates):
-            cb = wx.CheckBox(self, label=msg)
-            cb.SetValue(state)
-            self.__checkboxes.append(cb)
-            
-        self.__message   = wx.StaticText(self, label=message)
-        self.__yesButton = wx.Button(    self, label=yesText, id=wx.ID_YES)
-
-        self.__yesButton.Bind(wx.EVT_BUTTON, self.__onYesButton)
-
-        if noText is not None:
-            self.__noButton = wx.Button(self, label=noText, id=wx.ID_NO)
-            self.__noButton.Bind(wx.EVT_BUTTON, self.__onNoButton)
-
-        else:
-            self.__noButton = None
- 
-        if cancelText is not None:
-            self.__cancelButton = wx.Button(self,
-                                            label=cancelText,
-                                            id=wx.ID_CANCEL)
-            self.__cancelButton.Bind(wx.EVT_BUTTON, self.__onCancelButton)
-        else:
-            self.__cancelButton = None
-
-        if hintText is not None:
-            self.__hint = wx.StaticText(self, label=hintText)
-            self.__hint.SetForegroundColour('#888888')
-        else:
-            self.__hint = None
-
-        self.__mainSizer    = wx.BoxSizer(wx.HORIZONTAL)
-        self.__contentSizer = wx.BoxSizer(wx.VERTICAL)
-        self.__btnSizer     = wx.BoxSizer(wx.HORIZONTAL)
-
-        self.__contentSizer.Add(self.__message,  flag=wx.EXPAND, proportion=1)
-        self.__contentSizer.Add((1, 20), flag=wx.EXPAND)
-        for cb in self.__checkboxes:
-            self.__contentSizer.Add(cb, flag=wx.EXPAND)
-
-        if self.__hint is not None:
-            self.__contentSizer.Add((1, 20), flag=wx.EXPAND)
-            self.__contentSizer.Add(self.__hint, flag=wx.EXPAND)
-
-        self.__contentSizer.Add((1, 20), flag=wx.EXPAND)
-        self.__btnSizer.Add((1, 1), flag=wx.EXPAND, proportion=1)
-
-        buttons = [self.__yesButton, self.__noButton, self.__cancelButton]
-        buttons = [b for b in buttons if b is not None]
-
-        for i, b in enumerate(buttons):
-            self.__btnSizer.Add(b)
-            if i != len(buttons) - 1:
-                self.__btnSizer.Add((5, 1), flag=wx.EXPAND)
-        
-        self.__contentSizer.Add(self.__btnSizer, flag=wx.EXPAND)
-
-        self.__mainSizer.Add(self.__icon,
-                             flag=wx.ALL | wx.CENTRE,
-                             border=20)
-        self.__mainSizer.Add(self.__contentSizer,
-                             flag=wx.EXPAND | wx.ALL,
-                             proportion=1,
-                             border=20)
-
-        self.__message.Wrap(self.GetSize().GetWidth())
-
-        yes  = self.__yesButton
-        no   = self.__noButton
-        cncl = self.__cancelButton
-
-        if   focus == 'yes':                         yes .SetDefault()
-        elif focus == 'no'     and no   is not None: no  .SetDefault()
-        elif focus == 'cancel' and cncl is not None: cncl.SetDefault()
-
-        self.SetSizer(self.__mainSizer)
-        self.Layout()
-        self.Fit()
-        self.CentreOnParent()
-
-
-    def CheckBoxState(self, index=0):
-        """After this ``CheckBoxMessageDialog`` has been closed, this method
-        will retrieve the state of the dialog ``CheckBox``.
-        """
-        return self.__checkboxes[index].GetValue()
-
-
-    def __onYesButton(self, ev):
-        """Called when the button on this ``CheckBoxMessageDialog`` is
-        clicked. Closes the dialog.
-        """
-        self.EndModal(wx.ID_YES)
-
-        
-    def __onNoButton(self, ev):
-        """Called when the button on this ``CheckBoxMessageDialog`` is
-        clicked. Closes the dialog.
-        """
-        self.EndModal(wx.ID_NO)
-
-        
-    def __onCancelButton(self, ev):
-        """If the ``CHECKBOX_MSGDLG_CANCEL_BUTTON`` style was set, this method
-        is called when the cancel button is clicked. Closes the dialog.
-        """
-        self.EndModal(wx.ID_CANCEL)
diff --git a/fsl/utils/imagepanel.py b/fsl/utils/imagepanel.py
deleted file mode 100644
index 5352bd100b2cb98718a74ae1858040aeab3343f5..0000000000000000000000000000000000000000
--- a/fsl/utils/imagepanel.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/env python
-#
-# imagepanel.py - A panel for displaying a wx.Image.
-#
-# Author: Paul McCarthy <pauldmccarthy@gmail.com>
-#
-"""This module provides the :class:`ImagePanel` class, for displaying a
-:class:`wx.Image`.
-"""
-
-import logging
-
-import wx
-
-from fsl.utils.platform import platform as fslplatform
-
-
-log = logging.getLogger(__name__)
-
-
-if fslplatform.wxFlavour == fslplatform.WX_PHOENIX: ImagePanelBase = wx.Panel
-else:                                               ImagePanelBase = wx.PyPanel
-
-
-class ImagePanel(ImagePanelBase):
-    """A :class:`wx.Panel` 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.
-        """
-
-        ImagePanelBase.__init__(self, parent)
-
-        self.Bind(wx.EVT_PAINT, self.Draw)
-        self.Bind(wx.EVT_SIZE,  self.__onSize)
-
-        self.SetImage(image)
-
-
-    def SetImage(self, image):
-        """Set the image that is displayed on this ``ImagePanel``.
-
-        :arg image: The :class:`wx.Image` object to display.
-        """
-        self.__image = image
-
-
-        if image is not None: self.SetMinSize(image.GetSize())
-        else:                 self.SetMinSize((0, 0))
-        
-        self.Refresh()
-
-        
-    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()
-        
-        
-    def Draw(self, ev=None):
-        """Draws this ``ImagePanel``. The image is scaled to the current panel
-        size.
-        """
-
-        self.ClearBackground()
-
-        if self.__image is None:
-            return
-
-        if ev is None: dc = wx.ClientDC(self)
-        else:          dc = wx.PaintDC( self)
-
-        if not dc.IsOk():
-            return 
-        
-        width, height = dc.GetSize().Get()
-
-        if width == 0 or height == 0:
-            return
-
-        bitmap = self.__image.Scale(width, height).ConvertToBitmap()
-        
-        dc.DrawBitmap(bitmap, 0, 0, False)
diff --git a/fsl/utils/layout.py b/fsl/utils/layout.py
deleted file mode 100644
index 95f1e40ccba3783712981642a34c10e936cee940..0000000000000000000000000000000000000000
--- a/fsl/utils/layout.py
+++ /dev/null
@@ -1,556 +0,0 @@
-#!/usr/bin/env python
-#
-# layout.py - Utility functions for calculating canvas sizes and laying them
-# out.
-#
-# Author: Paul McCarthy <pauldmccarthy@gmail.com>
-#
-"""Utility functions for calculating canvas sizes and laying them out.
-
-
-This module implements a simple layout manager, for laying out canvases and
-associated orientation labels. It is used primarily by the :mod:`.render`
-application, for off-screen rendering.
-
-You can use the following classes to define a layout:
-
-.. autosummary::
-   :nosignatures:
-
-   Bitmap
-   Space
-   HBox
-   VBox
-
-
-And the following functions to generate layouts and bitmaps:
-
-.. autosummary::
-   :nosignatures:
-
-   buildOrthoLayout
-   buildCanvasBox
-   padBitmap
-   layoutToBitmap
-
-
-A few functions are also provided for calculating the display size, in pixels,
-of one or more canvases which are displaying a defined coordinate system. The
-canvas sizes are calculated so that their aspect ratio, relative to the
-respective horizontal/vertical display axes, are maintained, and that the
-canvases are sized proportionally with respect to each other. The following
-size calculation functions are available:
-
-.. autosummary::
-   :nosignatures:
-
-   calcSizes
-   calcGridSizes
-   calcHorizontalSizes
-   calcVerticalSizes
-   calcPixWidth
-   calcPixHeight
-"""
-
-
-import logging
-
-import numpy as np
-
-
-log = logging.getLogger(__name__)
-
-
-class Bitmap(object):
-    """A class which encapsulates a RGBA bitmap, assumed to be a
-    ``numpy.uint8`` array of shape :math:`height \\times width \\times 4`).
-
-    .. warning:: Note the unusual array shape - height is the first axis,
-                 and width the second!
-
-    
-    A ``Bitmap`` instance has the following attributes:
-
-      - ``bitmap``: The bitmap data
-      - ``width``:  Bitmap width in pixels
-      - ``height``: Bitmap height in pixels
-    """
-
-    def __init__(self, bitmap):
-        """Create a ``Bitmap``.
-
-        :arg bitmap: :mod:`numpy` array containing the bitmap data.
-        """
-        self.bitmap = bitmap
-        self.width  = bitmap.shape[1]
-        self.height = bitmap.shape[0]
-
-        
-class Space(object):
-    """A class which represents empty space of a specific width/height.
-
-    
-    A ``Space`` instance has the following attributes:
-
-      - ``width``:  Width in pixels.
-      - ``height``: Height in pixels.
-    """
-
-    def __init__(self, width, height):
-        """Creat a ``Space``.
-
-        :arg width:  Width in pixels.
-
-        :arg height: Height in pixels.
-        """
-        self.width  = width
-        self.height = height
-
-        
-class HBox(object):
-    """A class which contains items to be laid out horizontally.
-
-    After creation, new items should be added via the :meth:`append` method.
-
-    A ``HBox`` instance has the following attributes:
-
-      - ``width``:  Total width in pixels.
-      - ``height``: Total height in pixels.
-      - ``items``:  List of items in this ``HBox``.
-    """
-
-    
-    def __init__(self, items=None):
-        """Create a ``HBox``.
-
-        :arg items: List of items contained in this ``HBox``.
-        """
-        self.width  = 0
-        self.height = 0
-        self.items  = []
-        if items is not None: map(self.append, items)
-
-        
-    def append(self, item):
-        """Append a new item to this ``HBox``. """
-        self.items.append(item)
-        self.width = self.width + item.width
-        if item.height > self.height:
-            self.height = item.height
-
-            
-class VBox(object):
-    """A class which contains items to be laid out vertically.
-
-    After creation, new items can be added via the :meth:`append` method.
-
-    A ``VBox`` instance has the following attributes:
-
-      - ``width``:  Total width in pixels.
-      - ``height``: Total height in pixels.
-      - ``items``:  List of items in this ``VBox``.    
-    """
-    
-    def __init__(self, items=None):
-        """Create a ``VBox``.
-
-        :arg items: List of items contained in this ``VBox``.
-        """ 
-        self.width  = 0
-        self.height = 0
-        self.items  = []
-        if items is not None: map(self.append, items)
-
-        
-    def append(self, item):
-        """Append a new item to this ``VBox``. """
-        self.items.append(item)
-        self.height = self.height + item.height
-        if item.width > self.width:
-            self.width = item.width
-
-
-def padBitmap(bitmap, width, height, vert, bgColour):
-    """Pads the given bitmap with zeros along the secondary axis (specified
-    with the ``vert`` parameter), so that it fits in the given
-    ``width``/``height``.
-
-    
-    :arg bitmap:   A ``numpy.array`` of size :math:`x \\times y \\times 4`
-                   containing a RGBA bitmap.
-    
-    :arg width:    Desired width in pixels.
-    
-    :arg height:   Desired height in pixels.
-    
-    :arg vert:     If ``vert`` is ``True``, the bitmap is padded 
-                   horizontally to fit ``width``. Otherwise, the 
-                   bitmap is padded vertically to fit ``height``.
-
-    :arg bgColour: Background colour to use for padding. Must be
-                   a ``(r, g, b, a)`` tuple with each channel in
-                   the range ``[0 - 255]``.
-    """
-    
-    iheight = bitmap.shape[0]
-    iwidth  = bitmap.shape[1]
-    
-    if vert:
-        if iwidth < width:
-            lpad   = int(np.floor((width - iwidth) / 2.0))
-            rpad   = int(np.ceil( (width - iwidth) / 2.0))
-            lpad   = np.zeros((iheight, lpad, 4), dtype=np.uint8)
-            rpad   = np.zeros((iheight, rpad, 4), dtype=np.uint8)
-            lpad[:] = bgColour
-            rpad[:] = bgColour
-            bitmap = np.hstack((lpad, bitmap, rpad))
-    else:
-        if iheight < height:
-            tpad   = int(np.floor((height - iheight) / 2.0))
-            bpad   = int(np.ceil(( height - iheight) / 2.0))
-            tpad   = np.zeros((tpad, iwidth, 4), dtype=np.uint8)
-            bpad   = np.zeros((bpad, iwidth, 4), dtype=np.uint8)
-            tpad[:] = bgColour
-            bpad[:] = bgColour 
-            bitmap = np.vstack((tpad, bitmap, bpad))
-
-    return bitmap
-
-
-def layoutToBitmap(layout, bgColour):
-    """Recursively turns the given ``layout`` object into a bitmap.
-
-    :arg layout:   A :class:`Bitmap`, :class:`Space`, :class:`HBox` or 
-                   :class:`VBox` instance.
-
-    :arg bgColour: Background colour used to fill in empty space. Must be
-                   a ``(r, g, b, a)`` tuple with channel values in the range
-                   ``[0, 255]``. Defaults to transparent.
-
-    :returns:      a ``numpy.uint8`` array of size
-                   :math:`height \\times width \\times 4`.
-    """
-
-    if bgColour is None: bgColour = [0, 0, 0, 0]
-    bgColour = np.array(bgColour, dtype=np.uint8)
-
-    # Space is easy 
-    if isinstance(layout, Space):
-        space = np.zeros((layout.height, layout.width, 4), dtype=np.uint8)
-        space[:] = bgColour
-        return space
-
-    # Bitmap is easy
-    elif isinstance(layout, Bitmap):
-        return np.array(layout.bitmap, dtype=np.uint8)
-
-    # Boxes require a bit of work
-    if   isinstance(layout, HBox): vert = False
-    elif isinstance(layout, VBox): vert = True
-
-    # Recursively bitmapify the children of the box
-    itemBmps = map(lambda i: layoutToBitmap(i, bgColour), layout.items)
-
-    # Pad each of the bitmaps so they are all the same
-    # size along the secondary axis (which is width
-    # if the layout is a VBox, and height if the layout
-    # is a HBox).
-    width    = layout.width
-    height   = layout.height 
-    itemBmps = map(lambda bmp: padBitmap(bmp, width, height, vert, bgColour),
-                   itemBmps)
-
-    if vert: return np.vstack(itemBmps)
-    else:    return np.hstack(itemBmps)
-
-
-def buildCanvasBox(canvasBmp, labelBmps, showLabels, labelSize):
-    """Builds a layout containing the given canvas bitmap, and orientation
-    labels (if ``showLabels`` is ``True``).
-
-    
-    :arg canvasBmp:  A ``numpy.uint8`` array containing a bitmap.
-    
-    :arg labelBmps:  Only used if ``showLabels`` is ``True``. ``numpy.uint8``
-                     arrays containing label bitmaps. Must be a
-                     dictionary of ``{side : numpy.uint8}`` mappings,
-                     and must have keys ``top``, ``bottom``, ``left`` and
-                     ``right``.
-    
-    :arg showLabels: If ``True``, the orientation labels provided in
-                     ``labelBmps`` are added to the layout.
-    
-    :arg labelSize:  Label sizes - the ``left``/``right`` label widths,
-                     and ``top``/``bottom`` label heights are padded to this
-                     size using ``Space`` objects.
-
-    :returns:        A :class:`Bitmap`  or :class:`VBox` instance.
-    """
-
-    if not showLabels: return Bitmap(canvasBmp)
-
-    row1Box = HBox([Space(labelSize, labelSize),
-                    Bitmap(labelBmps['top']),
-                    Space(labelSize, labelSize)])
-
-    row2Box = HBox([Bitmap(labelBmps['left']),
-                    Bitmap(canvasBmp),
-                    Bitmap(labelBmps['right'])])
-
-    row3Box = HBox([Space(labelSize, labelSize),
-                    Bitmap(labelBmps['bottom']),
-                    Space(labelSize, labelSize)])
-
-    return VBox((row1Box, row2Box, row3Box))
-
-
-def buildOrthoLayout(canvasBmps,
-                     labelBmps,
-                     layout,
-                     showLabels,
-                     labelSize):
-    """Builds a layout containing the given canvas bitmaps, label bitmaps, and
-    colour bar bitmap.
-
-    
-    :arg canvasBmps: A list of ``numpy.uint8`` arrays containing the canvas
-                     bitmaps to be laid out.
-
-    :arg layout:     One of ``'horizontal'``, ``'vertical'``, or ``'grid'``.
-
-    See the :func:`buildCanvasBox` for details on the other parameters.
-
-    
-    :returns: A :class:`HBox` or :class:`VBox` describing the layout.
-    """
-
-    if labelBmps is None:
-        labelBmps  = [None] * len(canvasBmps)
-        showLabels = False
-
-    canvasBoxes = map(lambda cbmp, lbmps: buildCanvasBox(cbmp,
-                                                         lbmps,
-                                                         showLabels,
-                                                         labelSize),
-                      canvasBmps,
-                      labelBmps)
-
-    if   layout == 'horizontal': canvasBox = HBox(canvasBoxes)
-    elif layout == 'vertical':   canvasBox = VBox(canvasBoxes)
-    elif layout == 'grid':
-        row1Box   = HBox([canvasBoxes[0], canvasBoxes[1]])
-        row2Box   = HBox([canvasBoxes[2], Space(canvasBoxes[1].width,
-                                                canvasBoxes[2].height)])
-        canvasBox = VBox((row1Box, row2Box))
-
-    return canvasBox
-
-
-def calcSizes(layout, canvasaxes, bounds, width, height):
-    """Convenience function which, based upon whether the `layout` argument
-    is ``'horizontal'``, ``'vertical'``, or ``'grid'``,  respectively calls
-    one of:
-    
-      - :func:`calcHorizontalSizes`
-      - :func:`calcVerticalSizes`
-      - :func:`calcGridSizes`
-
-    :arg layout:    String specifying the layout type.
-    
-    :arg canvsaxes: A list of tuples, one for each canvas to be laid out.
-                    Each tuple contains two values, ``(i, j)``, where ``i``
-                    is an index, into ``bounds``, specifying the canvas
-                    width, and ``j`` is an index into ``bounds``, specifying
-                    the canvas height, in the display coordinate system.
-    
-    :arg bounds:    A list of three values specifying the size of the display
-                    space.
-    
-    :arg width:     Maximum width in pixels.
-    
-    :arg height:    Maximum height in pixels.
-
-    :returns:       A list of ``(width, height)`` tuples, one for each canvas,
-                    each specifying the canvas width and height in pixels.
-    """
-    
-    layout = layout.lower()
-    func   = None
-
-    if   layout == 'horizontal': func = calcHorizontalSizes
-    elif layout == 'vertical':   func = calcVerticalSizes
-    elif layout == 'grid':       func = calcGridSizes
-
-    # a bad value for layout
-    # will result in an error
-    sizes = func(canvasaxes, bounds, width, height)
-
-    log.debug('For space ({}, {}) and {} layout, pixel '
-              'sizes for canvases {} ({}) are: {}'.format(
-                  width, height, layout, canvasaxes, bounds, sizes))
-
-    return sizes
-
-        
-def calcGridSizes(canvasaxes, bounds, width, height):
-    """Calculates the size of three canvases so that they are laid
-    out in a grid, i.e.:
-
-       0   1
-
-       2
-
-
-    .. note:: If less than three canvases are specified, they are passed to
-              the :func:`calcHorizontalLayout` function.
-
-    See :func:`calcSizes` for details on the arguments.
-    """
-
-    if len(canvasaxes) < 3:
-        return calcHorizontalSizes(canvasaxes, bounds, width, height)
-
-    canvasWidths  = [bounds[c[0]] for c in canvasaxes]
-    canvasHeights = [bounds[c[1]] for c in canvasaxes]
-    
-    ttlWidth      = float(canvasWidths[ 0] + canvasWidths[ 1])
-    ttlHeight     = float(canvasHeights[0] + canvasHeights[2])
-
-    sizes = []
-
-    for i in range(len(canvasaxes)):
-
-        cw = width  * (canvasWidths[ i] / ttlWidth)
-        ch = height * (canvasHeights[i] / ttlHeight) 
-
-        acw, ach = _adjustPixelSize(canvasWidths[ i],
-                                    canvasHeights[i],
-                                    cw,
-                                    ch)
-
-        if (float(cw) / ch) > (float(acw) / ach): cw, ch = cw, ach
-        else:                                     cw, ch = acw, ch
-        
-        sizes.append((cw, ch))
-
-    return sizes
-
-
-def calcVerticalSizes(canvasaxes, bounds, width, height):
-    """Calculates the size of up to three canvases so they are laid out
-    vertically.
-
-    See :func:`calcSizes` for details on the arguments.
-    """
-    return _calcFlatSizes(canvasaxes, bounds, width, height, True)
-
-
-def calcHorizontalSizes(canvasaxes, bounds, width, height):
-    """Calculates the size of up to three canvases so they are laid out
-    horizontally.
-
-    See :func:`calcSizes` for details on the arguments.
-    """ 
-    return _calcFlatSizes(canvasaxes, bounds, width, height, False)
-
-        
-def _calcFlatSizes(canvasaxes, bounds, width, height, vert=True):
-    """Used by :func:`calcVerticalSizes` and :func:`calcHorizontalSizes`.
-    
-    Calculates the width and height, in pixels, of each canvas.
-
-    :arg vert: If ``True`` the sizes are calculated for a vertical layout;
-               otherwise they are calculated for a horizontal layout.
-
-    See :func:`calcSizes` for details on the other arguments.
-
-    :returns:  A list of ``(width, height)`` tuples, one for each canvas,
-               each specifying the canvas width and height in pixels. 
-    """
-
-    # Get the canvas dimensions in world space
-    canvasWidths  = [bounds[c[0]] for c in canvasaxes]
-    canvasHeights = [bounds[c[1]] for c in canvasaxes]
-
-    maxWidth  = float(max(canvasWidths))
-    maxHeight = float(max(canvasHeights))
-    ttlWidth  = float(sum(canvasWidths))
-    ttlHeight = float(sum(canvasHeights))
-
-    if vert: ttlWidth  = maxWidth
-    else:    ttlHeight = maxHeight
-
-    sizes = []
-    for i in range(len(canvasaxes)):
-
-        if ttlWidth  == 0: cw = 0
-        else:              cw = width  * (canvasWidths[ i] / ttlWidth)
-
-        if ttlHeight == 0: ch = 0
-        else:              ch = height * (canvasHeights[i] / ttlHeight)
-
-        sizes.append((cw, ch))
-
-    return sizes
-
-
-def calcPixWidth(wldWidth, wldHeight, pixHeight):
-    """Given the dimensions of a space to be displayed, and the available
-    height in pixels, calculates the required pixel width.
-
-    :arg wldWidth:   Width of the display coordinate system
-
-    :arg wldHeight:  Height of the display coordinate system
-
-    :arg pixHeight:  Available height in pixels.
-
-    :returns:        The required width in pixels.
-    """
-    return _adjustPixelSize(wldWidth,
-                            wldHeight,
-                            pixHeight * (2 ** 32),
-                            pixHeight)[0]
-
-
-def calcPixHeight(wldWidth, wldHeight, pixWidth):
-    """Given the dimensions of a space to be displayed, and the available
-    width in pixels, calculates the required pixel height.
-
-    :arg wldWidth:   Width of the display coordinate system
-
-    :arg wldHeight:  Height of the display coordinate system
-
-    :arg pixWidth:   Available width in pixels.
-
-    :returns:        The required height in pixels. 
-    """ 
-    return _adjustPixelSize(wldWidth,
-                            wldHeight,
-                            pixWidth,
-                            pixWidth * (2 ** 32))[1]
-
-
-
-def _adjustPixelSize(wldWidth, wldHeight, pixWidth, pixHeight):
-    """Used by :func:`calcPixelWidth` and :func:`calcPixelHeight`.
-
-    Potentially reduces the given pixel width/height such that the
-    display space aspect ratio is maintained.
-    """
-
-    if any((pixWidth  == 0,
-            pixHeight == 0,
-            wldWidth  == 0,
-            wldHeight == 0)):
-        return 0, 0
-
-    pixRatio = float(pixWidth) / pixHeight
-    wldRatio = float(wldWidth) / wldHeight
-
-    if   pixRatio > wldRatio:
-        pixWidth  = wldWidth  * (pixHeight / wldHeight)
-            
-    elif pixRatio < wldRatio:
-        pixHeight = wldHeight * (pixWidth  / wldWidth)
-
-    return pixWidth, pixHeight
diff --git a/fsl/utils/runwindow.py b/fsl/utils/runwindow.py
deleted file mode 100644
index a26969e9f3d06b753c9d8975f8730b30a8a7a12a..0000000000000000000000000000000000000000
--- a/fsl/utils/runwindow.py
+++ /dev/null
@@ -1,314 +0,0 @@
-#!/usr/bin/env python
-#
-# runwindow.py - Run a process, display its output in a wx window.
-#
-# Author: Paul McCarthy <pauldmccarthy@gmail.com>
-#
-"""This module provides classes and functions for running a non-interactive
-process, and displaying its output.
-
-
-This module provides the :class:`RunPanel` and :class:`ProcessManager`
-classes, and a couple of associated convenience functions.
-
-.. autosummary::
-   :nosignatures:
-
-   RunPanel
-   ProcessManager
-   run
-   checkAndRun
-"""
-
-import os
-import signal
-import logging
-
-import subprocess as subp
-import threading  as thread
-
-try:    import queue
-except: import Queue as queue
-
-import wx
-
-
-log = logging.getLogger(__name__)
-
-
-class RunPanel(wx.Panel):
-    """A panel which displays a multiline text control, and a couple of
-    buttons along the bottom. ``RunPanel`` instances are created by the
-    :func:`run` function, and used/controlled by the :class:`ProcessManager`.
-
-
-    One of the buttons is intended to closes the window in which this panel
-    is contained. The second button is intended to terminate the running
-    process. Both buttons are unbound by default, so must be manually
-    configured by the creator.
-    
-
-    The text panel and buttons are available as the following attributes:
-
-      - ``text``:        The text panel.
-      - ``closeButton``: The `Close window` button.
-      - ``killButton``:  The `Terminate process` button.
-    """
-
-    def __init__(self, parent):
-        """Create a ``RunPanel``.
-
-        :arg parent: The :mod:`wx` parent object.
-        """
-        wx.Panel.__init__(self, parent)
-
-        self.sizer = wx.BoxSizer(wx.VERTICAL)
-        self.SetSizer(self.sizer) 
-        
-        # Horizontal scrolling no work in OSX
-        # mavericks. I think it's a wxwidgets bug.
-        self.text  = wx.TextCtrl(self,
-                                 style=wx.TE_MULTILINE |
-                                       wx.TE_READONLY  |
-                                       wx.TE_DONTWRAP  |
-                                       wx.HSCROLL)
-
-        self.sizer.Add(self.text, flag=wx.EXPAND, proportion=1)
-
-        self.btnPanel = wx.Panel(self)
-        self.btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.btnPanel.SetSizer(self.btnSizer)
-        
-        self.sizer.Add(self.btnPanel, flag=wx.EXPAND)
-
-        self.killButton  = wx.Button(self.btnPanel, label='Terminate process')
-        self.closeButton = wx.Button(self.btnPanel, label='Close window')
-
-        self.btnSizer.Add(self.killButton,  flag=wx.EXPAND, proportion=1)
-        self.btnSizer.Add(self.closeButton, flag=wx.EXPAND, proportion=1)
-
-
-class ProcessManager(thread.Thread):
-    """A thread which manages the execution of a child process, and capture
-    of its output.
-
-    The process output is displayed in a :class:`RunPanel` which must be
-    passed to the ``ProcessManager`` on creation.
-
-    The :meth:`termProc` method can be used to terminate the child process
-    before it has completed.
-    """
-
-    def __init__(self, cmd, parent, runPanel, onFinish):
-        """Create a ``ProcessManager``.
-        
-        :arg cmd:      String or list of strings, the command to be
-                       executed.
-        
-        :arg parent:   :mod:`wx` parent object.
-        
-        :arg runPanel: A :class:`RunPanel` instance , for displaying the
-                       child process output.
-        
-        :arg onFinish: Callback function to be called when the process
-                       finishes. May be ``None``. Must accept two parameters,
-                       the GUI ``parent`` object, and the process return code.
-        """
-        thread.Thread.__init__(self, name=cmd[0])
-        
-        self.cmd      = cmd
-        self.parent   = parent
-        self.runPanel = runPanel
-        self.onFinish = onFinish
-
-        # Handle to the Popen object which represents
-        # the child process. Created in run().
-        self.proc = None
-
-        # A queue for sharing data between the thread which
-        # is blocking on process output (this thread object),
-        # and the wx main thread which writes that output to
-        # the runPanel
-        self.outq = queue.Queue()
- 
-        # Put the command string at the top of the text control
-        self.outq.put(' '.join(self.cmd) + '\n\n')
-        wx.CallAfter(self.__writeToPanel)
-
-
-    def __writeToPanel(self):
-        """Reads a string from the output queue, and appends it
-        to the :class:`RunPanel`. This method is intended to be
-        executed via :func:`wx.CallAfter`.
-        """
-        
-        try:                output = self.outq.get_nowait()
-        except queue.Empty: output = None
-
-        if output is None: return
-
-        # ignore errors - the user may have closed the
-        # runPanel window before the process has completed
-        try:    self.runPanel.text.WriteText(output)
-        except: pass
- 
-
-    def run(self):
-        """Starts the process, then reads its output line by line, writing
-        each line asynchronously to the :class:`RunPanel`.  When the
-        process ends, the ``onFinish`` method (if there is one) is called. 
-        If the process finishes abnormally (with a non-0 exit code) a warning
-        dialog is displayed.
-        """
-
-        # Run the command. The preexec_fn parameter creates
-        # a process group, so we are able to kill the child
-        # process, and all of its children, if necessary. 
-        log.debug('Running process: "{}"'.format(' '.join(self.cmd)))
-        self.proc = subp.Popen(self.cmd,
-                               stdout=subp.PIPE,
-                               bufsize=1,
-                               stderr=subp.STDOUT,
-                               preexec_fn=os.setsid)
-
-        # read process output, line by line, pushing
-        # each line onto the output queue and
-        # asynchronously writing it to the runPanel
-        for line in self.proc.stdout:
-            
-            log.debug('Process output: {}'.format(line.strip()))
-            self.outq.put(line)
-            wx.CallAfter(self.__writeToPanel)
-
-        # When the above for loop ends, it means that the stdout
-        # pipe has been broken. But it doesn't mean that the
-        # subprocess is finished. So here, we wait until the
-        # subprocess terminates, before continuing,
-        self.proc.wait()
-
-        retcode = self.proc.returncode
-        
-        log.debug(    'Process finished with return code {}'.format(retcode))
-        self.outq.put('Process finished with return code {}'.format(retcode))
-
-        wx.CallAfter(self.__writeToPanel)
-
-        # Disable the 'terminate' button on the run panel
-        def updateKillButton():
-
-            # ignore errors - see __writeToPanel
-            try:    self.runPanel.killButton.Enable(False)
-            except: pass
-
-        wx.CallAfter(updateKillButton)
-
-        # Run the onFinish handler, if there is one
-        if self.onFinish is not None:
-            wx.CallAfter(self.onFinish, self.parent, retcode)
-
-        
-    def termProc(self):
-        """Attempts to kill the running child process."""
-        
-        log.debug('Attempting to send SIGTERM to '
-                  'process group with pid {}'.format(self.proc.pid))
-        os.killpg(self.proc.pid, signal.SIGTERM)
-
-        # put a message on the runPanel
-        self.outq.put('\nSIGTERM sent to process\n\n')
-        wx.CallAfter(self.__writeToPanel)
-
-
-def run(name, cmd, parent, onFinish=None, modal=True):
-    """Runs the given command, displaying the output in a :class:`RunPanel`.
-    
-    :arg name:     Name of the tool to be run, used in the window title.
-    
-    :arg cmd:      String or list of strings, specifying the command to be
-                   executed.
-    
-    :arg parent:   :mod:`wx` parent object.
-    
-    :arg modal:    If ``True``, the frame which contains the ``RunPanel``
-                   will be modal.
-
-    :arg onFinish: Function to be called when the process ends. Must
-                   accept two parameters - a reference to the :mod:`wx`
-                   frame/dialog displaying the process output, and
-                   the exit code of the application.
-    """
-
-    # Create the GUI - if modal, the easiest
-    # approach is to use a wx.Dialog
-    if modal:
-        frame = wx.Dialog(
-            parent,
-            title=name,
-            style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
-    else:
-        frame = wx.Frame(parent, title=name)
-
-    panel = RunPanel(frame)
-
-    # Create the thread which runs the child process
-    mgr = ProcessManager(cmd, parent, panel, onFinish)
-
-    # Bind the panel control buttons so they do stuff
-    panel.closeButton.Bind(wx.EVT_BUTTON, lambda e: frame.Close())
-    panel.killButton .Bind(wx.EVT_BUTTON, lambda e: mgr.termProc())
-
-    # Run the thread which runs the child process
-    mgr.start()
-
-    # layout and show the window
-    frame.Layout()
-    if modal: frame.ShowModal()
-    else:     frame.Show()
- 
-
-def checkAndRun(name,
-                opts,
-                parent,
-                cmdFunc,
-                optLabels={},
-                modal=True,
-                onFinish=None):
-    """Validates the given options. If invalid, a dialog is shown,
-    informing the user about the errors. Otherwise, the tool is
-    executed, and its output shown in a dialog window. Parameters:
-    
-    
-    :arg opts:      A :class:`props.HasProperties` object to be
-                    validated.
-    
-    :arg cmdFunc:   Function which takes a :class:`props.HasProperties`
-                    object, and returns a command to be executed (as a 
-                    list of strings), which will be passed to the :func:`run`
-                    function.
-    
-    :arg optLabels: Dictionary containing property ``{name : label}`` mappings.
-                    Used in the error dialog, if any options are invalid.
-
-    See :func:`run` for details on the other arguments.
-    """
-
-    errors = opts.validateAll()
-
-    if len(errors) > 0:
-
-        msg = 'There are numerous errors which need '\
-              'to be fixed before {} can be run:\n'.format(name)
-
-        for opt, error in errors:
-            
-            if opt in optLabels: name = optLabels[opt]
-            msg = msg + '\n - {}: {}'.format(opt, error)
-
-        wx.MessageDialog(
-            parent,
-            message=msg,
-            style=wx.OK | wx.ICON_ERROR).ShowModal()
-        
-    else:
-        cmd = cmdFunc(opts)
-        run(name, cmd, parent, onFinish, modal)
diff --git a/fsl/utils/status.py b/fsl/utils/status.py
deleted file mode 100644
index ee40e787a529f86040129c2e398e80b72112d300..0000000000000000000000000000000000000000
--- a/fsl/utils/status.py
+++ /dev/null
@@ -1,245 +0,0 @@
-#!/usr/bin/env python
-#
-# status.py - A simple interface for displaying messages.
-#
-# Author: Paul McCarthy <pauldmccarthy@gmail.com>
-#
-"""This is a little module which provides an interface for displaying a
-message, or status update, to the user.  The ``status`` module provides the
-following functions:
-
- .. autosummary::
-    :nosignatures:
-
-    setTarget
-    update
-    clearStatus
-
-A couple of other functions are also provided, for reporting error messages
-to the user:
-
- .. autosummary::
-    :nosignatures:
-
-    reportError
-    reportIfError
-    reportErrorDecorator
-
-
-The :func:`update` function may be used to display a message. By default, the
-message is simply logged (via the ``logging`` module). However, if a status
-target has been set via the :func:`setTarget` function, the message is also
-passed to this target.
-
-
-.. warning:: If the status update target is a ``wx`` GUI object, you must
-             make sure that it is updated asynchronously (e.g. via
-             ``wx.CallAfter``). 
-"""
-
-
-import            threading
-import            contextlib
-import            logging
-import            inspect
-import os.path as op
-
-
-log = logging.getLogger(__name__)
-
-
-_statusUpdateTarget = None
-"""A reference to the status update target - this is ``None`` by default, and
-can be set via :func:`setTarget`.
-"""
-
-
-_clearThread = None
-"""Reference to a :class:`ClearThread`, which is a daemon thread that clears
-the status after the timeout passed to the :func:`update` function. 
-"""
-
-
-def setTarget(target):
-    """Set a target function to receive status updates. The ``target`` must
-    be a function which accepts a string as its sole parameter.
-    """
-    global _statusUpdateTarget
-    _statusUpdateTarget = target
-
-
-def update(message, timeout=1.0):
-    """Display a status update to the user. The message is logged and,
-    if a status update target has been set, passed to the target.
-
-    :arg timeout: Timeout (in seconds) after which the status will be
-                  cleared (via the :class:`ClearThread`). Pass in ``None``
-                  to disable this behaviour.
-
-
-    .. note:: The ``timeout`` method only makes sense to use if the status
-              target is a GUI widget of some sort.
-    """
-
-    global _clearThread
-    global _statusUpdateTarget
-
-    if log.getEffectiveLevel() == logging.DEBUG:
-        
-        frame   = inspect.stack()[1]
-        module  = frame[1]
-        linenum = frame[2]
-        module  = op.basename(module)
-
-        log.debug('[{}:{}] {}'.format(module, linenum, message))
-
-    if _statusUpdateTarget is None:
-        return
-
-    _statusUpdateTarget(message)
-
-    if timeout is not None:
-        log.debug('timeout is not None - starting clear thread')
-        
-        if _clearThread is None:
-            _clearThread = ClearThread()
-            _clearThread.start()
-
-        _clearThread.clear(timeout)
-    else:
-        if _clearThread is not None:
-            _clearThread.veto()
-            log.debug('No timeout - vetoing clear thread')
-
-
-def clearStatus():
-    """Clear the status. If a status update target has been set, it is passed
-    the empty string.
-    """ 
-    if _statusUpdateTarget is None:
-        return
-        
-    _statusUpdateTarget('')
-
-
-def reportError(title, msg, err):
-    """Reports an error to the user in a generic manner. If a GUI is available,
-    (see the :meth.`.Platform.haveGui` attribute), a ``wx.MessageBox`` is
-    shown. Otherwise a log message is generated.
-    """
-
-    from .platform import platform as fslplatform
-    from .         import async
-
-    if fslplatform.haveGui:
-        msg = '{}\n\nDetails: {}'.format(msg, str(err))
-        
-        import wx
-        async.idle(wx.MessageBox, msg, title, wx.ICON_ERROR | wx.OK)
-    
-
-@contextlib.contextmanager
-def reportIfError(title, msg, raiseError=True, report=True):
-    """A context manager which calls :func:`reportError` if the enclosed code
-    raises an ``Exception``.
-
-    :arg raiseError: If ``True``, the ``Exception`` which was raised is
-                     propagated upwards.
-
-    :arg report:     Defaults to ``True``. If ``False``, an error message
-                     is logged, but :func:`reportError` is not called.
-    """
-    try:
-        yield
-        
-    except Exception as e:
-
-        log.error('{}: {}'.format(title, msg), exc_info=True)
-
-        if report:
-            reportError(title, msg, e)
-
-        if raiseError:
-            raise
-
-
-def reportErrorDecorator(*args, **kwargs):
-    """A decorator which wraps the decorated function with
-    :func:`reportIfError`.
-    """ 
-
-    def decorator(func):
-        def wrapper(*wargs, **wkwargs):
-            with reportIfError(*args, **kwargs):
-                func(*wargs, **wkwargs)
-
-        return wrapper
-
-    return decorator
-
-    
-class ClearThread(threading.Thread):
-    """The ``ClearThread`` is a daemon thread used by the :func:`update`
-    function. Only one ``ClearThread`` is ever started - it is started on the
-    first call to ``update`` when a timeout is specified.
-
-    The ``ClearThread`` waits until the :meth:`clear` method is called.
-    It then waits for the specified timeout and, unless another call to
-    :meth:`clear`, or a call to :meth:`veto` has been made, clears the
-    status via a call to :func:`clearStatus`.
-    """
-
-    
-    def __init__(self):
-        """Create a ``ClearThread``. """
-
-        threading.Thread.__init__(self)
-
-        self.daemon       = True
-        self.__clearEvent = threading.Event()
-        self.__vetoEvent  = threading.Event()
-        self.__timeout    = None
-
-        
-    def clear(self, timeout):
-        """Clear the status after the specified timeout (in seconds). """
-        
-        self.__timeout = timeout
-        self.__vetoEvent .clear()
-        self.__clearEvent.set()
-
-
-    def veto(self):
-        """If this ``ClearThread`` is waiting on a timeout to clear
-        the status, a call to ``veto`` will prevent it from doing so.
-        """
-        self.__vetoEvent.set()
-
-        
-    def run(self):
-        """The ``ClearThread`` function. Infinite loop which waits until
-        the :meth:`clear` method is called, and then clears the status
-        (via a call to :func:`clearStatus`).
-        """
-
-        while True:
-
-            self.__vetoEvent .clear()
-            self.__clearEvent.wait()
-            self.__clearEvent.clear()
-
-            # http://bugs.python.org/issue14623
-            #
-            # When the main thread exits, daemon threads will
-            # continue to run after the threading module is
-            # destroyed. Calls to the Event methods can thus
-            # result in errors.
-            try:
-                if not self.__clearEvent.wait(self.__timeout) and \
-                   not self.__vetoEvent.isSet():
-
-                    log.debug('Timeout - clearing status')
-                    clearStatus()
-                    
-            except TypeError:
-                return
diff --git a/fsl/utils/textbitmap.py b/fsl/utils/textbitmap.py
deleted file mode 100644
index 3320284b075849e9e8845b707049f1577fe547a8..0000000000000000000000000000000000000000
--- a/fsl/utils/textbitmap.py
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/env python
-#
-# textbitmap.py - A function which renders some text using matplotlib, and
-# returns it as an RGBA bitmap.
-#
-# Author: Paul McCarthy <pauldmccarthy@gmail.com>
-#
-"""This module provides a single function, :func:`textBitmap`, which renders
-some text off-screen using :mod:`matplotlib`, and returns it as an RGBA bitmap.
-"""
-
-
-def textBitmap(text,
-               width,
-               height,
-               fontSize,
-               fgColour,
-               bgColour,
-               alpha=1.0):
-    """Draw some text using :mod:`matplotlib`.
-
-
-    The rendered text is returned as a RGBA bitmap within a ``numpy.uint8``
-    array of size :math:`w \\times h \\times 4`, with the top-left pixel
-    located at index ``[0, 0, :]``.
-
-    :arg text:     Text to render.
-    
-    :arg width:    Width in pixels.
-    
-    :arg height:   Height in pixels.
-    
-    :arg fontSize: Font size in points.
-    
-    :arg fgColour: Foreground (text) colour - can be any colour specification
-                   that is accepted by :mod:`matplotlib`.
-    
-    :arg bgColour: Background colour  - can be any colour specification that
-                   is accepted by :mod:`matplotlib`..
-    
-    :arg alpha:    Text transparency, in the range ``[0.0 - 1.0]``.
-    """
-
-    # Imports are expensive
-    import numpy                           as np
-    import matplotlib.backends.backend_agg as mplagg
-    import matplotlib.figure               as mplfig
-
-    dpi    = 96.0
-    fig    = mplfig.Figure(figsize=(width / dpi, height / dpi),
-                           dpi=dpi)
-    canvas = mplagg.FigureCanvasAgg(fig)
-    ax     = fig.add_axes([0, 0, 1, 1])
-    ax.axis('off')
-
-    if bgColour is not None: fig.patch.set_facecolor(bgColour)
-    else:                    fig.patch.set_alpha(0)
-
-    ax.set_xticks([])
-    ax.set_yticks([])
-
-    ax.text(0.5,
-            0.5,
-            text,
-            fontsize=fontSize,
-            verticalalignment='center',
-            horizontalalignment='center',
-            transform=ax.transAxes,
-            color=fgColour,
-            alpha=alpha)
-
-    try:    fig.tight_layout()
-    except: pass
-
-    canvas.draw()
-    buf = canvas.tostring_argb()
-    ncols, nrows = canvas.get_width_height()
-
-    bitmap = np.fromstring(buf, dtype=np.uint8)
-    bitmap = bitmap.reshape(nrows, ncols, 4)
-
-    rgb = bitmap[:, :, 1:]
-    a   = bitmap[:, :, 0]
-    bitmap = np.dstack((rgb, a))
-
-    return bitmap 
diff --git a/fsl/utils/typedict.py b/fsl/utils/typedict.py
deleted file mode 100644
index 2c587f44b8fc6a52a8c1b42af7967a005a1dbb26..0000000000000000000000000000000000000000
--- a/fsl/utils/typedict.py
+++ /dev/null
@@ -1,334 +0,0 @@
-#!/usr/bin/env python
-#
-# typedict.py - Provides the TypeDict class.
-#
-# Author: Paul McCarthy <pauldmccarthy@gmail.com>
-#
-"""This module provides the :class:`TypeDict` class, a type-aware dictionary.
-"""
-
-
-import six
-
-import collections
-
-
-class TypeDict(object):
-    """A type-aware dictionary.
-
-
-    The purpose of the ``TypeDict`` is to allow value lookup using either
-    classes or instances as keys. The ``TypeDict`` can be used in the same way
-    that you would use a regular ``dict``, but the ``get`` and ``__getitem__``
-    methods have some extra functionality.
-
-    
-    **Easy to understand example**
-
-    
-    Let's say we have a class with some properties::
-
-        import fsl.utils.typedict as td
-
-        class Animal(object):
-            isMammal = True
-            numLegs  = 4
-
-    
-    And we want to associate some tooltips with those properties::
-
-        tooltips = td.TypeDict({
-
-            'Animal.isMammal' : 'Set this to True for mammals, '
-                                'False for reptiles.',
-            'Animal.numLegs'  : 'The nuber of legs on this animal.' 
-        })
-
-    Because we used a ``TypeDict``, we can now look up those tooltips
-    in a number of ways::
-
-        a = Animal()
-
-        # Lookup by string (equivalent to a normal dict lookup)
-        tt = tooltips['Animal.isMammal']
-
-        # Lookup by class
-        tt = tooltips[Animal, 'isMammal']
-
-        # Lookup by instance
-        tt = tooltips[a, 'isMammal']
-
-
-    This functionality also works across class hierarchies::
-
-        class Cat(Animal):
-           numYoutubeHits = 10
-
-        tooltips = td.TypeDict({
-
-            'Animal.isMammal'    : 'Set this to True for mammals, '
-                                   'False for reptiles.',
-            'Animal.numLegs'     : 'The nuber of legs on this animal.',
-            'Cat.numYoutubeHits' : 'Number of youtube videos this cat '
-                                   'has starred in.'
-        })
-
-        c = Cat()
-
-        isMammalTooltip    = tooltips[Cat,  'isMammal']
-        numLegsTooltip     = tooltips[c,    'numLegs']
-        youtubeHitsTooltip = tooltips[c,    'numYoutubeHits']
-
-        # Class-hierachy-aware TypeDict lookups only
-        # work when you pass in an instance/class as
-        # the key - the following will result in a
-        # KeyError:
-        t = tooltips['Cat.numLegs']
-
-
-    The :meth:`get` method has some extra functionality for working with 
-    class hierarchies::
-
-
-        tooltips = td.TypeDict({
-
-            'Animal.isMammal'    : 'Set this to True for mammals, '
-                                   'False for reptiles.',
-    
-            'Animal.numLegs'     : 'The nuber of legs on this animal.',
-
-            'Cat.numLegs'        : 'This will be equal to four for all cats, '
-                                    'but could be less for disabled cats, '
-                                    'or more for lucky cats.',
-    
-            'Cat.numYoutubeHits' : 'Number of youtube videos this cat '
-                                   'has starred in.'
-        })
-
-        print tooltips.get((c, 'numLegs'))
-        #  'This will be equal to four for all cats, but could '
-        #  'be less for disabled cats, or more for lucky cats.'
-
-        print tooltips.get((c, 'numLegs'), allhits=True)
-        # ['This will be equal to four for all cats, but could '
-        #  'be less for disabled cats, or more for lucky cats.',
-        #  'The nuber of legs on this animal.']
-
-        print tooltips.get((c, 'numLegs'), allhits=True, bykey=True)
-        # {('Animal', 'numLegs'): 'The nuber of legs on this animal.',
-        #  ('Cat',    'numLegs'): 'This will be equal to four for all cats, '
-        #                         'but could be less for disabled cats, or '
-        #                         'more for lucky cats.'}
-
-    
-    **Boring technical description**
-
-    
-    The ``TypeDict`` is a custom dictionary which allows classes or class
-    instances to be used as keys for value lookups, but internally transforms
-    any class/instance keys into strings. Tuple keys are supported. Value
-    assignment with class/instance keys is not supported. All keys are
-    transformed via the :meth:`tokenifyKey` method before being internally
-    used and/or stored.
-
-    If a class/instance is passed in as a key, and there is no value
-    associated with that class, a search is performed on all of the base
-    classes of that class to see if any values are present for them.
-    """
-
-    
-    def __init__(self, initial=None):
-        """Create a ``TypeDict``.
-
-        :arg initial: Dictionary containing initial values.
-        """
-        
-        if initial is None:
-            initial = {}
-        
-        self.__dict = {}
-
-        for k, v in initial.items():
-            self[k] = v
-
-
-    def __str__(self):
-        return self.__dict.__str__()
-
-
-    def __repr__(self):
-        return self.__dict.__repr__()
-
-
-    def __len__(self):
-        return len(self.__dict)
-
-
-    def keys(self):
-        return self.__dict.keys()
-
-
-    def values(self):
-        return self.__dict.values()
-
-
-    def items(self):
-        return self.__dict.items()
-
-
-    def __setitem__(self, key, value):
-        self.__dict[self.tokenifyKey(key)] = value
-
-
-    def tokenifyKey(self, key):
-        """Turns a dictionary key, which may have been specified as a
-        string, or a combination of strings and types, into a tuple.
-        """
-
-        if isinstance(key, six.string_types):
-            if '.' in key: return tuple(key.split('.'))
-            else:          return key
-
-        if isinstance(key, collections.Sequence):
-
-            tKeys = map(self.tokenifyKey, key)
-            key   = []
-
-            for tk in tKeys:
-                if   isinstance(tk, six.string_types):     key.append(tk)
-                elif isinstance(tk, collections.Sequence): key += list(tk)
-                else:                                      key.append(tk)
-            
-            return tuple(key)
-
-        return key
-
-        
-    def get(self, key, default=None, allhits=False, bykey=False):
-        """Retrieve the value associated with the given key. If
-        no value is present, return the specified ``default`` value,
-        which itself defaults to ``None``.
-
-        If the specified key contains a class or instance, and the
-        ``allhits`` argument evaluates to ``True``, the entire class
-        hierarchy is searched, and all values present for the class,
-        and any base class, are returned as a sequence.
-
-        If ``allhits`` is ``True`` and the ``bykey`` parameter is also
-        set to ``True``, a dictionary is returned rather than a sequence,
-        where the dictionary contents are the subset of this dictionary,
-        containing the keys which equated to the given key, and their
-        corresponding values.
-        """
-
-        try:             return self.__getitem__(key, allhits, bykey)
-        except KeyError: return default
-
-        
-    def __getitem__(self, key, allhits=False, bykey=False):
-
-        origKey = key
-        key     = self.tokenifyKey(key)
-        bases   = []
-
-        # Make the code a bit easier by
-        # treating non-tuple keys as tuples
-        if not isinstance(key, tuple):
-            key = tuple([key])
-
-        newKey = []
-
-        # Transform any class/instance elements into
-        # their string representation (the class name)
-        for elem in key:
-            
-            if isinstance(elem, type):
-                newKey.append(elem.__name__)
-                bases .append(elem.__bases__)
-                
-            elif not isinstance(elem, (str, int)):
-                newKey.append(elem.__class__.__name__)
-                bases .append(elem.__class__.__bases__)
-                
-            else:
-                newKey.append(elem)
-                bases .append(None)
-
-        key  = newKey
-
-        keys = []
-        hits = []
-            
-        while True:
-
-            # If the key was not a tuple turn
-            # it back into a single element key
-            # for the lookup
-            if len(key) == 1: lKey = key[0]
-            else:             lKey = tuple(key)
-
-            val = self.__dict.get(lKey, None)
-
-            # We've found a value for the key
-            if val is not None:
-
-                # If allhits is false, just return the value
-                if not allhits: return val
-
-                # Otherwise, accumulate the value, and keep
-                # searching
-                else:
-                    hits.append(val)
-                    if bykey:
-                        keys.append(lKey)
-
-            # No more base classes to search for - there
-            # really is no value associated with this key
-            elif all([b is None for b in bases]):
-                raise KeyError(key)
-
-            # Search through the base classes to see
-            # if a value is present for one of them
-            for i, (elem, elemBases) in enumerate(zip(key, bases)):
-                if elemBases is None:
-                    continue
-
-                # test each of the base classes 
-                # of the current tuple element
-                for elemBase in elemBases:
-
-                    newKey    = list(key)
-                    newKey[i] = elemBase
-
-                    if len(newKey) == 1: newKey = newKey[0]
-                    else:                newKey = tuple(newKey)
-
-                    try:
-                        newVal = self.__getitem__(newKey, allhits, bykey)
-                    except KeyError:
-                        continue
-
-                    if not allhits:
-                        return newVal
-                    else:
-                        if bykey:
-                            newKeys, newVals = zip(*newVal.items())
-                            keys.extend(newKeys)
-                            hits.extend(newVals)
-                        else:
-                            hits.extend(newVal)
-
-            # No value for any base classes either
-            if len(hits) == 0:
-                raise KeyError(origKey)
-
-            # if bykey is true, return a dict
-            # containing the values and their
-            # corresponding keys
-            if bykey:
-                return dict(zip(keys, hits))
-
-            # otherwise just return the
-            # list of matched values
-            else:
-                return hits
diff --git a/fsl/utils/webpage.py b/fsl/utils/webpage.py
deleted file mode 100644
index 962c6444fb39beab8168f5716fe10da3a8ab7ae6..0000000000000000000000000000000000000000
--- a/fsl/utils/webpage.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env python
-#
-# webpage.py - Convenience functions for opening a URL in a web browser.
-#
-# Author: Paul McCarthy <pauldmccarthy@gmail.com>
-#
-"""This module provides convenience functions for opening a URL in a web
-browser.
-
-The following functions are provided:
-
-.. autosummary::
-   :nosignatures:
-
-   fileToUrl
-   openPage
-   openFile
-   localHelpUrl
-   openLocalHelp
-"""
-
-import            os
-import os.path as op
-import            webbrowser
-
-
-def fileToUrl(fileName):
-    """Converts a file path to a URL. """
-    
-    import urlparse
-    import urllib
-    return urlparse.urljoin(
-        'file:', urllib.pathname2url(fileName))
-
-
-
-def openPage(url):
-    """Opens the given URL in the system-default web browser."""
-    webbrowser.open(url)
-
-
-def openFile(fileName):
-    """Opens the given file in the system-default web browser."""
-    openPage(fileToUrl(fileName))
-
-
-def localHelpUrl(toolName):
-    """Checks the ``$FSLDIR`` to see if a local help page exists for the
-    FSL tool with the specified name.
-    """
-    fsldir = os.environ.get('FSLDIR', None)
-
-    if fsldir is None:
-        return None
-
-    toolName = toolName.lower()
-    localUrl = op.join(fsldir, 'doc', 'redirects', '{}.html'.format(toolName))
-
-    if op.exists(localUrl):
-        return fileToUrl(localUrl)
-
-    return None
-
-
-def openLocalHelp(toolName):
-    """Attempts to open the locally hosted FSL help documentation
-    for the given FSL tool. If there is no help page for the
-    given tool, attempts to open the FSL wiki.
-    """
-
-    localUrl = localHelpUrl(toolName)
-
-    if localUrl is None:
-        localUrl = "http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/"
-
-    openPage(localUrl)
diff --git a/tests/test_typedict.py b/tests/test_typedict.py
deleted file mode 100644
index fe19bcf2b869fe3aa43f5359aa6e16db642044e1..0000000000000000000000000000000000000000
--- a/tests/test_typedict.py
+++ /dev/null
@@ -1,242 +0,0 @@
-#!/usr/bin/env python
-#
-# test_typedict.py -
-#
-# Author: Paul McCarthy <pauldmccarthy@gmail.com>
-#
-
-import itertools as it
-import pytest
-
-import fsl.utils.typedict as typedict
-
-
-def test_create():
-    
-    td = typedict.TypeDict()
-
-
-    assert len(td)          == 0
-    assert len(td.keys())   == 0
-    assert len(td.values()) == 0
-    assert len(td.items())  == 0
-
-    keys   = [0,
-              1,
-              2,
-              'a',
-              'b',
-              'c',
-              'a.b',
-              'a.b.c',
-              ('a', 'c'),
-              ('a',  0)]
-    values = list(range(len(keys)))
-    
-    td = typedict.TypeDict(        dict(zip(keys, values)))
-    td = typedict.TypeDict(initial=dict(zip(keys, values)))
-
-    print(     td)
-    print(repr(td))
-
-    tknkeys = [td.tokenifyKey(k) for k in keys]
-
-    assert len(td)                   == len(keys)
-    assert list(sorted(td.keys()))   == list(sorted(tknkeys))
-    assert list(sorted(td.values())) == list(sorted(values))
-    assert list(sorted(td.items()))  == list(sorted(zip(tknkeys, values)))
-
-    for k, v in zip(keys, values):
-        assert td[k] == v
-
-    with pytest.raises(KeyError):
-        td['non-existent']
-
-    assert td.get('non-existent') is None
-    assert td.get('non-existent', 'default') == 'default'
-
-
-def test_class_keys():
-
-    class A(object):
-        pass
-
-    class B(object):
-        pass
-
-    class C(object):
-        pass
-
-    td = typedict.TypeDict()
-
-    a  = A()
-    b  = B()
-    c  = C()
-
-    # TypeDict [currently] does not allow value
-    # assignment with classes/instances as keys -
-    # we must use the class name, encoded as a
-    # string, when assigning.
-    keycomponents = ['A', 'B', 'C', 'att1', 'att2', 'att3']
-    keys          = list(it.chain(it.permutations(keycomponents, 1),
-                                  it.permutations(keycomponents, 2),
-                                  it.permutations(keycomponents, 3),
-                                  it.permutations(keycomponents, 4),
-                                  it.permutations(keycomponents, 5),
-                                  it.permutations(keycomponents, 6)))
-
-    for val, key in enumerate(keys):
-        if len(key) == 1: td[key[0]] = val
-        else:             td[key]    = val
-
-    for val, key in enumerate(keys):
-
-        # Keys can be passed as tuples
-        assert td[key] == val
-
-        # Or as dot-separated strings
-        assert td['.'.join(key)] == val
-
-        # But when accessing items,
-        # we can use either class names,
-        # classes, or instances.
-        for toReplace in it.chain(it.combinations(['A', 'B', 'C'], 1),
-                                  it.combinations(['A', 'B', 'C'], 2),
-                                  it.combinations(['A', 'B', 'C'], 3)):
-
-            clsrep  = {'A' : A, 'B' : B, 'C' : C}
-            instrep = {'A' : a, 'B' : b, 'C' : c}
-
-            # use class instead of name
-            repkey = [clsrep[k] if k in toReplace else k for k in key]
-            assert td[repkey] == val
-
-            # use instance instead of name
-            repkey = [instrep[k] if k in toReplace else k for k in key]
-            assert td[repkey] == val
-
-
-def test_class_hierarchy():
-
-    class A(object):
-        pass
-
-    class B(A):
-        pass
-
-    td = typedict.TypeDict()
-    td['A.a'] = 'A.a'
-    td['A.b'] = 'A.b'
-    td['A.c'] = 'A.c'
-    td['A.d'] = 'A.d'
-    td['B.a'] = 'B.a'
-    td['B.b'] = 'B.b'
-    td['B.1'] = 'B.1'
-    td['B.2'] = 'B.2'
-
-    a = A()
-    b = B()
-    
-    assert td[A, 'a'] == 'A.a'
-    assert td[A, 'b'] == 'A.b'
-    assert td[A, 'c'] == 'A.c'
-    assert td[A, 'd'] == 'A.d'
-    
-    assert td['A.a']  == 'A.a'
-    assert td['A.b']  == 'A.b'
-    assert td['A.c']  == 'A.c'
-    assert td['A.d']  == 'A.d'
-    
-    assert td.get((A, 'a')) == 'A.a'
-    assert td.get((A, 'b')) == 'A.b'
-    assert td.get((A, 'c')) == 'A.c'
-    assert td.get((A, 'd')) == 'A.d' 
-    
-    assert td.get((A, 'a'), allhits=True) == ['A.a']
-    assert td.get((A, 'b'), allhits=True) == ['A.b']
-    assert td.get((A, 'c'), allhits=True) == ['A.c']
-    assert td.get((A, 'd'), allhits=True) == ['A.d']
-    
-    assert td.get((a, 'a'), allhits=True) == ['A.a']
-    assert td.get((a, 'b'), allhits=True) == ['A.b']
-    assert td.get((a, 'c'), allhits=True) == ['A.c']
-    assert td.get((a, 'd'), allhits=True) == ['A.d']
-
-    assert td[B, 'a'] == 'B.a'
-    assert td[B, 'b'] == 'B.b'
-    assert td[B, '1'] == 'B.1'
-    assert td[B, '2'] == 'B.2'
-    
-    assert td['B.a']  == 'B.a'
-    assert td['B.b']  == 'B.b'
-    assert td['B.1']  == 'B.1'
-    assert td['B.2']  == 'B.2'
-    
-    assert td.get('B.a') == 'B.a'
-    assert td.get('B.b') == 'B.b'
-    assert td.get('B.1') == 'B.1'
-    assert td.get('B.2') == 'B.2'
-
-    assert td.get((B, 'a')) == 'B.a'
-    assert td.get((B, 'b')) == 'B.b'
-    assert td.get((B, '1')) == 'B.1'
-    assert td.get((B, '2')) == 'B.2'
-    assert td.get((b, 'a')) == 'B.a'
-    assert td.get((b, 'b')) == 'B.b'
-    assert td.get((b, '1')) == 'B.1'
-    assert td.get((b, '2')) == 'B.2'
-
-    with pytest.raises(KeyError):
-        td['B.c']
-    with pytest.raises(KeyError):
-        td['B.d']
-
-    assert td[B, 'c'] == 'A.c'
-    assert td[B, 'd'] == 'A.d'
-    assert td[b, 'c'] == 'A.c'
-    assert td[b, 'd'] == 'A.d' 
-    
-    assert td.get('B.a',    allhits=True) == ['B.a']
-    assert td.get('B.b',    allhits=True) == ['B.b']
-    assert td.get('B.1',    allhits=True) == ['B.1']
-    assert td.get('B.2',    allhits=True) == ['B.2'] 
-    assert td.get((B, 'a'), allhits=True) == ['B.a', 'A.a']
-    assert td.get((B, 'b'), allhits=True) == ['B.b', 'A.b']
-    assert td.get((B, '1'), allhits=True) == ['B.1']
-    assert td.get((B, '2'), allhits=True) == ['B.2']
-    assert td.get((B, 'c'), allhits=True) == ['A.c']
-    assert td.get((B, 'd'), allhits=True) == ['A.d'] 
-    
-    assert td.get((b, 'a'), allhits=True) == ['B.a', 'A.a']
-    assert td.get((b, 'b'), allhits=True) == ['B.b', 'A.b']
-    assert td.get((b, '1'), allhits=True) == ['B.1']
-    assert td.get((b, '2'), allhits=True) == ['B.2']
-    assert td.get((b, 'c'), allhits=True) == ['A.c']
-
-    assert td.get((B, 'a'), allhits=False, bykey=True) == 'B.a'
-    assert td.get((B, 'b'), allhits=False, bykey=True) == 'B.b'
-    assert td.get((B, '1'), allhits=False, bykey=True) == 'B.1'
-    assert td.get((B, '2'), allhits=False, bykey=True) == 'B.2'
-    
-    assert td.get((B, 'a'), allhits=True,  bykey=True) == {('A', 'a') : 'A.a',
-                                                           ('B', 'a') : 'B.a'}
-    assert td.get((B, 'b'), allhits=True,  bykey=True) == {('A', 'b') : 'A.b',
-                                                           ('B', 'b') : 'B.b'}
-    assert td.get((B, '1'), allhits=True,  bykey=True) == {('B', '1') : 'B.1'}
-    assert td.get((B, '2'), allhits=True,  bykey=True) == {('B', '2') : 'B.2'}
-    assert td.get((B, 'c'), allhits=True,  bykey=True) == {('A', 'c') : 'A.c'}
-    assert td.get((B, 'd'), allhits=True,  bykey=True) == {('A', 'd') : 'A.d'} 
-    
-    assert td.get((b, 'a'), allhits=True,  bykey=True) == {('A', 'a') : 'A.a',
-                                                           ('B', 'a') : 'B.a'}
-    assert td.get((b, 'b'), allhits=True,  bykey=True) == {('A', 'b') : 'A.b',
-                                                           ('B', 'b') : 'B.b'}
-    assert td.get((b, '1'), allhits=True,  bykey=True) == {('B', '1') : 'B.1'}
-    assert td.get((b, '2'), allhits=True,  bykey=True) == {('B', '2') : 'B.2'}
-    assert td.get((b, 'c'), allhits=True,  bykey=True) == {('A', 'c') : 'A.c'}
-    assert td.get((b, 'd'), allhits=True,  bykey=True) == {('A', 'd') : 'A.d'} 
-    
-    assert td.get((A, 'a'), allhits=True,  bykey=True) == {('A', 'a') : 'A.a'}
-    assert td.get((A, 'b'), allhits=True,  bykey=True) == {('A', 'b') : 'A.b'}
-    assert td.get((A, 'c'), allhits=True,  bykey=True) == {('A', 'c') : 'A.c'}
-    assert td.get((A, 'd'), allhits=True,  bykey=True) == {('A', 'd') : 'A.d'}