##// END OF EJS Templates
Validation on the python side
Jonathan Frederic -
Show More
@@ -1,280 +1,295 b''
1 """Float class.
1 """Float class.
2
2
3 Represents an unbounded float using a widget.
3 Represents an unbounded float using a widget.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from .widget import DOMWidget, register
16 from .widget import DOMWidget, register
17 from IPython.utils.traitlets import Unicode, CFloat, Bool, CaselessStrEnum, Tuple
17 from IPython.utils.traitlets import Unicode, CFloat, Bool, CaselessStrEnum, Tuple
18 from IPython.utils.warn import DeprecatedClass
18 from IPython.utils.warn import DeprecatedClass
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Classes
21 # Classes
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 class _Float(DOMWidget):
23 class _Float(DOMWidget):
24 value = CFloat(0.0, help="Float value", sync=True)
24 value = CFloat(0.0, help="Float value", sync=True)
25 disabled = Bool(False, help="Enable or disable user changes", sync=True)
25 disabled = Bool(False, help="Enable or disable user changes", sync=True)
26 description = Unicode(help="Description of the value this widget represents", sync=True)
26 description = Unicode(help="Description of the value this widget represents", sync=True)
27
27
28 def __init__(self, value=None, **kwargs):
28 def __init__(self, value=None, **kwargs):
29 if value is not None:
29 if value is not None:
30 kwargs['value'] = value
30 kwargs['value'] = value
31 super(_Float, self).__init__(**kwargs)
31 super(_Float, self).__init__(**kwargs)
32
32
33 class _BoundedFloat(_Float):
33 class _BoundedFloat(_Float):
34 max = CFloat(100.0, help="Max value", sync=True)
34 max = CFloat(100.0, help="Max value", sync=True)
35 min = CFloat(0.0, help="Min value", sync=True)
35 min = CFloat(0.0, help="Min value", sync=True)
36 step = CFloat(0.1, help="Minimum step that the value can take (ignored by some views)", sync=True)
36 step = CFloat(0.1, help="Minimum step that the value can take (ignored by some views)", sync=True)
37
37
38 def __init__(self, *pargs, **kwargs):
38 def __init__(self, *pargs, **kwargs):
39 """Constructor"""
39 """Constructor"""
40 super(_BoundedFloat, self).__init__(*pargs, **kwargs)
40 super(_BoundedFloat, self).__init__(*pargs, **kwargs)
41 self._validate('value', None, self.value)
41 self._value_changed('value', None, self.value)
42 self.on_trait_change(self._validate, ['value', 'min', 'max'])
42 self._min_changed('min', None, self.min)
43 self._max_changed('max', None, self.max)
43
44
44 def _validate(self, name, old, new):
45 def _value_changed(self, name, old, new):
45 """Validate value, max, min."""
46 """Validate value."""
46 if self.min > new or new > self.max:
47 if self.min > new or new > self.max:
47 self.value = min(max(new, self.min), self.max)
48 self.value = min(max(new, self.min), self.max)
48
49
50 def _max_changed(self, name, old, new):
51 """Make sure the min is always <= the max."""
52 if new < self.min:
53 raise ValueError("setting max < min")
54 if new < self.value:
55 self.value = new
56
57 def _min_changed(self, name, old, new):
58 """Make sure the max is always >= the min."""
59 if new > self.max:
60 raise ValueError("setting min > max")
61 if new > self.value:
62 self.value = new
63
49
64
50 @register('IPython.FloatText')
65 @register('IPython.FloatText')
51 class FloatText(_Float):
66 class FloatText(_Float):
52 """ Displays a float value within a textbox. For a textbox in
67 """ Displays a float value within a textbox. For a textbox in
53 which the value must be within a specific range, use BoundedFloatText.
68 which the value must be within a specific range, use BoundedFloatText.
54
69
55 Parameters
70 Parameters
56 ----------
71 ----------
57 value : float
72 value : float
58 value displayed
73 value displayed
59 description : str
74 description : str
60 description displayed next to the textbox
75 description displayed next to the textbox
61 color : str Unicode color code (eg. '#C13535'), optional
76 color : str Unicode color code (eg. '#C13535'), optional
62 color of the value displayed
77 color of the value displayed
63 """
78 """
64 _view_name = Unicode('FloatTextView', sync=True)
79 _view_name = Unicode('FloatTextView', sync=True)
65
80
66
81
67 @register('IPython.BoundedFloatText')
82 @register('IPython.BoundedFloatText')
68 class BoundedFloatText(_BoundedFloat):
83 class BoundedFloatText(_BoundedFloat):
69 """ Displays a float value within a textbox. Value must be within the range specified.
84 """ Displays a float value within a textbox. Value must be within the range specified.
70 For a textbox in which the value doesn't need to be within a specific range, use FloatText.
85 For a textbox in which the value doesn't need to be within a specific range, use FloatText.
71
86
72 Parameters
87 Parameters
73 ----------
88 ----------
74 value : float
89 value : float
75 value displayed
90 value displayed
76 min : float
91 min : float
77 minimal value of the range of possible values displayed
92 minimal value of the range of possible values displayed
78 max : float
93 max : float
79 maximal value of the range of possible values displayed
94 maximal value of the range of possible values displayed
80 description : str
95 description : str
81 description displayed next to the textbox
96 description displayed next to the textbox
82 color : str Unicode color code (eg. '#C13535'), optional
97 color : str Unicode color code (eg. '#C13535'), optional
83 color of the value displayed
98 color of the value displayed
84 """
99 """
85 _view_name = Unicode('FloatTextView', sync=True)
100 _view_name = Unicode('FloatTextView', sync=True)
86
101
87
102
88 @register('IPython.FloatSlider')
103 @register('IPython.FloatSlider')
89 class FloatSlider(_BoundedFloat):
104 class FloatSlider(_BoundedFloat):
90 """ Slider/trackbar of floating values with the specified range.
105 """ Slider/trackbar of floating values with the specified range.
91
106
92 Parameters
107 Parameters
93 ----------
108 ----------
94 value : float
109 value : float
95 position of the slider
110 position of the slider
96 min : float
111 min : float
97 minimal position of the slider
112 minimal position of the slider
98 max : float
113 max : float
99 maximal position of the slider
114 maximal position of the slider
100 step : float
115 step : float
101 step of the trackbar
116 step of the trackbar
102 description : str
117 description : str
103 name of the slider
118 name of the slider
104 orientation : {'vertical', 'horizontal}, optional
119 orientation : {'vertical', 'horizontal}, optional
105 default is horizontal
120 default is horizontal
106 readout : {True, False}, optional
121 readout : {True, False}, optional
107 default is True, display the current value of the slider next to it
122 default is True, display the current value of the slider next to it
108 slider_color : str Unicode color code (eg. '#C13535'), optional
123 slider_color : str Unicode color code (eg. '#C13535'), optional
109 color of the slider
124 color of the slider
110 color : str Unicode color code (eg. '#C13535'), optional
125 color : str Unicode color code (eg. '#C13535'), optional
111 color of the value displayed (if readout == True)
126 color of the value displayed (if readout == True)
112 """
127 """
113 _view_name = Unicode('FloatSliderView', sync=True)
128 _view_name = Unicode('FloatSliderView', sync=True)
114 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
129 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
115 default_value='horizontal',
130 default_value='horizontal',
116 help="Vertical or horizontal.", allow_none=False, sync=True)
131 help="Vertical or horizontal.", allow_none=False, sync=True)
117 _range = Bool(False, help="Display a range selector", sync=True)
132 _range = Bool(False, help="Display a range selector", sync=True)
118 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
133 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
119 slider_color = Unicode(sync=True)
134 slider_color = Unicode(sync=True)
120
135
121
136
122 @register('IPython.FloatProgress')
137 @register('IPython.FloatProgress')
123 class FloatProgress(_BoundedFloat):
138 class FloatProgress(_BoundedFloat):
124 """ Displays a progress bar.
139 """ Displays a progress bar.
125
140
126 Parameters
141 Parameters
127 -----------
142 -----------
128 value : float
143 value : float
129 position within the range of the progress bar
144 position within the range of the progress bar
130 min : float
145 min : float
131 minimal position of the slider
146 minimal position of the slider
132 max : float
147 max : float
133 maximal position of the slider
148 maximal position of the slider
134 step : float
149 step : float
135 step of the progress bar
150 step of the progress bar
136 description : str
151 description : str
137 name of the progress bar
152 name of the progress bar
138 bar_style: {'success', 'info', 'warning', 'danger', ''}, optional
153 bar_style: {'success', 'info', 'warning', 'danger', ''}, optional
139 color of the progress bar, default is '' (blue)
154 color of the progress bar, default is '' (blue)
140 colors are: 'success'-green, 'info'-light blue, 'warning'-orange, 'danger'-red
155 colors are: 'success'-green, 'info'-light blue, 'warning'-orange, 'danger'-red
141 """
156 """
142 _view_name = Unicode('ProgressView', sync=True)
157 _view_name = Unicode('ProgressView', sync=True)
143
158
144 bar_style = CaselessStrEnum(
159 bar_style = CaselessStrEnum(
145 values=['success', 'info', 'warning', 'danger', ''],
160 values=['success', 'info', 'warning', 'danger', ''],
146 default_value='', allow_none=True, sync=True, help="""Use a
161 default_value='', allow_none=True, sync=True, help="""Use a
147 predefined styling for the progess bar.""")
162 predefined styling for the progess bar.""")
148
163
149 class _FloatRange(_Float):
164 class _FloatRange(_Float):
150 value = Tuple(CFloat, CFloat, default_value=(0.0, 1.0), help="Tuple of (lower, upper) bounds", sync=True)
165 value = Tuple(CFloat, CFloat, default_value=(0.0, 1.0), help="Tuple of (lower, upper) bounds", sync=True)
151 lower = CFloat(0.0, help="Lower bound", sync=False)
166 lower = CFloat(0.0, help="Lower bound", sync=False)
152 upper = CFloat(1.0, help="Upper bound", sync=False)
167 upper = CFloat(1.0, help="Upper bound", sync=False)
153
168
154 def __init__(self, *pargs, **kwargs):
169 def __init__(self, *pargs, **kwargs):
155 value_given = 'value' in kwargs
170 value_given = 'value' in kwargs
156 lower_given = 'lower' in kwargs
171 lower_given = 'lower' in kwargs
157 upper_given = 'upper' in kwargs
172 upper_given = 'upper' in kwargs
158 if value_given and (lower_given or upper_given):
173 if value_given and (lower_given or upper_given):
159 raise ValueError("Cannot specify both 'value' and 'lower'/'upper' for range widget")
174 raise ValueError("Cannot specify both 'value' and 'lower'/'upper' for range widget")
160 if lower_given != upper_given:
175 if lower_given != upper_given:
161 raise ValueError("Must specify both 'lower' and 'upper' for range widget")
176 raise ValueError("Must specify both 'lower' and 'upper' for range widget")
162
177
163 DOMWidget.__init__(self, *pargs, **kwargs)
178 DOMWidget.__init__(self, *pargs, **kwargs)
164
179
165 # ensure the traits match, preferring whichever (if any) was given in kwargs
180 # ensure the traits match, preferring whichever (if any) was given in kwargs
166 if value_given:
181 if value_given:
167 self.lower, self.upper = self.value
182 self.lower, self.upper = self.value
168 else:
183 else:
169 self.value = (self.lower, self.upper)
184 self.value = (self.lower, self.upper)
170
185
171 self.on_trait_change(self._validate, ['value', 'upper', 'lower'])
186 self.on_trait_change(self._validate, ['value', 'upper', 'lower'])
172
187
173 def _validate(self, name, old, new):
188 def _validate(self, name, old, new):
174 if name == 'value':
189 if name == 'value':
175 self.lower, self.upper = min(new), max(new)
190 self.lower, self.upper = min(new), max(new)
176 elif name == 'lower':
191 elif name == 'lower':
177 self.value = (new, self.value[1])
192 self.value = (new, self.value[1])
178 elif name == 'upper':
193 elif name == 'upper':
179 self.value = (self.value[0], new)
194 self.value = (self.value[0], new)
180
195
181 class _BoundedFloatRange(_FloatRange):
196 class _BoundedFloatRange(_FloatRange):
182 step = CFloat(1.0, help="Minimum step that the value can take (ignored by some views)", sync=True)
197 step = CFloat(1.0, help="Minimum step that the value can take (ignored by some views)", sync=True)
183 max = CFloat(100.0, help="Max value", sync=True)
198 max = CFloat(100.0, help="Max value", sync=True)
184 min = CFloat(0.0, help="Min value", sync=True)
199 min = CFloat(0.0, help="Min value", sync=True)
185
200
186 def __init__(self, *pargs, **kwargs):
201 def __init__(self, *pargs, **kwargs):
187 any_value_given = 'value' in kwargs or 'upper' in kwargs or 'lower' in kwargs
202 any_value_given = 'value' in kwargs or 'upper' in kwargs or 'lower' in kwargs
188 _FloatRange.__init__(self, *pargs, **kwargs)
203 _FloatRange.__init__(self, *pargs, **kwargs)
189
204
190 # ensure a minimal amount of sanity
205 # ensure a minimal amount of sanity
191 if self.min > self.max:
206 if self.min > self.max:
192 raise ValueError("min must be <= max")
207 raise ValueError("min must be <= max")
193
208
194 if any_value_given:
209 if any_value_given:
195 # if a value was given, clamp it within (min, max)
210 # if a value was given, clamp it within (min, max)
196 self._validate("value", None, self.value)
211 self._validate("value", None, self.value)
197 else:
212 else:
198 # otherwise, set it to 25-75% to avoid the handles overlapping
213 # otherwise, set it to 25-75% to avoid the handles overlapping
199 self.value = (0.75*self.min + 0.25*self.max,
214 self.value = (0.75*self.min + 0.25*self.max,
200 0.25*self.min + 0.75*self.max)
215 0.25*self.min + 0.75*self.max)
201 # callback already set for 'value', 'lower', 'upper'
216 # callback already set for 'value', 'lower', 'upper'
202 self.on_trait_change(self._validate, ['min', 'max'])
217 self.on_trait_change(self._validate, ['min', 'max'])
203
218
204
219
205 def _validate(self, name, old, new):
220 def _validate(self, name, old, new):
206 if name == "min":
221 if name == "min":
207 if new > self.max:
222 if new > self.max:
208 raise ValueError("setting min > max")
223 raise ValueError("setting min > max")
209 self.min = new
224 self.min = new
210 elif name == "max":
225 elif name == "max":
211 if new < self.min:
226 if new < self.min:
212 raise ValueError("setting max < min")
227 raise ValueError("setting max < min")
213 self.max = new
228 self.max = new
214
229
215 low, high = self.value
230 low, high = self.value
216 if name == "value":
231 if name == "value":
217 low, high = min(new), max(new)
232 low, high = min(new), max(new)
218 elif name == "upper":
233 elif name == "upper":
219 if new < self.lower:
234 if new < self.lower:
220 raise ValueError("setting upper < lower")
235 raise ValueError("setting upper < lower")
221 high = new
236 high = new
222 elif name == "lower":
237 elif name == "lower":
223 if new > self.upper:
238 if new > self.upper:
224 raise ValueError("setting lower > upper")
239 raise ValueError("setting lower > upper")
225 low = new
240 low = new
226
241
227 low = max(self.min, min(low, self.max))
242 low = max(self.min, min(low, self.max))
228 high = min(self.max, max(high, self.min))
243 high = min(self.max, max(high, self.min))
229
244
230 # determine the order in which we should update the
245 # determine the order in which we should update the
231 # lower, upper traits to avoid a temporary inverted overlap
246 # lower, upper traits to avoid a temporary inverted overlap
232 lower_first = high < self.lower
247 lower_first = high < self.lower
233
248
234 self.value = (low, high)
249 self.value = (low, high)
235 if lower_first:
250 if lower_first:
236 self.lower = low
251 self.lower = low
237 self.upper = high
252 self.upper = high
238 else:
253 else:
239 self.upper = high
254 self.upper = high
240 self.lower = low
255 self.lower = low
241
256
242
257
243 @register('IPython.FloatRangeSlider')
258 @register('IPython.FloatRangeSlider')
244 class FloatRangeSlider(_BoundedFloatRange):
259 class FloatRangeSlider(_BoundedFloatRange):
245 """ Slider/trackbar for displaying a floating value range (within the specified range of values).
260 """ Slider/trackbar for displaying a floating value range (within the specified range of values).
246
261
247 Parameters
262 Parameters
248 ----------
263 ----------
249 value : float tuple
264 value : float tuple
250 range of the slider displayed
265 range of the slider displayed
251 min : float
266 min : float
252 minimal position of the slider
267 minimal position of the slider
253 max : float
268 max : float
254 maximal position of the slider
269 maximal position of the slider
255 step : float
270 step : float
256 step of the trackbar
271 step of the trackbar
257 description : str
272 description : str
258 name of the slider
273 name of the slider
259 orientation : {'vertical', 'horizontal}, optional
274 orientation : {'vertical', 'horizontal}, optional
260 default is horizontal
275 default is horizontal
261 readout : {True, False}, optional
276 readout : {True, False}, optional
262 default is True, display the current value of the slider next to it
277 default is True, display the current value of the slider next to it
263 slider_color : str Unicode color code (eg. '#C13535'), optional
278 slider_color : str Unicode color code (eg. '#C13535'), optional
264 color of the slider
279 color of the slider
265 color : str Unicode color code (eg. '#C13535'), optional
280 color : str Unicode color code (eg. '#C13535'), optional
266 color of the value displayed (if readout == True)
281 color of the value displayed (if readout == True)
267 """
282 """
268 _view_name = Unicode('FloatSliderView', sync=True)
283 _view_name = Unicode('FloatSliderView', sync=True)
269 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
284 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
270 default_value='horizontal', allow_none=False,
285 default_value='horizontal', allow_none=False,
271 help="Vertical or horizontal.", sync=True)
286 help="Vertical or horizontal.", sync=True)
272 _range = Bool(True, help="Display a range selector", sync=True)
287 _range = Bool(True, help="Display a range selector", sync=True)
273 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
288 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
274 slider_color = Unicode(sync=True)
289 slider_color = Unicode(sync=True)
275
290
276 # Remove in IPython 4.0
291 # Remove in IPython 4.0
277 FloatTextWidget = DeprecatedClass(FloatText, 'FloatTextWidget')
292 FloatTextWidget = DeprecatedClass(FloatText, 'FloatTextWidget')
278 BoundedFloatTextWidget = DeprecatedClass(BoundedFloatText, 'BoundedFloatTextWidget')
293 BoundedFloatTextWidget = DeprecatedClass(BoundedFloatText, 'BoundedFloatTextWidget')
279 FloatSliderWidget = DeprecatedClass(FloatSlider, 'FloatSliderWidget')
294 FloatSliderWidget = DeprecatedClass(FloatSlider, 'FloatSliderWidget')
280 FloatProgressWidget = DeprecatedClass(FloatProgress, 'FloatProgressWidget')
295 FloatProgressWidget = DeprecatedClass(FloatProgress, 'FloatProgressWidget')
@@ -1,202 +1,206 b''
1 """Int class.
1 """Int class.
2
2
3 Represents an unbounded int using a widget.
3 Represents an unbounded int using a widget.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from .widget import DOMWidget, register
16 from .widget import DOMWidget, register
17 from IPython.utils.traitlets import Unicode, CInt, Bool, CaselessStrEnum, Tuple
17 from IPython.utils.traitlets import Unicode, CInt, Bool, CaselessStrEnum, Tuple
18 from IPython.utils.warn import DeprecatedClass
18 from IPython.utils.warn import DeprecatedClass
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Classes
21 # Classes
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 class _Int(DOMWidget):
23 class _Int(DOMWidget):
24 """Base class used to create widgets that represent an int."""
24 """Base class used to create widgets that represent an int."""
25 value = CInt(0, help="Int value", sync=True)
25 value = CInt(0, help="Int value", sync=True)
26 disabled = Bool(False, help="Enable or disable user changes", sync=True)
26 disabled = Bool(False, help="Enable or disable user changes", sync=True)
27 description = Unicode(help="Description of the value this widget represents", sync=True)
27 description = Unicode(help="Description of the value this widget represents", sync=True)
28
28
29 def __init__(self, value=None, **kwargs):
29 def __init__(self, value=None, **kwargs):
30 if value is not None:
30 if value is not None:
31 kwargs['value'] = value
31 kwargs['value'] = value
32 super(_Int, self).__init__(**kwargs)
32 super(_Int, self).__init__(**kwargs)
33
33
34 class _BoundedInt(_Int):
34 class _BoundedInt(_Int):
35 """Base class used to create widgets that represent a int that is bounded
35 """Base class used to create widgets that represent a int that is bounded
36 by a minium and maximum."""
36 by a minium and maximum."""
37 step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True)
37 step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True)
38 max = CInt(100, help="Max value", sync=True)
38 max = CInt(100, help="Max value", sync=True)
39 min = CInt(0, help="Min value", sync=True)
39 min = CInt(0, help="Min value", sync=True)
40
40
41 def __init__(self, *pargs, **kwargs):
41 def __init__(self, *pargs, **kwargs):
42 """Constructor"""
42 """Constructor"""
43 super(_BoundedInt, self).__init__(*pargs, **kwargs)
43 super(_BoundedInt, self).__init__(*pargs, **kwargs)
44 self.on_trait_change(self._validate_value, ['value'])
44 self._value_changed('value', None, self.value)
45 self.on_trait_change(self._handle_max_changed, ['max'])
45 self._min_changed('min', None, self.min)
46 self.on_trait_change(self._handle_min_changed, ['min'])
46 self._max_changed('max', None, self.max)
47
47
48 def _validate_value(self, name, old, new):
48 def _value_changed(self, name, old, new):
49 """Validate value."""
49 """Validate value."""
50 if self.min > new or new > self.max:
50 if self.min > new or new > self.max:
51 self.value = min(max(new, self.min), self.max)
51 self.value = min(max(new, self.min), self.max)
52
52
53 def _handle_max_changed(self, name, old, new):
53 def _max_changed(self, name, old, new):
54 """Make sure the min is always <= the max."""
54 """Make sure the min is always <= the max."""
55 if new < self.min:
55 if new < self.min:
56 raise ValueError("setting max < min")
56 raise ValueError("setting max < min")
57 if new < self.value:
58 self.value = new
57
59
58 def _handle_min_changed(self, name, old, new):
60 def _min_changed(self, name, old, new):
59 """Make sure the max is always >= the min."""
61 """Make sure the max is always >= the min."""
60 if new > self.max:
62 if new > self.max:
61 raise ValueError("setting min > max")
63 raise ValueError("setting min > max")
64 if new > self.value:
65 self.value = new
62
66
63 @register('IPython.IntText')
67 @register('IPython.IntText')
64 class IntText(_Int):
68 class IntText(_Int):
65 """Textbox widget that represents a int."""
69 """Textbox widget that represents a int."""
66 _view_name = Unicode('IntTextView', sync=True)
70 _view_name = Unicode('IntTextView', sync=True)
67
71
68
72
69 @register('IPython.BoundedIntText')
73 @register('IPython.BoundedIntText')
70 class BoundedIntText(_BoundedInt):
74 class BoundedIntText(_BoundedInt):
71 """Textbox widget that represents a int bounded by a minimum and maximum value."""
75 """Textbox widget that represents a int bounded by a minimum and maximum value."""
72 _view_name = Unicode('IntTextView', sync=True)
76 _view_name = Unicode('IntTextView', sync=True)
73
77
74
78
75 @register('IPython.IntSlider')
79 @register('IPython.IntSlider')
76 class IntSlider(_BoundedInt):
80 class IntSlider(_BoundedInt):
77 """Slider widget that represents a int bounded by a minimum and maximum value."""
81 """Slider widget that represents a int bounded by a minimum and maximum value."""
78 _view_name = Unicode('IntSliderView', sync=True)
82 _view_name = Unicode('IntSliderView', sync=True)
79 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
83 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
80 default_value='horizontal', allow_none=False,
84 default_value='horizontal', allow_none=False,
81 help="Vertical or horizontal.", sync=True)
85 help="Vertical or horizontal.", sync=True)
82 _range = Bool(False, help="Display a range selector", sync=True)
86 _range = Bool(False, help="Display a range selector", sync=True)
83 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
87 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
84 slider_color = Unicode(sync=True)
88 slider_color = Unicode(sync=True)
85
89
86
90
87 @register('IPython.IntProgress')
91 @register('IPython.IntProgress')
88 class IntProgress(_BoundedInt):
92 class IntProgress(_BoundedInt):
89 """Progress bar that represents a int bounded by a minimum and maximum value."""
93 """Progress bar that represents a int bounded by a minimum and maximum value."""
90 _view_name = Unicode('ProgressView', sync=True)
94 _view_name = Unicode('ProgressView', sync=True)
91
95
92 bar_style = CaselessStrEnum(
96 bar_style = CaselessStrEnum(
93 values=['success', 'info', 'warning', 'danger', ''],
97 values=['success', 'info', 'warning', 'danger', ''],
94 default_value='', allow_none=True, sync=True, help="""Use a
98 default_value='', allow_none=True, sync=True, help="""Use a
95 predefined styling for the progess bar.""")
99 predefined styling for the progess bar.""")
96
100
97 class _IntRange(_Int):
101 class _IntRange(_Int):
98 value = Tuple(CInt, CInt, default_value=(0, 1), help="Tuple of (lower, upper) bounds", sync=True)
102 value = Tuple(CInt, CInt, default_value=(0, 1), help="Tuple of (lower, upper) bounds", sync=True)
99 lower = CInt(0, help="Lower bound", sync=False)
103 lower = CInt(0, help="Lower bound", sync=False)
100 upper = CInt(1, help="Upper bound", sync=False)
104 upper = CInt(1, help="Upper bound", sync=False)
101
105
102 def __init__(self, *pargs, **kwargs):
106 def __init__(self, *pargs, **kwargs):
103 value_given = 'value' in kwargs
107 value_given = 'value' in kwargs
104 lower_given = 'lower' in kwargs
108 lower_given = 'lower' in kwargs
105 upper_given = 'upper' in kwargs
109 upper_given = 'upper' in kwargs
106 if value_given and (lower_given or upper_given):
110 if value_given and (lower_given or upper_given):
107 raise ValueError("Cannot specify both 'value' and 'lower'/'upper' for range widget")
111 raise ValueError("Cannot specify both 'value' and 'lower'/'upper' for range widget")
108 if lower_given != upper_given:
112 if lower_given != upper_given:
109 raise ValueError("Must specify both 'lower' and 'upper' for range widget")
113 raise ValueError("Must specify both 'lower' and 'upper' for range widget")
110
114
111 super(_IntRange, self).__init__(*pargs, **kwargs)
115 super(_IntRange, self).__init__(*pargs, **kwargs)
112
116
113 # ensure the traits match, preferring whichever (if any) was given in kwargs
117 # ensure the traits match, preferring whichever (if any) was given in kwargs
114 if value_given:
118 if value_given:
115 self.lower, self.upper = self.value
119 self.lower, self.upper = self.value
116 else:
120 else:
117 self.value = (self.lower, self.upper)
121 self.value = (self.lower, self.upper)
118
122
119 self.on_trait_change(self._validate, ['value', 'upper', 'lower'])
123 self.on_trait_change(self._validate, ['value', 'upper', 'lower'])
120
124
121 def _validate(self, name, old, new):
125 def _validate(self, name, old, new):
122 if name == 'value':
126 if name == 'value':
123 self.lower, self.upper = min(new), max(new)
127 self.lower, self.upper = min(new), max(new)
124 elif name == 'lower':
128 elif name == 'lower':
125 self.value = (new, self.value[1])
129 self.value = (new, self.value[1])
126 elif name == 'upper':
130 elif name == 'upper':
127 self.value = (self.value[0], new)
131 self.value = (self.value[0], new)
128
132
129 class _BoundedIntRange(_IntRange):
133 class _BoundedIntRange(_IntRange):
130 step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True)
134 step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True)
131 max = CInt(100, help="Max value", sync=True)
135 max = CInt(100, help="Max value", sync=True)
132 min = CInt(0, help="Min value", sync=True)
136 min = CInt(0, help="Min value", sync=True)
133
137
134 def __init__(self, *pargs, **kwargs):
138 def __init__(self, *pargs, **kwargs):
135 any_value_given = 'value' in kwargs or 'upper' in kwargs or 'lower' in kwargs
139 any_value_given = 'value' in kwargs or 'upper' in kwargs or 'lower' in kwargs
136 _IntRange.__init__(self, *pargs, **kwargs)
140 _IntRange.__init__(self, *pargs, **kwargs)
137
141
138 # ensure a minimal amount of sanity
142 # ensure a minimal amount of sanity
139 if self.min > self.max:
143 if self.min > self.max:
140 raise ValueError("min must be <= max")
144 raise ValueError("min must be <= max")
141
145
142 if any_value_given:
146 if any_value_given:
143 # if a value was given, clamp it within (min, max)
147 # if a value was given, clamp it within (min, max)
144 self._validate("value", None, self.value)
148 self._validate("value", None, self.value)
145 else:
149 else:
146 # otherwise, set it to 25-75% to avoid the handles overlapping
150 # otherwise, set it to 25-75% to avoid the handles overlapping
147 self.value = (0.75*self.min + 0.25*self.max,
151 self.value = (0.75*self.min + 0.25*self.max,
148 0.25*self.min + 0.75*self.max)
152 0.25*self.min + 0.75*self.max)
149 # callback already set for 'value', 'lower', 'upper'
153 # callback already set for 'value', 'lower', 'upper'
150 self.on_trait_change(self._validate, ['min', 'max'])
154 self.on_trait_change(self._validate, ['min', 'max'])
151
155
152 def _validate(self, name, old, new):
156 def _validate(self, name, old, new):
153 if name == "min":
157 if name == "min":
154 if new > self.max:
158 if new > self.max:
155 raise ValueError("setting min > max")
159 raise ValueError("setting min > max")
156 elif name == "max":
160 elif name == "max":
157 if new < self.min:
161 if new < self.min:
158 raise ValueError("setting max < min")
162 raise ValueError("setting max < min")
159
163
160 low, high = self.value
164 low, high = self.value
161 if name == "value":
165 if name == "value":
162 low, high = min(new), max(new)
166 low, high = min(new), max(new)
163 elif name == "upper":
167 elif name == "upper":
164 if new < self.lower:
168 if new < self.lower:
165 raise ValueError("setting upper < lower")
169 raise ValueError("setting upper < lower")
166 high = new
170 high = new
167 elif name == "lower":
171 elif name == "lower":
168 if new > self.upper:
172 if new > self.upper:
169 raise ValueError("setting lower > upper")
173 raise ValueError("setting lower > upper")
170 low = new
174 low = new
171
175
172 low = max(self.min, min(low, self.max))
176 low = max(self.min, min(low, self.max))
173 high = min(self.max, max(high, self.min))
177 high = min(self.max, max(high, self.min))
174
178
175 # determine the order in which we should update the
179 # determine the order in which we should update the
176 # lower, upper traits to avoid a temporary inverted overlap
180 # lower, upper traits to avoid a temporary inverted overlap
177 lower_first = high < self.lower
181 lower_first = high < self.lower
178
182
179 self.value = (low, high)
183 self.value = (low, high)
180 if lower_first:
184 if lower_first:
181 self.lower = low
185 self.lower = low
182 self.upper = high
186 self.upper = high
183 else:
187 else:
184 self.upper = high
188 self.upper = high
185 self.lower = low
189 self.lower = low
186
190
187 @register('IPython.IntRangeSlider')
191 @register('IPython.IntRangeSlider')
188 class IntRangeSlider(_BoundedIntRange):
192 class IntRangeSlider(_BoundedIntRange):
189 """Slider widget that represents a pair of ints between a minimum and maximum value."""
193 """Slider widget that represents a pair of ints between a minimum and maximum value."""
190 _view_name = Unicode('IntSliderView', sync=True)
194 _view_name = Unicode('IntSliderView', sync=True)
191 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
195 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
192 default_value='horizontal', allow_none=False,
196 default_value='horizontal', allow_none=False,
193 help="Vertical or horizontal.", sync=True)
197 help="Vertical or horizontal.", sync=True)
194 _range = Bool(True, help="Display a range selector", sync=True)
198 _range = Bool(True, help="Display a range selector", sync=True)
195 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
199 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
196 slider_color = Unicode(sync=True)
200 slider_color = Unicode(sync=True)
197
201
198 # Remove in IPython 4.0
202 # Remove in IPython 4.0
199 IntTextWidget = DeprecatedClass(IntText, 'IntTextWidget')
203 IntTextWidget = DeprecatedClass(IntText, 'IntTextWidget')
200 BoundedIntTextWidget = DeprecatedClass(BoundedIntText, 'BoundedIntTextWidget')
204 BoundedIntTextWidget = DeprecatedClass(BoundedIntText, 'BoundedIntTextWidget')
201 IntSliderWidget = DeprecatedClass(IntSlider, 'IntSliderWidget')
205 IntSliderWidget = DeprecatedClass(IntSlider, 'IntSliderWidget')
202 IntProgressWidget = DeprecatedClass(IntProgress, 'IntProgressWidget')
206 IntProgressWidget = DeprecatedClass(IntProgress, 'IntProgressWidget')
General Comments 0
You need to be logged in to leave comments. Login now