diff --git a/fsl/data/strings.py b/fsl/data/strings.py
index 0cdd9982d5a3d4ae4a745c6a1f02caca851131a3..4e8ed5ea2bebee8ea967fb8964776bcdb1652c2f 100644
--- a/fsl/data/strings.py
+++ b/fsl/data/strings.py
@@ -21,8 +21,8 @@ messages = TypeDict({
                                    'mapping...',
 
     'overlay.loadOverlays.loading'     : 'Loading {} ...',
-    'overlay.loadOverlays.error'       : 'An error occurred loading the image {}\n\n'
-                                         'Details: {}',
+    'overlay.loadOverlays.error'       : 'An error occurred loading the image '
+                                         '{}\n\nDetails: {}',
 
     'overlay.loadOverlays.unknownType' : 'Unknown data type',
 
@@ -70,6 +70,9 @@ messages = TypeDict({
 
     'LookupTablePanel.notLutOverlay' : 'Choose an overlay which '
                                        'uses a lookup table',
+
+    'LookupTablePanel.labelExists' : 'The {} LUT already contains a '
+                                     'label with value {}'
     
 })
 
@@ -107,7 +110,10 @@ titles = TypeDict({
     'LightBoxToolBar'       : 'Lightbox view toolbar',
     'LightBoxSettingsPanel' : 'Lightbox view settings',
     'HistogramToolBar'      : 'Histogram settings',
-    'LookupTablePanel'      : 'Lookup tables'
+    'LookupTablePanel'      : 'Lookup tables',
+    'LutLabelDialog'        : 'New LUT label',
+
+    'LookupTablePanel.labelExists' : 'Label already exists',
 })
 
 
@@ -174,6 +180,12 @@ labels = TypeDict({
     'LookupTablePanel.copyLut'  : 'Copy',
     'LookupTablePanel.saveLut'  : 'Save',
     'LookupTablePanel.loadLut'  : 'Load',
+
+    'LutLabelDialog.value'  : 'Value',
+    'LutLabelDialog.name'   : 'Name',
+    'LutLabelDialog.colour' : 'Colour',
+    'LutLabelDialog.ok'     : 'Ok',
+    'LutLabelDialog.cancel' : 'Cancel',
 })
 
 
diff --git a/fsl/fslview/colourmaps.py b/fsl/fslview/colourmaps.py
index 25784c531c0932c869ebf63f8f45d2d4e71b0e64..8775140ba1439c4cc7d919d516ce037318341438 100644
--- a/fsl/fslview/colourmaps.py
+++ b/fsl/fslview/colourmaps.py
@@ -91,8 +91,6 @@ give the label name. For example::
 
  - :func:`isLookupTableInstalled`:
 
- - :func:`saveLookupTable`:         TODO - update an installed lookup table
-
 
 -------------
 Miscellaneous
@@ -120,6 +118,7 @@ and generating/manipulating colours.:
 
 import glob
 import shutil
+import bisect
 import os.path as op
 
 from collections import OrderedDict
@@ -213,6 +212,11 @@ class LutLabel(object):
                 self.__colour  == other.__colour and
                 self.__enabled == other.__enabled)
 
+
+    def __cmp__(self, other):
+        return self.__value.__cmp__(other.__value)
+
+    
     def __hash__(self):
         return (hash(self.__value)  ^
                 hash(self.__name)   ^
@@ -232,7 +236,11 @@ class LookupTable(props.HasProperties):
     
     labels = props.List()
     """A list of :class:`LutLabel` instances, defining the label ->
-    colour/name mappings.
+    colour/name mappings. This list is sorted in increasing order
+    by the label value.
+
+    If you modify this list directly, you will probably break things. Use
+    the get/set methods instead.
     """
 
     
@@ -288,7 +296,9 @@ class LookupTable(props.HasProperties):
         enabled = kwargs.get('enabled', label.enabled())
         label   = LutLabel(value, name, colour, enabled)
 
-        if idx == -1: self.labels.append(label)
+        # Use the bisect module to
+        # maintain the list order
+        if idx == -1: bisect.insort(self.labels, label)
         else:         self.labels[idx] = label
 
 
diff --git a/fsl/fslview/controls/lookuptablepanel.py b/fsl/fslview/controls/lookuptablepanel.py
index 37eda0a4e5d9a5e0adb6e3a0ef96f66fbee28d5c..dc13bb5e4686cb86eb51929b9404eeb8b8b7424f 100644
--- a/fsl/fslview/controls/lookuptablepanel.py
+++ b/fsl/fslview/controls/lookuptablepanel.py
@@ -24,6 +24,7 @@ log = logging.getLogger(__name__)
 
 
 
+
 class LabelWidget(wx.Panel):
     
     def __init__(self, lutPanel, overlayOpts, lut, value):
@@ -59,31 +60,23 @@ class LabelWidget(wx.Panel):
         self.enableBox   .Bind(wx.EVT_CHECKBOX,             self.__onEnable)
         self.colourButton.Bind(wx.EVT_COLOURPICKER_CHANGED, self.__onColour)
 
-
     def __onEnable(self, ev):
 
+        # Disable the LutPanel listener, otherwise
+        # it will recreate the label list (see
+        # LookupTablePanel._initLabelList)
+        self.lut.disableListener('labels', self.lutPanel._name)
         self.lut.set(self.value, enabled=self.enableBox.GetValue())
-        self.__notifyLut()
-
-
-    def __notifyLut(self):
-
-        # Disable the LookupTablePanel listener
-        # on the lut property, otherwise it will
-        # re-create the label list
-        self.opts.disableListener('lut', self.lutPanel._name)
-        self.opts.notify('lut')
-        self.opts.enableListener('lut', self.lutPanel._name)        
-
+        self.lut.enableListener('labels', self.lutPanel._name)
 
     def __onColour(self, ev):
 
         newColour = self.colourButton.GetColour()
         newColour = [c / 255.0 for c in newColour]
 
+        self.lut.disableListener('labels', self.lutPanel._name)
         self.lut.set(self.value, colour=newColour)
-        self.__notifyLut()
-
+        self.lut.enableListener('labels', self.lutPanel._name)
 
 
 class LookupTablePanel(fslpanel.FSLViewPanel):
@@ -166,8 +159,9 @@ class LookupTablePanel(fslpanel.FSLViewPanel):
         self.__loadLutButton.Bind(wx.EVT_BUTTON, self.__onLoadLut)
         self.__saveLutButton.Bind(wx.EVT_BUTTON, self.__onSaveLut)
 
-        self.__selectedOpts    = None
         self.__selectedOverlay = None
+        self.__selectedOpts    = None
+        self.__selectedLut     = None
 
         overlayList.addListener('overlays',
                                 self._name,
@@ -177,6 +171,28 @@ class LookupTablePanel(fslpanel.FSLViewPanel):
                                 self.__selectedOverlayChanged)
 
         self.__selectedOverlayChanged()
+
+    def destroy(self):
+
+        self._overlayList.removeListener('overlays',        self._name)
+        self._displayCtx .removeListener('selectedOverlay', self._name)
+
+        overlay = self.__selectedOverlay
+        opts    = self.__selectedOpts
+        lut     = self.__selectedLut
+
+        if overlay is not None:
+
+            display = self._displayCtx.getDisplay(overlay)
+
+            display.removeListener('name',        self._name)
+            display.removeListener('overlayType', self._name)
+
+        if opts is not None:
+            opts.removeListener('lut', self._name)
+
+        if lut is not None:
+            lut.removeListener('labels', self._name)
     
 
     def __selectedOverlayChanged(self, *a):
@@ -252,7 +268,7 @@ class LookupTablePanel(fslpanel.FSLViewPanel):
 
         opts = self._displayCtx.getOpts(overlay)
 
-        opts.addListener('lut', self._name, self.__initLabelList)
+        opts.addListener('lut', self._name, self.__lutChanged)
         
         self.__selectedOpts = opts
         self.__lutWidget    = props.makeWidget(
@@ -261,11 +277,28 @@ class LookupTablePanel(fslpanel.FSLViewPanel):
         self.__controlRowSizer.Insert(
             0, self.__lutWidget, flag=wx.EXPAND, proportion=1)
 
-        self.__initLabelList()
+        self.__lutChanged()
 
         self.Layout()
 
 
+    def __lutChanged(self, *a):
+
+        if self.__selectedLut is not None:
+            self.__selectedLut.removeListener('labels', self._name)
+            self.__selecedLut = None
+
+        opts = self.__selectedOpts
+
+        if opts is not None:
+            self.__selectedLut = opts.lut
+
+            self.__selectedLut.addListener(
+                'labels', self._name, self.__initLabelList)
+
+        self.__initLabelList()
+
+        
     def __initLabelList(self, *a):
 
         self.__labelList.Clear()
@@ -275,7 +308,6 @@ class LookupTablePanel(fslpanel.FSLViewPanel):
 
         opts = self.__selectedOpts
         lut  = opts.lut
-        
 
         for i, label in enumerate(lut.labels):
 
@@ -302,20 +334,112 @@ class LookupTablePanel(fslpanel.FSLViewPanel):
 
     
     def __onLabelAdd(self, ev):
-        # Prompt for value and name
-        # Add to lut
-        pass
+
+        dlg = LutLabelDialog(self.GetTopLevelParent())
+        if dlg.ShowModal() != wx.ID_OK:
+            return
+
+        opts   = self.__selectedOpts
+        value  = dlg.value
+        name   = dlg.name
+        colour = dlg.colour[:3]
+        colour = [c / 255.0 for c in colour]
+
+        if opts.lut.get(value) is not None:
+            wx.MessageBox(
+                strings.messages[self, 'labelExists'].format(
+                    opts.lut.name, value),
+                strings.titles[  self, 'labelExists'],
+                wx.ICON_INFORMATION | wx.OK)
+            return
+
+        log.debug('New lut label for {}: {}, {}, {}'.format(
+            opts.lut.name,
+            value,
+            name,
+            colour))
+
+        opts.lut.set(value, name=name, colour=colour)
 
     
     def __onLabelRemove(self, ev):
 
-        opts  = self._displayCtx.getOpts(self.__selectedOverlay)
+        opts  = self.__selectedOpts
         value = opts.lut.labels[ev.idx].value()
+
+        self.__selectedLut.disableListener('labels', self._name)
         opts.lut.delete(value)
+        self.__selectedLut.enableListener('labels', self._name)
 
 
     def __onLabelEdit(self, ev):
 
-        opts  = self._displayCtx.getOpts(self.__selectedOverlay)
+        opts  = self.__selectedOpts
         value = opts.lut.labels[ev.idx].value()
+
+        self.__selectedLut.disableListener('labels', self._name)
         opts.lut.set(value, name=ev.label)
+        self.__selectedLut.enableListener('labels', self._name)
+
+
+class LutLabelDialog(wx.Dialog):
+
+    def __init__(self, parent):
+
+        wx.Dialog.__init__(self, parent, title=strings.titles[self])
+
+        self._value  = wx.SpinCtrl(        self)
+        self._name   = wx.TextCtrl(        self)
+        self._colour = wx.ColourPickerCtrl(self)
+
+        self._valueLabel  = wx.StaticText(self)
+        self._nameLabel   = wx.StaticText(self)
+        self._colourLabel = wx.StaticText(self)
+
+        self._ok     = wx.Button(self)
+        self._cancel = wx.Button(self)
+
+        self._valueLabel .SetLabel(strings.labels[self, 'value'])
+        self._nameLabel  .SetLabel(strings.labels[self, 'name'])
+        self._colourLabel.SetLabel(strings.labels[self, 'colour'])
+        self._ok         .SetLabel(strings.labels[self, 'ok'])
+        self._cancel     .SetLabel(strings.labels[self, 'cancel'])
+
+        self._value.SetValue(0)
+        self._name .SetValue('New label')
+
+        self._sizer = wx.GridSizer(4, 2)
+        self.SetSizer(self._sizer)
+
+        self._sizer.Add(self._valueLabel,  flag=wx.EXPAND)
+        self._sizer.Add(self._value,       flag=wx.EXPAND)
+        self._sizer.Add(self._nameLabel,   flag=wx.EXPAND)
+        self._sizer.Add(self._name,        flag=wx.EXPAND)
+        self._sizer.Add(self._colourLabel, flag=wx.EXPAND)
+        self._sizer.Add(self._colour,      flag=wx.EXPAND)
+        self._sizer.Add(self._ok,          flag=wx.EXPAND)
+        self._sizer.Add(self._cancel,      flag=wx.EXPAND)
+
+        self._ok    .Bind(wx.EVT_BUTTON, self.onOk)
+        self._cancel.Bind(wx.EVT_BUTTON, self.onCancel)
+
+        self.Fit()
+        self.Layout()
+
+        self.CentreOnParent()
+
+        self.value  = None
+        self.name   = None
+        self.colour = None
+
+
+    def onOk(self, ev):
+        self.value  = self._value .GetValue()
+        self.name   = self._name  .GetValue()
+        self.colour = self._colour.GetColour()
+
+        self.EndModal(wx.ID_OK)
+
+
+    def onCancel(self, ev):
+        self.EndModal(wx.ID_CANCEL)