#
# lookuptablepanel.py - The LookupTablePanel class.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides the :class:`LookupTablePanel`, a *FSLeyes control*
panel which allows the user to manage lookup tables. See the
:mod:`.colourmaps` module for more details on lookup tables.
A few other classes and functions are defined in this module, all for use by
the ``LookupTablePanel``:
.. autosummary::
:nosignatures:
promptForLutName
LabelWidget
LutLabelDialog
"""
import os
import os.path as op
import logging
import wx
import fsl.utils.idle as idle
import fsl.utils.settings as fslsettings
import fsl.data.melodicimage as fslmelimage
import fsleyes_props as props
import fsleyes_widgets.elistbox as elistbox
import fsleyes_widgets.utils.status as status
import fsleyes.controls.controlpanel as ctrlpanel
import fsleyes.displaycontext as displayctx
import fsleyes.colourmaps as fslcmaps
import fsleyes.strings as strings
log = logging.getLogger(__name__)
[docs]class LookupTablePanel(ctrlpanel.ControlPanel):
"""A ``LookupTablePanel`` is a :class:`.ControlPanel` which allows users
to manage ``LookupTable`` instances. A ``LookupTablePanel`` looks
something like this:
.. image:: images/lookuptablepanel.png
:scale: 50%
:align: center
A ``LookupTablePanel`` allows the user to do the following:
- Add/remove labels to/from a :class:`LookupTable`.
- Change the colour, name, and visibility of a label in a
``LookupTable``.
- Create a new ``LookupTable``, or copy an existing one.
- Save/load a ``LookupTable`` to/from a file.
The ``LookupTablePanel`` keeps track of the currently selected overlay
(see the :attr:`.DisplayContext.selectedOverlay` property). If the overlay
is associated with a :class:`.LabelOpts` instance, its
:attr:`.Labelopts.lut` property will be updated when the
:class:`LookupTable` is changed through the ``LookupTablePanel``, and vice
versa.
"""
[docs] def __init__(self, parent, overlayList, displayCtx, frame):
"""Create a ``LookupTablePanel``.
:arg parent: The :mod:`wx` parent object.
:arg overlayList: The :class:`.OverlayList` instance.
:arg displayCtx: The :class:`.DisplayContext` instance.
:arg frame: The :class:`.FSLeyesFrame` instance.
"""
ctrlpanel.ControlPanel.__init__(
self, parent, overlayList, displayCtx, frame)
self.__controlCol = wx.Panel(self)
self.__labelList = elistbox.EditableListBox(
self, style=(elistbox.ELB_NO_MOVE |
elistbox.ELB_NO_ADD |
elistbox.ELB_NO_REMOVE |
elistbox.ELB_WIDGET_RIGHT))
self.__lutChoice = wx.Choice(self.__controlCol)
self.__selAllButton = wx.Button(self.__controlCol)
self.__selNoneButton = wx.Button(self.__controlCol)
self.__addLabelButton = wx.Button(self.__controlCol)
self.__rmLabelButton = wx.Button(self.__controlCol)
self.__newLutButton = wx.Button(self.__controlCol)
self.__copyLutButton = wx.Button(self.__controlCol)
self.__saveLutButton = wx.Button(self.__controlCol)
self.__loadLutButton = wx.Button(self.__controlCol)
self.__controlColSizer = wx.BoxSizer(wx.VERTICAL)
self.__sizer = wx.BoxSizer(wx.VERTICAL)
self.__controlCol.SetSizer(self.__controlColSizer)
self .SetSizer(self.__sizer)
self.__controlColSizer.Add(self.__lutChoice, flag=wx.EXPAND)
self.__controlColSizer.Add(self.__selAllButton, flag=wx.EXPAND)
self.__controlColSizer.Add(self.__selNoneButton, flag=wx.EXPAND)
self.__controlColSizer.Add(self.__addLabelButton, flag=wx.EXPAND)
self.__controlColSizer.Add(self.__rmLabelButton, flag=wx.EXPAND)
self.__controlColSizer.Add(self.__newLutButton, flag=wx.EXPAND)
self.__controlColSizer.Add(self.__copyLutButton, flag=wx.EXPAND)
self.__controlColSizer.Add(self.__loadLutButton, flag=wx.EXPAND)
self.__controlColSizer.Add(self.__saveLutButton, flag=wx.EXPAND)
self.__sizer.Add(self.__controlCol, flag=wx.EXPAND)
self.__sizer.Add(self.__labelList, flag=wx.EXPAND, proportion=1)
# Label the buttons
self.__selAllButton .SetLabel(strings.labels[ self, 'selectAll'])
self.__selNoneButton .SetLabel(strings.labels[ self, 'selectNone'])
self.__addLabelButton.SetLabel(strings.labels[ self, 'addLabel'])
self.__rmLabelButton .SetLabel(strings.labels[ self, 'removeLabel'])
self.__newLutButton .SetLabel(strings.labels[ self, 'newLut'])
self.__copyLutButton .SetLabel(strings.labels[ self, 'copyLut'])
self.__loadLutButton .SetLabel(strings.labels[ self, 'loadLut'])
self.__saveLutButton .SetLabel(strings.labels[ self, 'saveLut'])
self.__lutChoice .Bind(wx.EVT_CHOICE, self.__onLutChoice)
self.__selAllButton .Bind(wx.EVT_BUTTON, self.__onSelectAll)
self.__selNoneButton .Bind(wx.EVT_BUTTON, self.__onSelectNone)
self.__addLabelButton.Bind(wx.EVT_BUTTON, self.__onLabelAdd)
self.__rmLabelButton .Bind(wx.EVT_BUTTON, self.__onLabelRemove)
self.__newLutButton .Bind(wx.EVT_BUTTON, self.__onNewLut)
self.__copyLutButton .Bind(wx.EVT_BUTTON, self.__onCopyLut)
self.__loadLutButton .Bind(wx.EVT_BUTTON, self.__onLoadLut)
self.__saveLutButton .Bind(wx.EVT_BUTTON, self.__onSaveLut)
# The selected overlay / DisplayOpts
# are tracked if they use an LUT
# (e.g. LabelOpts). And the currently
# selected/displayed LUT is always
# tracked.
self.__selectedOverlay = None
self.__selectedOpts = None
self.__selectedLut = None
# See the __createLabelList method
self.__labelListCreateKey = 0
overlayList.addListener('overlays',
self.name,
self.__selectedOverlayChanged)
displayCtx .addListener('selectedOverlay',
self.name,
self.__selectedOverlayChanged)
self.__updateLutChoices()
self.__selectedOverlayChanged()
# If the selected lut was not set
# via the selectedOverlayChanged
# call, we'll manually set it here
if self.__selectedLut is None:
self.__setLut(fslcmaps.getLookupTables()[0])
self.Layout()
# The label values (used as labels in the
# EditableListBox) seem to get squashed
# easily. So we're adding a bit of padding
# to force this panel to have a minimum
# size, to ensure that the labels are
# visible.
dc = wx.ClientDC(self.__labelList)
w, h = dc.GetTextExtent('9999')
minSize = self.__sizer.GetMinSize()
self.SetMinSize((minSize[0] + w, minSize[1]))
[docs] def destroy(self):
"""Must be called when this ``LookupTablePanel`` is no longer needed.
Removes some property listeners, and calls the
:meth:`ControlPanel.destroy` method.
"""
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 and overlay in self.overlayList:
display = self.displayCtx.getDisplay(overlay)
display.removeListener('overlayType', self.name)
if opts is not None:
opts.removeListener('lut', self.name)
if lut is not None:
lut.deregister(self.name, 'saved')
lut.deregister(self.name, 'added')
lut.deregister(self.name, 'removed')
self.__selectedOverlay = None
self.__selectedOpts = None
self.__selectedLut = None
ctrlpanel.ControlPanel.destroy(self)
def __updateLutChoices(self):
"""Refreshes the contents of the lookup table drop down box,
using the :class:`.LookupTable` instances returned by the
:func:`.colourmaps.getLookupTables` function.
"""
log.debug('Updating lookup table choices')
oldNames = self.__lutChoice.GetItems()
oldSelection = self.__lutChoice.GetSelection()
luts = fslcmaps.getLookupTables()
newNames = [l.name for l in luts]
try: newSelection = oldNames.index(oldNames[oldSelection])
except Exception: newSelection = 0
self.__lutChoice.SetItems(newNames)
self.__lutChoice.SetSelection(newSelection)
for i, lut in enumerate(luts):
self.__lutChoice.SetClientData(i, lut)
def __createLabelList(self):
"""Refreshes the contents of the class:`.LookupTable` label list, from
the currently selected ``LookupTable``.
"""
# The label list is created asynchronously on
# the wx.Idle loop, because it can take some
# time for big lookup tables. In the event
# that the list needs to be re-created (e.g.
# the current lookup table is changed), this
# attribute is used so that scheduled creation
# routines (the addLabel function defined
# below) can tell whether they should cancel.
myCreateKey = (self.__labelListCreateKey + 1) % 65536
self.__labelListCreateKey = myCreateKey
lut = self.__selectedLut
nlabels = len(lut)
self.__labelList.Clear()
# If this is a new lut, it
# won't have any labels
if nlabels == 0:
return
# The label widgets are created via consecutive
# calls to addLabel, which is scheduled on the
# idle.idle loop. We create blockSize labels
# in each asynchronous call.
blockSize = 100
def addLabel(startIdx):
# If the user closes this panel while the
# label list is being created, wx will
# complain when we try to append things
# to a widget that has been destroyed.
try:
for labelIdx in range(
startIdx, min(startIdx + blockSize, nlabels)):
# A new request to re-create the list has
# been made - cancel this creation chain.
if self.__labelListCreateKey != myCreateKey:
return
label = lut[labelIdx]
widget = LabelWidget(self, lut, label)
self.__labelList.Append(str(label.value),
clientData=label.value,
extraWidget=widget)
if labelIdx == nlabels - 1:
status.update('Lookup table label list created.')
self.Enable()
self.__labelList.Enable()
else:
idle.idle(addLabel, labelIdx + 1)
except RuntimeError:
pass
log .debug( 'Creating lookup table label list')
status.update('Creating lookup table label list...', timeout=None)
self.__labelList.Disable()
self.Disable()
idle.idle(addLabel, 0)
def __setLut(self, lut):
"""Updates this ``LookupTablePanel`` to display the labels for the
given ``lut`` (assumed to be a :class:`.LookupTable` instance).
If the currently selected overlay is associated with a
:class:`.LabelOpts` instance, its :attr:`.LabelOpts.lut` property is
set to the new ``LookupTable``.
"""
if self.__selectedLut == lut:
return
log.debug('Selecting lut: {}'.format(lut))
if self.__selectedLut is not None:
self.__selectedLut.deregister(self.name, 'saved')
self.__selectedLut.deregister(self.name, 'added')
self.__selectedLut.deregister(self.name, 'removed')
self.__selectedLut = lut
if lut is not None:
lut.register(self.name, self.__lutSaveStateChanged, 'saved')
lut.register(self.name, self.__lutLabelAdded, 'added')
lut.register(self.name, self.__lutLabelRemoved, 'removed')
if lut is not None and self.__selectedOpts is not None:
with props.skip(self.__selectedOpts, 'lut', self.name):
self.__selectedOpts.lut = lut
allLuts = fslcmaps.getLookupTables()
self.__lutChoice.SetSelection(allLuts.index(lut))
self.__lutSaveStateChanged()
self.__createLabelList()
def __lutSaveStateChanged(self, *a):
"""Called when the :attr:`.LookupTable.saved` property of the
current :class:`LookupTable` instance changes. Sets the state
of the *save* button accordingly.
"""
self.__saveLutButton.Enable(not self.__selectedLut.saved)
def __lutLabelAdded(self, lut, topic, label):
"""Called when the current :class:`.LookupTable` sends an ``'added'``
notification, indicating that a label has been added. Updates the list
of displayed labels.
"""
label, idx = label
widget = LabelWidget(self, lut, label)
self.__labelList.Insert(str(label.value),
idx,
clientData=label.value,
extraWidget=widget)
def __lutLabelRemoved(self, lut, topic, label):
"""Called when the current :class:`.LookupTable` sends a ``'removed'``
notification, indicating that a label has been removed. Updates the
list of displayed labels.
"""
label, idx = label
self.__labelList.Delete(idx)
def __onLutChoice(self, ev):
"""Called when the user changes the selected :class:`.LookupTable`
via the lookup table drop down box. See the :meth:`__setLut` method..
"""
selection = self.__lutChoice.GetSelection()
lut = self.__lutChoice.GetClientData(selection)
log.debug('Lut choice: {}'.format(lut))
self.__setLut(lut)
def __onSelectAll(self, ev):
"""Called when the user pushes the *Select all* button. Enables
every label on the current LUT.
"""
for label in self.__selectedLut:
label.enabled = True
def __onSelectNone(self, ev):
"""Called when the user pushes the *Select none* button. Disables
every label on the current LUT.
"""
for label in self.__selectedLut:
label.enabled = False
def __onNewLut(self, ev):
"""Called when the user presses the *New LUT* button.
Prompts the user to enter a name (via :func:`promptForLutName`), and
then creates and registers a new :class:`.LookupTable`
instance. Updates this ``LookupTablePanel`` via the
:meth:`__updateLutChoices` and :meth:`__setLut` methods.
"""
key, name = promptForLutName()
if key is None:
return
log.debug('Creating and registering new '
'LookupTable: {}'.format(key))
lut = fslcmaps.LookupTable(key=key, name=name)
fslcmaps.registerLookupTable(lut, self.overlayList, self.displayCtx)
self.__updateLutChoices()
self.__setLut(lut)
def __onCopyLut(self, ev):
"""Called when the user presses the *Copy LUT* button.
Prompts the user to enter a name (via :func:`promptForLutName`), and
then creates and registers a new :class:`.LookupTable` instance which
is initialised with the same labels as the previously selected
``LookupTable``. Updates this ``LookupTablePanel`` via the
:meth:`__updateLutChoices` and :meth:`__setLut` methods.
"""
oldKey = self.__selectedLut.key
oldName = self.__selectedLut.name
newKey, newName = promptForLutName('{} copy'.format(oldName))
if newKey is None:
return
log.debug('Creating and registering new '
'LookupTable {} (copied from {})'.format(newKey, oldKey))
lut = fslcmaps.LookupTable(key=newKey, name=newName)
for label in self.__selectedLut.labels():
lut.insert(label.value,
name=label.name,
colour=label.colour,
enabled=label.enabled)
fslcmaps.registerLookupTable(lut, self.overlayList, self.displayCtx)
self.__updateLutChoices()
self.__setLut(lut)
def __onLoadLut(self, ev):
"""Called when the user presses the *Load LUT* button. Does the
following:
- Prompts the user to select a LUT file with a ``wx.FileDialog``
- Prompts the user to enter a name for the LUT via the
:func:`promptForLutName` function.
- Creates and registers a new :class:`.LookupTable` instance,
initialising it with the selected file.
- Updates this ``LookupTablePanel`` via the
:meth:`__updateLutChoices` and :meth:`__setLut` methods.
"""
parent = wx.GetApp().GetTopWindow()
loadDir = fslsettings.read('fsleyes.loadlutdir', os.getcwd())
# Prompt the user to select a lut file
fileDlg = wx.FileDialog(
parent,
defaultDir=loadDir,
message=strings.titles[self, 'loadLut'],
style=wx.FD_OPEN)
if fileDlg.ShowModal() != wx.ID_OK:
return
lutFile = fileDlg.GetPath()
lutDir = op.dirname(lutFile)
lutName = op.splitext(op.basename(lutFile))[0]
# Prompt the user to enter a name
lutKey, lutName = promptForLutName(lutName)
if lutKey is None:
return
# Register the lut
errTitle = strings.titles[ self, 'loadError']
errMsg = strings.messages[self, 'loadError'].format(lutFile)
with status.reportIfError(errTitle, errMsg):
lut = fslcmaps.registerLookupTable(lutFile,
self.overlayList,
self.displayCtx,
key=lutKey,
name=lutName)
# Save the directory for next time
fslsettings.write('fsleyes.loadlutdir', lutDir)
# Select the lut in the panel
self.__updateLutChoices()
self.__setLut(lut)
def __onSaveLut(self, ev):
"""Called when the user presses the *Save LUT* button. Makes sure
that the current :class:`LookupTable` is saved (see the
:func:`.colourmaps.installLookupTable` function).
"""
etitle = strings.titles[ self, 'installerror']
emsg = strings.messages[self, 'installerror']
with status.reportIfError(title=etitle, msg=emsg, raiseError=False):
fslcmaps.installLookupTable(self.__selectedLut.key)
def __onLabelAdd(self, ev):
"""Called when the user pushes the *add* button on the lookup table
label list. Displays a :class:`LutLabelDialog`, prompting the user
to select a name, value and colour, and then adds a new label to the
current :class:`.LookupTable` instance.
"""
lut = self.__selectedLut
value = lut.max() + 1
name = strings.labels['LutLabelDialog.newLabel']
colour = fslcmaps.randomBrightColour()
colour = [int(round(c * 255.0)) for c in colour]
dlg = LutLabelDialog(self.GetTopLevelParent(), value, name, colour)
if dlg.ShowModal() != wx.ID_OK:
return
lut = self.__selectedLut
value = dlg.GetValue()
name = dlg.GetName()
colour = dlg.GetColour()[:3]
colour = [c / 255.0 for c in colour]
if lut.get(value) is not None:
wx.MessageBox(
strings.messages[self, 'labelExists'].format(lut.name, value),
strings.titles[ self, 'labelExists'], (wx.ICON_INFORMATION |
wx.OK))
return
log.debug('New lut label for {}: {}, {}, {}'.format(
lut.name,
value,
name,
colour))
with lut.skip(self.name, 'added'):
label = lut.insert(value, name=name, colour=colour)
widget = LabelWidget(self, lut, label)
idx = lut.index(label)
self.__labelList.Insert(str(label.value),
idx,
clientData=label.value,
extraWidget=widget)
def __onLabelRemove(self, ev):
"""Called when the user pushes the *remove* button on the lookup
table label list. Removes the selected label from the current
:class:`.LookupTable`.
"""
idx = self.__labelList.GetSelection()
lut = self.__selectedLut
value = lut[idx].value
with lut.skip(self.name, 'removed'):
lut.delete(value)
self.__labelList.Delete(idx)
def __selectedOverlayChanged(self, *a):
"""Called when the :class:`OverlayList` or
:attr:`.DisplayContext.selectedOverlay` changes. Refreshes the
``LookupTablePanel`` accordingly.
"""
newOverlay = self.displayCtx.getSelectedOverlay()
if self.__selectedOverlay is not None and \
self.__selectedOverlay in self.overlayList:
display = self.displayCtx.getDisplay(self.__selectedOverlay)
display.removeListener('overlayType', self.name)
self.__selectedOverlay = newOverlay
if newOverlay is not None:
display = self.displayCtx.getDisplay(newOverlay)
display.addListener('overlayType',
self.name,
self.__overlayTypeChanged)
self.__overlayTypeChanged()
def __overlayTypeChanged(self, *a):
"""Called when the :attr:`.Display.overlayType` property of the
currently selected overlay changes. If the :class:`.DisplayOpts`
instance associated with the new overlay type is a
:class:`.LabelOpts`, a listener is addd to its ``lut`` property.
"""
if self.__selectedOpts is not None:
self.__selectedOpts.removeListener('lut', self.name)
self.__selectedOpts = None
overlay = self.__selectedOverlay
opts = None
if overlay is None:
return
opts = self.displayCtx.getOpts(overlay)
if not isinstance(opts, (displayctx.LabelOpts, displayctx.MeshOpts)):
# If the image is a Melodic image, show
# the melodic classification lut
if isinstance(overlay, fslmelimage.MelodicImage):
self.__setLut(fslcmaps.getLookupTable('melodic-classes'))
return
opts.addListener('lut', self.name, self.__lutChanged)
self.__selectedOpts = opts
self.__lutChanged()
self.Layout()
def __lutChanged(self, *a):
"""Called when the :attr:`.LabelOpts.lut` property associated
with the currently selected overlay changes. Changes the
:class:`.LookupTable` displayed on this ``LookupTablePanel`` (see
the :meth:`__setLut` method).
"""
self.__setLut(self.__selectedOpts.lut)
[docs]def promptForLutName(initial=None):
"""Prompts the user to enter a name for a newly created
:class:`.LookupTable`.
"""
if initial is None:
initial = strings.labels[LookupTablePanel, 'newLutDefault']
nameMsg = strings.messages[LookupTablePanel, 'newlut']
nameTitle = strings.titles[ LookupTablePanel, 'newlut']
while True:
dlg = wx.TextEntryDialog(
wx.GetApp().GetTopWindow(),
nameMsg,
nameTitle,
initial)
if dlg.ShowModal() != wx.ID_OK:
return None, None
lutName = dlg.GetValue()
lutKey = fslcmaps.makeValidMapKey(lutName)
# a lut with the specified name already exists
if fslcmaps.isLookupTableRegistered(lutKey):
nameMsg = strings.messages[LookupTablePanel, 'alreadyinstalled']
continue
break
return lutKey, lutName
[docs]class LutLabelDialog(wx.Dialog):
"""A dialog which is displayed when the user adds a new label to the
:class:`.LookupTable` currently displayed in the
:class:`LookupTablePanel`.
Prompts the user to enter a label value, name, and colour. After the
dialog is dismissed, the entered information is available via the
following methods:
.. autosummary::
:nosignatures:
GetValue
GetName
GetColour
"""
[docs] def __init__(self, parent, value, name, colour):
"""Create a ``LutLabelDialog``.
:arg parent: The :mod:`wx` parent object.
"""
wx.Dialog.__init__(self, parent, title=strings.titles[self])
self.__value = wx.SpinCtrl( self, min=0, max=65535)
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, id=wx.ID_OK)
self.__cancel = wx.Button(self, id=wx.ID_CANCEL)
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( value)
self.__name .SetValue( name)
self.__colour .SetColour(colour)
self.__sizer = wx.GridSizer(4, 2, 0, 0)
self.SetSizer(self.__sizer)
self.__sizer.Add(self.__valueLabel,
flag=wx.EXPAND | wx.TOP | wx.LEFT,
border=15)
self.__sizer.Add(self.__value,
flag=wx.EXPAND | wx.TOP | wx.RIGHT,
border=15)
self.__sizer.Add(self.__nameLabel,
flag=wx.EXPAND | wx.LEFT,
border=15)
self.__sizer.Add(self.__name,
flag=wx.EXPAND | wx.RIGHT,
border=15)
self.__sizer.Add(self.__colourLabel,
flag=wx.EXPAND | wx.LEFT,
border=15)
self.__sizer.Add(self.__colour,
flag=wx.EXPAND | wx.RIGHT,
border=15)
self.__sizer.Add(self.__ok,
flag=wx.EXPAND | wx.BOTTOM | wx.LEFT,
border=15)
self.__sizer.Add(self.__cancel,
flag=wx.EXPAND | wx.BOTTOM | wx.RIGHT,
border=15)
self.__ok .Bind(wx.EVT_BUTTON, self.__onOk)
self.__cancel.Bind(wx.EVT_BUTTON, self.__onCancel)
self.__ok.SetDefault()
self.Layout()
self.Fit()
self.CentreOnParent()
self.__enteredValue = None
self.__enteredName = None
self.__enteredColour = None
[docs] def GetValue(self):
"""Returns the value that was entered by the user. Or, returns
``None`` if the user cancelled the dialog, or the dialog has not
yet been closed.
"""
return self.__enteredValue
[docs] def GetName(self):
"""Returns the name that was entered by the user. Or, returns
``None`` if the user cancelled the dialog, or the dialog has not
yet been closed.
"""
return self.__enteredName
[docs] def GetColour(self):
"""Returns the colour that was entered by the user. Or, returns
``None`` if the user cancelled the dialog, or the dialog has not
yet been closed.
"""
return self.__enteredColour
def __onOk(self, ev):
"""Called when the user confirms the dialog. Saves the name, colour,
and value that were entered, and closes the dialog.
"""
self.__enteredValue = self.__value .GetValue()
self.__enteredName = self.__name .GetValue()
self.__enteredColour = self.__colour.GetColour()
self.EndModal(wx.ID_OK)
def __onCancel(self, ev):
"""Called when the user cancells the dialog. Closes the dialog."""
self.EndModal(wx.ID_CANCEL)