##// END OF EJS Templates
Changed children list to CTuple....
Jonathan Frederic -
Show More
@@ -1,443 +1,443 b''
1 1 """Base Widget class. Allows user to create widgets in the back-end that render
2 2 in the IPython notebook front-end.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15 from contextlib import contextmanager
16 16
17 17 from IPython.core.getipython import get_ipython
18 18 from IPython.kernel.comm import Comm
19 19 from IPython.config import LoggingConfigurable
20 20 from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple, Int
21 21 from IPython.utils.py3compat import string_types
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Classes
25 25 #-----------------------------------------------------------------------------
26 26 class CallbackDispatcher(LoggingConfigurable):
27 27 """A structure for registering and running callbacks"""
28 28 callbacks = List()
29 29
30 30 def __call__(self, *args, **kwargs):
31 31 """Call all of the registered callbacks."""
32 32 value = None
33 33 for callback in self.callbacks:
34 34 try:
35 35 local_value = callback(*args, **kwargs)
36 36 except Exception as e:
37 37 ip = get_ipython()
38 38 if ip is None:
39 39 self.log.warn("Exception in callback %s: %s", callback, e, exc_info=True)
40 40 else:
41 41 ip.showtraceback()
42 42 else:
43 43 value = local_value if local_value is not None else value
44 44 return value
45 45
46 46 def register_callback(self, callback, remove=False):
47 47 """(Un)Register a callback
48 48
49 49 Parameters
50 50 ----------
51 51 callback: method handle
52 52 Method to be registered or unregistered.
53 53 remove=False: bool
54 54 Whether to unregister the callback."""
55 55
56 56 # (Un)Register the callback.
57 57 if remove and callback in self.callbacks:
58 58 self.callbacks.remove(callback)
59 59 elif not remove and callback not in self.callbacks:
60 60 self.callbacks.append(callback)
61 61
62 62 def _show_traceback(method):
63 63 """decorator for showing tracebacks in IPython"""
64 64 def m(self, *args, **kwargs):
65 65 try:
66 66 return(method(self, *args, **kwargs))
67 67 except Exception as e:
68 68 ip = get_ipython()
69 69 if ip is None:
70 70 self.log.warn("Exception in widget method %s: %s", method, e, exc_info=True)
71 71 else:
72 72 ip.showtraceback()
73 73 return m
74 74
75 75 class Widget(LoggingConfigurable):
76 76 #-------------------------------------------------------------------------
77 77 # Class attributes
78 78 #-------------------------------------------------------------------------
79 79 _widget_construction_callback = None
80 80 widgets = {}
81 81
82 82 @staticmethod
83 83 def on_widget_constructed(callback):
84 84 """Registers a callback to be called when a widget is constructed.
85 85
86 86 The callback must have the following signature:
87 87 callback(widget)"""
88 88 Widget._widget_construction_callback = callback
89 89
90 90 @staticmethod
91 91 def _call_widget_constructed(widget):
92 92 """Static method, called when a widget is constructed."""
93 93 if Widget._widget_construction_callback is not None and callable(Widget._widget_construction_callback):
94 94 Widget._widget_construction_callback(widget)
95 95
96 96 #-------------------------------------------------------------------------
97 97 # Traits
98 98 #-------------------------------------------------------------------------
99 99 _model_name = Unicode('WidgetModel', help="""Name of the backbone model
100 100 registered in the front-end to create and sync this widget with.""")
101 101 _view_name = Unicode(help="""Default view registered in the front-end
102 102 to use to represent the widget.""", sync=True)
103 103 _comm = Instance('IPython.kernel.comm.Comm')
104 104
105 105 closed = Bool(False)
106 106 msg_throttle = Int(3, sync=True, help="""Maximum number of msgs the
107 107 front-end can send before receiving an idle msg from the back-end.""")
108 108
109 109 keys = List()
110 110 def _keys_default(self):
111 111 return [name for name in self.traits(sync=True)]
112 112
113 113 _property_lock = Tuple((None, None))
114 114
115 115 _display_callbacks = Instance(CallbackDispatcher, ())
116 116 _msg_callbacks = Instance(CallbackDispatcher, ())
117 117
118 118 #-------------------------------------------------------------------------
119 119 # (Con/de)structor
120 120 #-------------------------------------------------------------------------
121 121 def __init__(self, **kwargs):
122 122 """Public constructor"""
123 123 super(Widget, self).__init__(**kwargs)
124 124
125 125 self.on_trait_change(self._handle_property_changed, self.keys)
126 126 Widget._call_widget_constructed(self)
127 127
128 128 def __del__(self):
129 129 """Object disposal"""
130 130 self.close()
131 131
132 132 #-------------------------------------------------------------------------
133 133 # Properties
134 134 #-------------------------------------------------------------------------
135 135
136 136 @property
137 137 def comm(self):
138 138 """Gets the Comm associated with this widget.
139 139
140 140 If a Comm doesn't exist yet, a Comm will be created automagically."""
141 141 if self._comm is None:
142 142 # Create a comm.
143 143 self._comm = Comm(target_name=self._model_name)
144 144 self._comm.on_msg(self._handle_msg)
145 145 self._comm.on_close(self._close)
146 146 Widget.widgets[self.model_id] = self
147 147
148 148 # first update
149 149 self.send_state()
150 150 return self._comm
151 151
152 152 @property
153 153 def model_id(self):
154 154 """Gets the model id of this widget.
155 155
156 156 If a Comm doesn't exist yet, a Comm will be created automagically."""
157 157 return self.comm.comm_id
158 158
159 159 #-------------------------------------------------------------------------
160 160 # Methods
161 161 #-------------------------------------------------------------------------
162 162 def _close(self):
163 163 """Private close - cleanup objects, registry entries"""
164 164 del Widget.widgets[self.model_id]
165 165 self._comm = None
166 166 self.closed = True
167 167
168 168 def close(self):
169 169 """Close method.
170 170
171 171 Closes the widget which closes the underlying comm.
172 172 When the comm is closed, all of the widget views are automatically
173 173 removed from the front-end."""
174 174 if not self.closed:
175 175 self._comm.close()
176 176 self._close()
177 177
178 178 def send_state(self, key=None):
179 179 """Sends the widget state, or a piece of it, to the front-end.
180 180
181 181 Parameters
182 182 ----------
183 183 key : unicode (optional)
184 184 A single property's name to sync with the front-end.
185 185 """
186 186 self._send({
187 187 "method" : "update",
188 188 "state" : self.get_state()
189 189 })
190 190
191 191 def get_state(self, key=None):
192 192 """Gets the widget state, or a piece of it.
193 193
194 194 Parameters
195 195 ----------
196 196 key : unicode (optional)
197 197 A single property's name to get.
198 198 """
199 199 keys = self.keys if key is None else [key]
200 200 return {k: self._pack_widgets(getattr(self, k)) for k in keys}
201 201
202 202 def send(self, content):
203 203 """Sends a custom msg to the widget model in the front-end.
204 204
205 205 Parameters
206 206 ----------
207 207 content : dict
208 208 Content of the message to send.
209 209 """
210 210 self._send({"method": "custom", "content": content})
211 211
212 212 def on_msg(self, callback, remove=False):
213 213 """(Un)Register a custom msg receive callback.
214 214
215 215 Parameters
216 216 ----------
217 217 callback: callable
218 218 callback will be passed two arguments when a message arrives::
219 219
220 220 callback(widget, content)
221 221
222 222 remove: bool
223 223 True if the callback should be unregistered."""
224 224 self._msg_callbacks.register_callback(callback, remove=remove)
225 225
226 226 def on_displayed(self, callback, remove=False):
227 227 """(Un)Register a widget displayed callback.
228 228
229 229 Parameters
230 230 ----------
231 231 callback: method handler
232 232 Must have a signature of::
233 233
234 234 callback(widget, **kwargs)
235 235
236 236 kwargs from display are passed through without modification.
237 237 remove: bool
238 238 True if the callback should be unregistered."""
239 239 self._display_callbacks.register_callback(callback, remove=remove)
240 240
241 241 #-------------------------------------------------------------------------
242 242 # Support methods
243 243 #-------------------------------------------------------------------------
244 244 @contextmanager
245 245 def _lock_property(self, key, value):
246 246 """Lock a property-value pair.
247 247
248 248 NOTE: This, in addition to the single lock for all state changes, is
249 249 flawed. In the future we may want to look into buffering state changes
250 250 back to the front-end."""
251 251 self._property_lock = (key, value)
252 252 try:
253 253 yield
254 254 finally:
255 255 self._property_lock = (None, None)
256 256
257 257 def _should_send_property(self, key, value):
258 258 """Check the property lock (property_lock)"""
259 259 return key != self._property_lock[0] or \
260 260 value != self._property_lock[1]
261 261
262 262 # Event handlers
263 263 @_show_traceback
264 264 def _handle_msg(self, msg):
265 265 """Called when a msg is received from the front-end"""
266 266 data = msg['content']['data']
267 267 method = data['method']
268 268 if not method in ['backbone', 'custom']:
269 269 self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)
270 270
271 271 # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
272 272 if method == 'backbone' and 'sync_data' in data:
273 273 sync_data = data['sync_data']
274 274 self._handle_receive_state(sync_data) # handles all methods
275 275
276 276 # Handle a custom msg from the front-end
277 277 elif method == 'custom':
278 278 if 'content' in data:
279 279 self._handle_custom_msg(data['content'])
280 280
281 281 def _handle_receive_state(self, sync_data):
282 282 """Called when a state is received from the front-end."""
283 283 for name in self.keys:
284 284 if name in sync_data:
285 285 value = self._unpack_widgets(sync_data[name])
286 286 with self._lock_property(name, value):
287 287 setattr(self, name, value)
288 288
289 289 def _handle_custom_msg(self, content):
290 290 """Called when a custom msg is received."""
291 291 self._msg_callbacks(self, content)
292 292
293 293 def _handle_property_changed(self, name, old, new):
294 294 """Called when a property has been changed."""
295 295 # Make sure this isn't information that the front-end just sent us.
296 296 if self._should_send_property(name, new):
297 297 # Send new state to front-end
298 298 self.send_state(key=name)
299 299
300 300 def _handle_displayed(self, **kwargs):
301 301 """Called when a view has been displayed for this widget instance"""
302 302 self._display_callbacks(self, **kwargs)
303 303
304 304 def _pack_widgets(self, x):
305 305 """Recursively converts all widget instances to model id strings.
306 306
307 307 Children widgets will be stored and transmitted to the front-end by
308 308 their model ids. Return value must be JSON-able."""
309 309 if isinstance(x, dict):
310 310 return {k: self._pack_widgets(v) for k, v in x.items()}
311 elif isinstance(x, list):
311 elif isinstance(x, (list, tuple)):
312 312 return [self._pack_widgets(v) for v in x]
313 313 elif isinstance(x, Widget):
314 314 return x.model_id
315 315 else:
316 316 return x # Value must be JSON-able
317 317
318 318 def _unpack_widgets(self, x):
319 319 """Recursively converts all model id strings to widget instances.
320 320
321 321 Children widgets will be stored and transmitted to the front-end by
322 322 their model ids."""
323 323 if isinstance(x, dict):
324 324 return {k: self._unpack_widgets(v) for k, v in x.items()}
325 elif isinstance(x, list):
325 elif isinstance(x, (list, tuple)):
326 326 return [self._unpack_widgets(v) for v in x]
327 327 elif isinstance(x, string_types):
328 328 return x if x not in Widget.widgets else Widget.widgets[x]
329 329 else:
330 330 return x
331 331
332 332 def _ipython_display_(self, **kwargs):
333 333 """Called when `IPython.display.display` is called on the widget."""
334 334 # Show view. By sending a display message, the comm is opened and the
335 335 # initial state is sent.
336 336 self._send({"method": "display"})
337 337 self._handle_displayed(**kwargs)
338 338
339 339 def _send(self, msg):
340 340 """Sends a message to the model in the front-end."""
341 341 self.comm.send(msg)
342 342
343 343
344 344 class DOMWidget(Widget):
345 345 visible = Bool(True, help="Whether the widget is visible.", sync=True)
346 346 _css = Dict(sync=True) # Internal CSS property dict
347 347
348 348 def get_css(self, key, selector=""):
349 349 """Get a CSS property of the widget.
350 350
351 351 Note: This function does not actually request the CSS from the
352 352 front-end; Only properties that have been set with set_css can be read.
353 353
354 354 Parameters
355 355 ----------
356 356 key: unicode
357 357 CSS key
358 358 selector: unicode (optional)
359 359 JQuery selector used when the CSS key/value was set.
360 360 """
361 361 if selector in self._css and key in self._css[selector]:
362 362 return self._css[selector][key]
363 363 else:
364 364 return None
365 365
366 366 def set_css(self, dict_or_key, value=None, selector=''):
367 367 """Set one or more CSS properties of the widget.
368 368
369 369 This function has two signatures:
370 370 - set_css(css_dict, selector='')
371 371 - set_css(key, value, selector='')
372 372
373 373 Parameters
374 374 ----------
375 375 css_dict : dict
376 376 CSS key/value pairs to apply
377 377 key: unicode
378 378 CSS key
379 379 value:
380 380 CSS value
381 381 selector: unicode (optional, kwarg only)
382 382 JQuery selector to use to apply the CSS key/value. If no selector
383 383 is provided, an empty selector is used. An empty selector makes the
384 384 front-end try to apply the css to a default element. The default
385 385 element is an attribute unique to each view, which is a DOM element
386 386 of the view that should be styled with common CSS (see
387 387 `$el_to_style` in the Javascript code).
388 388 """
389 389 if not selector in self._css:
390 390 self._css[selector] = {}
391 391 my_css = self._css[selector]
392 392
393 393 if value is None:
394 394 css_dict = dict_or_key
395 395 else:
396 396 css_dict = {dict_or_key: value}
397 397
398 398 for (key, value) in css_dict.items():
399 399 if not (key in my_css and value == my_css[key]):
400 400 my_css[key] = value
401 401 self.send_state('_css')
402 402
403 403 def add_class(self, class_names, selector=""):
404 404 """Add class[es] to a DOM element.
405 405
406 406 Parameters
407 407 ----------
408 408 class_names: unicode or list
409 409 Class name(s) to add to the DOM element(s).
410 410 selector: unicode (optional)
411 411 JQuery selector to select the DOM element(s) that the class(es) will
412 412 be added to.
413 413 """
414 414 class_list = class_names
415 if isinstance(class_list, list):
415 if isinstance(class_list, (list, tuple)):
416 416 class_list = ' '.join(class_list)
417 417
418 418 self.send({
419 419 "msg_type" : "add_class",
420 420 "class_list" : class_list,
421 421 "selector" : selector
422 422 })
423 423
424 424 def remove_class(self, class_names, selector=""):
425 425 """Remove class[es] from a DOM element.
426 426
427 427 Parameters
428 428 ----------
429 429 class_names: unicode or list
430 430 Class name(s) to remove from the DOM element(s).
431 431 selector: unicode (optional)
432 432 JQuery selector to select the DOM element(s) that the class(es) will
433 433 be removed from.
434 434 """
435 435 class_list = class_names
436 if isinstance(class_list, list):
436 if isinstance(class_list, (list, tuple)):
437 437 class_list = ' '.join(class_list)
438 438
439 439 self.send({
440 440 "msg_type" : "remove_class",
441 441 "class_list" : class_list,
442 442 "selector" : selector,
443 443 })
@@ -1,34 +1,34 b''
1 1 """BoolWidget class.
2 2
3 3 Represents a boolean using a widget.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from .widget import DOMWidget
17 from IPython.utils.traitlets import Unicode, Bool, List
17 from IPython.utils.traitlets import Unicode, Bool
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Classes
21 21 #-----------------------------------------------------------------------------
22 22 class _BoolWidget(DOMWidget):
23 23 value = Bool(False, help="Bool value", sync=True)
24 24 description = Unicode('', help="Description of the boolean (label).", sync=True)
25 25 disabled = Bool(False, help="Enable or disable user changes.", sync=True)
26 26
27 27
28 28 class CheckboxWidget(_BoolWidget):
29 29 _view_name = Unicode('CheckboxView', sync=True)
30 30
31 31
32 32 class ToggleButtonWidget(_BoolWidget):
33 33 _view_name = Unicode('ToggleButtonView', sync=True)
34 34 No newline at end of file
@@ -1,51 +1,51 b''
1 1 """ContainerWidget class.
2 2
3 3 Represents a container that can be used to group other widgets.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from .widget import DOMWidget
17 from IPython.utils.traitlets import Unicode, Bool, List, Instance
17 from IPython.utils.traitlets import Unicode, CTuple, Instance
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Classes
21 21 #-----------------------------------------------------------------------------
22 22 class ContainerWidget(DOMWidget):
23 23 _view_name = Unicode('ContainerView', sync=True)
24 24
25 25 # Keys, all private and managed by helper methods. Flexible box model
26 26 # classes...
27 children = List(Instance(DOMWidget))
28 _children = List(Instance(DOMWidget), sync=True)
27 children = CTuple(Instance(DOMWidget))
28 _children = CTuple(Instance(DOMWidget), sync=True)
29 29
30 30 def _children_changed(self, name, old, new):
31 31 """Validate children list.
32 32
33 33 Makes sure only one instance of any given model can exist in the
34 34 children list.
35 35 An excellent post on uniqifiers is available at
36 36 http://www.peterbe.com/plog/uniqifiers-benchmark
37 37 which provides the inspiration for using this implementation. Below
38 38 I've implemented the `f5` algorithm using Python comprehensions."""
39 39 if new is not None and isinstance(new, list):
40 40 seen = {}
41 41 def add_item(i):
42 42 seen[i.model_id] = True
43 43 return i
44 44 self._children = [add_item(i) for i in new if not i.model_id in seen]
45 45
46 46
47 47 class PopupWidget(ContainerWidget):
48 48 _view_name = Unicode('PopupView', sync=True)
49 49
50 50 description = Unicode(sync=True)
51 51 button_text = Unicode(sync=True)
@@ -1,60 +1,60 b''
1 1 """FloatWidget class.
2 2
3 3 Represents an unbounded float using a widget.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from .widget import DOMWidget
17 from IPython.utils.traitlets import Unicode, CFloat, Bool, List, Enum
17 from IPython.utils.traitlets import Unicode, CFloat, Bool, Enum
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Classes
21 21 #-----------------------------------------------------------------------------
22 22 class _FloatWidget(DOMWidget):
23 23 value = CFloat(0.0, help="Float value", sync=True)
24 24 disabled = Bool(False, help="Enable or disable user changes", sync=True)
25 25 description = Unicode(help="Description of the value this widget represents", sync=True)
26 26
27 27
28 28 class _BoundedFloatWidget(_FloatWidget):
29 29 max = CFloat(100.0, help="Max value", sync=True)
30 30 min = CFloat(0.0, help="Min value", sync=True)
31 31 step = CFloat(0.1, help="Minimum step that the value can take (ignored by some views)", sync=True)
32 32
33 33 def __init__(self, *pargs, **kwargs):
34 34 """Constructor"""
35 35 DOMWidget.__init__(self, *pargs, **kwargs)
36 36 self.on_trait_change(self._validate, ['value', 'min', 'max'])
37 37
38 38 def _validate(self, name, old, new):
39 39 """Validate value, max, min."""
40 40 if self.min > new or new > self.max:
41 41 self.value = min(max(new, self.min), self.max)
42 42
43 43
44 44 class FloatTextWidget(_FloatWidget):
45 45 _view_name = Unicode('FloatTextView', sync=True)
46 46
47 47
48 48 class BoundedFloatTextWidget(_BoundedFloatWidget):
49 49 _view_name = Unicode('FloatTextView', sync=True)
50 50
51 51
52 52 class FloatSliderWidget(_BoundedFloatWidget):
53 53 _view_name = Unicode('FloatSliderView', sync=True)
54 54 orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
55 55 help="Vertical or horizontal.", sync=True)
56 56 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
57 57
58 58
59 59 class FloatProgressWidget(_BoundedFloatWidget):
60 60 _view_name = Unicode('ProgressView', sync=True)
@@ -1,60 +1,60 b''
1 1 """IntWidget class.
2 2
3 3 Represents an unbounded int using a widget.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from .widget import DOMWidget
17 from IPython.utils.traitlets import Unicode, CInt, Bool, List, Enum
17 from IPython.utils.traitlets import Unicode, CInt, Bool, Enum
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Classes
21 21 #-----------------------------------------------------------------------------
22 22 class _IntWidget(DOMWidget):
23 23 value = CInt(0, help="Int value", sync=True)
24 24 disabled = Bool(False, help="Enable or disable user changes", sync=True)
25 25 description = Unicode(help="Description of the value this widget represents", sync=True)
26 26
27 27
28 28 class _BoundedIntWidget(_IntWidget):
29 29 step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True)
30 30 max = CInt(100, help="Max value", sync=True)
31 31 min = CInt(0, help="Min value", sync=True)
32 32
33 33 def __init__(self, *pargs, **kwargs):
34 34 """Constructor"""
35 35 DOMWidget.__init__(self, *pargs, **kwargs)
36 36 self.on_trait_change(self._validate, ['value', 'min', 'max'])
37 37
38 38 def _validate(self, name, old, new):
39 39 """Validate value, max, min."""
40 40 if self.min > new or new > self.max:
41 41 self.value = min(max(new, self.min), self.max)
42 42
43 43
44 44 class IntTextWidget(_IntWidget):
45 45 _view_name = Unicode('IntTextView', sync=True)
46 46
47 47
48 48 class BoundedIntTextWidget(_BoundedIntWidget):
49 49 _view_name = Unicode('IntTextView', sync=True)
50 50
51 51
52 52 class IntSliderWidget(_BoundedIntWidget):
53 53 _view_name = Unicode('IntSliderView', sync=True)
54 54 orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
55 55 help="Vertical or horizontal.", sync=True)
56 56 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
57 57
58 58
59 59 class IntProgressWidget(_BoundedIntWidget):
60 60 _view_name = Unicode('ProgressView', sync=True)
@@ -1,58 +1,58 b''
1 1 """SelectionContainerWidget class.
2 2
3 3 Represents a multipage container that can be used to group other widgets into
4 4 pages.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (c) 2013, the IPython Development Team.
8 8 #
9 9 # Distributed under the terms of the Modified BSD License.
10 10 #
11 11 # The full license is in the file COPYING.txt, distributed with this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17 from .widget_container import ContainerWidget
18 from IPython.utils.traitlets import Unicode, Dict, CInt, List, Instance
18 from IPython.utils.traitlets import Unicode, Dict, CInt
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Classes
22 22 #-----------------------------------------------------------------------------
23 23 class _SelectionContainerWidget(ContainerWidget):
24 24 _titles = Dict(help="Titles of the pages", sync=True)
25 25 selected_index = CInt(0, sync=True)
26 26
27 27 # Public methods
28 28 def set_title(self, index, title):
29 29 """Sets the title of a container page.
30 30
31 31 Parameters
32 32 ----------
33 33 index : int
34 34 Index of the container page
35 35 title : unicode
36 36 New title"""
37 37 self._titles[index] = title
38 38 self.send_state('_titles')
39 39
40 40 def get_title(self, index):
41 41 """Gets the title of a container pages.
42 42
43 43 Parameters
44 44 ----------
45 45 index : int
46 46 Index of the container page"""
47 47 if index in self._titles:
48 48 return self._titles[index]
49 49 else:
50 50 return None
51 51
52 52
53 53 class AccordionWidget(_SelectionContainerWidget):
54 54 _view_name = Unicode('AccordionView', sync=True)
55 55
56 56
57 57 class TabWidget(_SelectionContainerWidget):
58 58 _view_name = Unicode('TabView', sync=True)
@@ -1,72 +1,72 b''
1 1 """StringWidget class.
2 2
3 3 Represents a unicode string using a widget.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from .widget import DOMWidget, CallbackDispatcher
17 from IPython.utils.traitlets import Unicode, Bool, List
17 from IPython.utils.traitlets import Unicode, Bool
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Classes
21 21 #-----------------------------------------------------------------------------
22 22 class _StringWidget(DOMWidget):
23 23 value = Unicode(help="String value", sync=True)
24 24 disabled = Bool(False, help="Enable or disable user changes", sync=True)
25 25 description = Unicode(help="Description of the value this widget represents", sync=True)
26 26
27 27
28 28 class HTMLWidget(_StringWidget):
29 29 _view_name = Unicode('HTMLView', sync=True)
30 30
31 31
32 32 class LatexWidget(_StringWidget):
33 33 _view_name = Unicode('LatexView', sync=True)
34 34
35 35
36 36 class TextareaWidget(_StringWidget):
37 37 _view_name = Unicode('TextareaView', sync=True)
38 38
39 39 def scroll_to_bottom(self):
40 40 self.send({"method": "scroll_to_bottom"})
41 41
42 42
43 43 class TextWidget(_StringWidget):
44 44 _view_name = Unicode('TextView', sync=True)
45 45
46 46 def __init__(self, **kwargs):
47 47 super(TextWidget, self).__init__(**kwargs)
48 48 self._submission_callbacks = CallbackDispatcher()
49 49 self.on_msg(self._handle_string_msg)
50 50
51 51 def _handle_string_msg(self, _, content):
52 52 """Handle a msg from the front-end.
53 53
54 54 Parameters
55 55 ----------
56 56 content: dict
57 57 Content of the msg."""
58 58 if content.get('event', '') == 'submit':
59 59 self._submission_callbacks(self)
60 60
61 61 def on_submit(self, callback, remove=False):
62 62 """(Un)Register a callback to handle text submission.
63 63
64 64 Triggered when the user clicks enter.
65 65
66 66 Parameters
67 67 ----------
68 68 callback: callable
69 69 Will be called with exactly one argument: the Widget instance
70 70 remove: bool (optional)
71 71 Whether to unregister the callback"""
72 72 self._submission_callbacks.register_callback(callback, remove=remove)
General Comments 0
You need to be logged in to leave comments. Login now