Show More
@@ -33,68 +33,81 class _Selection(DOMWidget): | |||||
33 | """ |
|
33 | """ | |
34 |
|
34 | |||
35 | value = Any(help="Selected value") |
|
35 | value = Any(help="Selected value") | |
36 | values = Dict(help="""Dictionary of {name: value} the user can select. |
|
36 | value_name = Unicode(help="The name of the selected value", sync=True) | |
|
37 | values = Any(sync=True, help="""List of (key, value) tuples the user can select. | |||
37 |
|
38 | |||
38 |
The keys of this |
|
39 | The keys of this list are the strings that will be displayed in the UI, | |
39 | representing the actual Python choices. |
|
40 | representing the actual Python choices. | |
40 |
|
41 | |||
41 |
The keys of this |
|
42 | The keys of this list are also available as value_names. | |
42 | """) |
|
43 | """) | |
43 | value_name = Unicode(help="The name of the selected value", sync=True) |
|
44 | ||
44 | value_names = List(Unicode, help="""Read-only list of names for each value. |
|
45 | values_dict = Dict() | |
45 |
|
46 | values_names = Tuple() | ||
46 | If values is specified as a list, this is the string representation of each element. |
|
47 | values_values = Tuple() | |
47 | Otherwise, it is the keys of the values dictionary. |
|
48 | ||
48 |
|
||||
49 | These strings are used to display the choices in the front-end.""", sync=True) |
|
|||
50 | disabled = Bool(False, help="Enable or disable user changes", sync=True) |
|
49 | disabled = Bool(False, help="Enable or disable user changes", sync=True) | |
51 | description = Unicode(help="Description of the value this widget represents", sync=True) |
|
50 | description = Unicode(help="Description of the value this widget represents", sync=True) | |
52 |
|
51 | |||
53 |
|
||||
54 | def __init__(self, *args, **kwargs): |
|
52 | def __init__(self, *args, **kwargs): | |
55 | self.value_lock = Lock() |
|
53 | self.value_lock = Lock() | |
56 |
self. |
|
54 | self.values_lock = Lock() | |
|
55 | self.on_trait_change(self._values_readonly_changed, ['values_dict', 'values_names', 'values_values', '_values']) | |||
57 | if 'values' in kwargs: |
|
56 | if 'values' in kwargs: | |
58 | values = kwargs['values'] |
|
|||
59 | # convert list values to an dict of {str(v):v} |
|
|||
60 | if isinstance(values, list): |
|
|||
61 | # preserve list order with an OrderedDict |
|
|||
62 | kwargs['values'] = OrderedDict((unicode_type(v), v) for v in values) |
|
|||
63 | # python3.3 turned on hash randomization by default - this means that sometimes, randomly |
|
|||
64 | # we try to set value before setting values, due to dictionary ordering. To fix this, force |
|
|||
65 | # the setting of self.values right now, before anything else runs |
|
|||
66 | self.values = kwargs.pop('values') |
|
57 | self.values = kwargs.pop('values') | |
67 | DOMWidget.__init__(self, *args, **kwargs) |
|
58 | DOMWidget.__init__(self, *args, **kwargs) | |
68 | self._value_in_values() |
|
59 | self._value_in_values() | |
69 |
|
60 | |||
|
61 | def _make_values(self, x): | |||
|
62 | # If x is a dict, convert it to list format. | |||
|
63 | if isinstance(x, (OrderedDict, dict)): | |||
|
64 | return [(k, v) for k, v in x.items()] | |||
|
65 | ||||
|
66 | # Make sure x is a list or tuple. | |||
|
67 | if not isinstance(x, (list, tuple)): | |||
|
68 | raise ValueError('x') | |||
|
69 | ||||
|
70 | # If x is an ordinary list, use the values as names. | |||
|
71 | for y in x: | |||
|
72 | if not isinstance(y, (list, tuple)) or len(y) < 2: | |||
|
73 | return [(i, i) for i in x] | |||
|
74 | ||||
|
75 | # Value is already in the correct format. | |||
|
76 | return x | |||
|
77 | ||||
70 | def _values_changed(self, name, old, new): |
|
78 | def _values_changed(self, name, old, new): | |
71 |
"""Handles when the values |
|
79 | """Handles when the values tuple has been changed. | |
72 |
|
80 | |||
73 | Setting values implies setting value names from the keys of the dict. |
|
81 | Setting values implies setting value names from the keys of the dict. | |
74 | """ |
|
82 | """ | |
75 | self._in_values_changed = True |
|
83 | if self.values_lock.acquire(False): | |
76 | try: |
|
84 | try: | |
77 | self.value_names = list(new.keys()) |
|
85 | ||
78 | finally: |
|
|||
79 | self._in_values_changed = False |
|
|||
80 | self._value_in_values() |
|
|||
81 |
|
86 | |||
|
87 | self.values = self._make_values(x) | |||
|
88 | self.values_dict = {i[0]: i[1] for i in self.values} | |||
|
89 | self.values_names = [i[0] for i in self.values] | |||
|
90 | self.values_values = [i[1] for i in self.values] | |||
|
91 | self._value_in_values() | |||
|
92 | ||||
82 | def _value_in_values(self): |
|
93 | def _value_in_values(self): | |
83 | # ensure that the chosen value is one of the choices |
|
94 | # ensure that the chosen value is one of the choices | |
84 | if self.values: |
|
95 | if self.values_values: | |
85 |
if self.value not in self.values |
|
96 | if self.value not in self.values_values: | |
86 |
self.value = next(iter(self.values |
|
97 | self.value = next(iter(self.values_values)) | |
87 |
|
98 | |||
88 |
def _value |
|
99 | def _values_readonly_changed(self, name, old, new): | |
89 |
if not self. |
|
100 | if not self.values_lock.acquire(False): | |
90 |
raise TraitError(" |
|
101 | raise TraitError("`.%s` is a read-only trait. Use the `.values` tuple instead." % name) | |
|
102 | else: | |||
|
103 | self.values_lock.release() | |||
91 |
|
104 | |||
92 | def _value_changed(self, name, old, new): |
|
105 | def _value_changed(self, name, old, new): | |
93 | """Called when value has been changed""" |
|
106 | """Called when value has been changed""" | |
94 | if self.value_lock.acquire(False): |
|
107 | if self.value_lock.acquire(False): | |
95 | try: |
|
108 | try: | |
96 | # Reverse dictionary lookup for the value name |
|
109 | # Reverse dictionary lookup for the value name | |
97 | for k,v in self.values.items(): |
|
110 | for k,v in self.values_dict.items(): | |
98 | if new == v: |
|
111 | if new == v: | |
99 | # set the selected value name |
|
112 | # set the selected value name | |
100 | self.value_name = k |
|
113 | self.value_name = k | |
@@ -109,7 +122,7 class _Selection(DOMWidget): | |||||
109 | """Called when the value name has been changed (typically by the frontend).""" |
|
122 | """Called when the value name has been changed (typically by the frontend).""" | |
110 | if self.value_lock.acquire(False): |
|
123 | if self.value_lock.acquire(False): | |
111 | try: |
|
124 | try: | |
112 | self.value = self.values[new] |
|
125 | self.value = self.values_dict[new] | |
113 | finally: |
|
126 | finally: | |
114 | self.value_lock.release() |
|
127 | self.value_lock.release() | |
115 |
|
128 |
General Comments 0
You need to be logged in to leave comments.
Login now