@ -1,4 +1,4 @@
""" SelectionWidget class .
""" SelectionWidget class es .
Represents an enumeration using a widget .
"""
@ -13,66 +13,84 @@ Represents an enumeration using a widget.
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from collections import OrderedDict
from threading import Lock
from . widget import DOMWidget
from IPython . utils . traitlets import Unicode , List , Bool , Any , Dict
from IPython . utils . traitlets import Unicode , List , Bool , Any , Dict , TraitError
from IPython . utils . py3compat import unicode_type
#-----------------------------------------------------------------------------
# SelectionWidget
#-----------------------------------------------------------------------------
class _SelectionWidget ( DOMWidget ) :
value = Any ( help = " Selected value " )
values = List ( help = " List of values the user can select " )
labels = List ( help = """ List of string representations for each value.
These string representations are used to display the values in the
front - end . """ , sync=True) # Only synced to the back-end.
""" Base class for Selection widgets
` ` values ` ` can be specified as a list or dict . If given as a list ,
it will be transformed to a dict of the form ` ` { str ( value ) : value } ` ` .
"""
value = Any ( help = " Selected value " )
values = Dict ( help = """ Dictionary of { name: value} the user can select.
The keys of this dictionary are the strings that will be displayed in the UI ,
representing the actual Python choices .
The keys of this dictionary are also available as value_names .
""" )
value_name = Unicode ( help = " The name of the selected value " , sync = True )
value_names = List ( Unicode , help = """ List of names for each value.
If values is specified as a list , this is the string representation of each element .
Otherwise , it is the keys of the values dictionary .
These strings are used to display the choices in the front - end . """ , sync=True)
disabled = Bool ( False , help = " Enable or disable user changes " , sync = True )
description = Unicode ( help = " Description of the value this widget represents " , sync = True )
_value = Unicode ( sync = True ) # Bi-directionally synced.
def __init__ ( self , * pargs , * * kwargs ) :
""" Constructor """
def __init__ ( self , * args , * * kwargs ) :
self . value_lock = Lock ( )
self . on_trait_change ( self . _string_value_set , [ ' _value ' ] )
DOMWidget . __init__ ( self , * pargs , * * kwargs )
def _labels_changed ( self , name = None , old = None , new = None ) :
""" Handles when the value_names Dict has been changed.
if ' values ' in kwargs :
values = kwargs [ ' values ' ]
# convert list values to an dict of {str(v):v}
if isinstance ( values , list ) :
# preserve list order with an OrderedDict
kwargs [ ' values ' ] = OrderedDict ( ( unicode_type ( v ) , v ) for v in values )
DOMWidget . __init__ ( self , * args , * * kwargs )
def _values_changed ( self , name , old , new ) :
""" Handles when the values dict has been changed.
This method sets the _reverse_value_names Dict to the inverse of the new
value for the value_names Dict . """
Setting values implies setting value names from the keys of the dict .
"""
self . value_names = list ( new . keys ( ) )
def _value_names_changed ( self , name , old , new ) :
if len ( new ) != len ( self . values ) :
raise TypeError ( ' Labels list must be the same size as the values list. ' )
def _values_changed ( self , name = None , old = None , new = None ) :
""" Handles when the value_names Dict has been changed.
This method sets the _reverse_value_names Dict to the inverse of the new
value for the value_names Dict . """
if len ( new ) != len ( self . labels ) :
self . labels = [ ( self . labels [ i ] if i < len ( self . labels ) else str ( v ) ) for i , v in enumerate ( new ) ]
raise TraitError ( " Expected %i value names, got %i . " % ( len ( self . values ) , len ( new ) ) )
def _value_changed ( self , name , old , new ) :
""" Called when value has been changed """
if self . value_lock . acquire ( False ) :
try :
# Make sure the value is in the list of values.
if new in self . values :
# Set the string version of the value.
self . _value = self . labels [ self . values . index ( new ) ]
else :
raise TypeError ( ' Value must be a value in the values list. ' )
# Make sure the value is one of the options
for k , v in self . values . items ( ) :
if new == v :
# set the selected value name
self . value_name = k
return
raise TraitError ( ' Value not found: %r ' % new )
finally :
self . value_lock . release ( )
def _ string_value_set ( self , name , old , new ) :
""" Called when _value has been changed ."""
def _ value_name_changed ( self , name , old , new ) :
""" Called when the value name has been changed (typically by the frontend) ."""
if self . value_lock . acquire ( False ) :
try :
if new in self . label s:
self . value = self . values [ self . labels . index ( new ) ]
if new in self . value s:
self . value = self . values [ new ]
else :
self . value = None
finally :