Show More
@@ -1,523 +1,551 b'' | |||||
1 | // Copyright (c) IPython Development Team. |
|
1 | // Copyright (c) IPython Development Team. | |
2 | // Distributed under the terms of the Modified BSD License. |
|
2 | // Distributed under the terms of the Modified BSD License. | |
3 |
|
3 | |||
4 | define([ |
|
4 | define([ | |
5 | "widgets/js/widget", |
|
5 | "widgets/js/widget", | |
6 | "base/js/utils", |
|
6 | "base/js/utils", | |
7 | "jquery", |
|
7 | "jquery", | |
|
8 | "underscore", | |||
8 | "bootstrap", |
|
9 | "bootstrap", | |
9 | ], function(widget, utils, $){ |
|
10 | ], function(widget, utils, $, _){ | |
10 |
|
11 | |||
11 | var DropdownView = widget.DOMWidgetView.extend({ |
|
12 | var DropdownView = widget.DOMWidgetView.extend({ | |
12 | render : function(){ |
|
13 | render : function(){ | |
13 | /** |
|
14 | /** | |
14 | * Called when view is rendered. |
|
15 | * Called when view is rendered. | |
15 | */ |
|
16 | */ | |
16 | this.$el |
|
17 | this.$el | |
17 | .addClass('widget-hbox widget-dropdown'); |
|
18 | .addClass('widget-hbox widget-dropdown'); | |
18 | this.$label = $('<div />') |
|
19 | this.$label = $('<div />') | |
19 | .appendTo(this.$el) |
|
20 | .appendTo(this.$el) | |
20 | .addClass('widget-label') |
|
21 | .addClass('widget-label') | |
21 | .hide(); |
|
22 | .hide(); | |
22 | this.$buttongroup = $('<div />') |
|
23 | this.$buttongroup = $('<div />') | |
23 | .addClass('widget_item') |
|
24 | .addClass('widget_item') | |
24 | .addClass('btn-group') |
|
25 | .addClass('btn-group') | |
25 | .appendTo(this.$el); |
|
26 | .appendTo(this.$el); | |
26 | this.$droplabel = $('<button />') |
|
27 | this.$droplabel = $('<button />') | |
27 | .addClass('btn btn-default') |
|
28 | .addClass('btn btn-default') | |
28 | .addClass('widget-combo-btn') |
|
29 | .addClass('widget-combo-btn') | |
29 | .html(" ") |
|
30 | .html(" ") | |
30 | .appendTo(this.$buttongroup); |
|
31 | .appendTo(this.$buttongroup); | |
31 | this.$dropbutton = $('<button />') |
|
32 | this.$dropbutton = $('<button />') | |
32 | .addClass('btn btn-default') |
|
33 | .addClass('btn btn-default') | |
33 | .addClass('dropdown-toggle') |
|
34 | .addClass('dropdown-toggle') | |
34 | .addClass('widget-combo-carrot-btn') |
|
35 | .addClass('widget-combo-carrot-btn') | |
35 | .attr('data-toggle', 'dropdown') |
|
36 | .attr('data-toggle', 'dropdown') | |
36 | .append($('<span />').addClass("caret")) |
|
37 | .append($('<span />').addClass("caret")) | |
37 | .appendTo(this.$buttongroup); |
|
38 | .appendTo(this.$buttongroup); | |
38 | this.$droplist = $('<ul />') |
|
39 | this.$droplist = $('<ul />') | |
39 | .addClass('dropdown-menu') |
|
40 | .addClass('dropdown-menu') | |
40 | .appendTo(this.$buttongroup); |
|
41 | .appendTo(this.$buttongroup); | |
41 |
|
42 | |||
42 | this.model.on('change:button_style', function(model, value) { |
|
43 | this.model.on('change:button_style', function(model, value) { | |
43 | this.update_button_style(); |
|
44 | this.update_button_style(); | |
44 | }, this); |
|
45 | }, this); | |
45 | this.update_button_style(''); |
|
46 | this.update_button_style(''); | |
46 |
|
47 | |||
47 | // Set defaults. |
|
48 | // Set defaults. | |
48 | this.update(); |
|
49 | this.update(); | |
49 | }, |
|
50 | }, | |
50 |
|
51 | |||
51 | update : function(options){ |
|
52 | update : function(options){ | |
52 | /** |
|
53 | /** | |
53 | * Update the contents of this view |
|
54 | * Update the contents of this view | |
54 | * |
|
55 | * | |
55 |
* Called when the model is changed. The model may have been |
|
56 | * Called when the model is changed. The model may have been | |
56 | * changed by another view or by a state update from the back-end. |
|
57 | * changed by another view or by a state update from the back-end. | |
57 | */ |
|
58 | */ | |
58 |
|
59 | |||
59 | if (options === undefined || options.updated_view != this) { |
|
60 | if (options === undefined || options.updated_view != this) { | |
60 |
var selected_item_text = this.model.get(' |
|
61 | var selected_item_text = this.model.get('selected_label'); | |
61 | if (selected_item_text.trim().length === 0) { |
|
62 | if (selected_item_text.trim().length === 0) { | |
62 | this.$droplabel.html(" "); |
|
63 | this.$droplabel.html(" "); | |
63 | } else { |
|
64 | } else { | |
64 | this.$droplabel.text(selected_item_text); |
|
65 | this.$droplabel.text(selected_item_text); | |
65 | } |
|
66 | } | |
66 |
|
67 | |||
67 |
var items = this.model.get('_ |
|
68 | var items = this.model.get('_options_labels'); | |
68 | var $replace_droplist = $('<ul />') |
|
69 | var $replace_droplist = $('<ul />') | |
69 | .addClass('dropdown-menu'); |
|
70 | .addClass('dropdown-menu'); | |
70 | // Copy the style |
|
71 | // Copy the style | |
71 | $replace_droplist.attr('style', this.$droplist.attr('style')); |
|
72 | $replace_droplist.attr('style', this.$droplist.attr('style')); | |
72 | var that = this; |
|
73 | var that = this; | |
73 | _.each(items, function(item, i) { |
|
74 | _.each(items, function(item, i) { | |
74 | var item_button = $('<a href="#"/>') |
|
75 | var item_button = $('<a href="#"/>') | |
75 | .text(item) |
|
76 | .text(item) | |
76 | .on('click', $.proxy(that.handle_click, that)); |
|
77 | .on('click', $.proxy(that.handle_click, that)); | |
77 | $replace_droplist.append($('<li />').append(item_button)); |
|
78 | $replace_droplist.append($('<li />').append(item_button)); | |
78 | }); |
|
79 | }); | |
79 |
|
80 | |||
80 | this.$droplist.replaceWith($replace_droplist); |
|
81 | this.$droplist.replaceWith($replace_droplist); | |
81 | this.$droplist.remove(); |
|
82 | this.$droplist.remove(); | |
82 | this.$droplist = $replace_droplist; |
|
83 | this.$droplist = $replace_droplist; | |
83 |
|
84 | |||
84 | if (this.model.get('disabled')) { |
|
85 | if (this.model.get('disabled')) { | |
85 | this.$buttongroup.attr('disabled','disabled'); |
|
86 | this.$buttongroup.attr('disabled','disabled'); | |
86 | this.$droplabel.attr('disabled','disabled'); |
|
87 | this.$droplabel.attr('disabled','disabled'); | |
87 | this.$dropbutton.attr('disabled','disabled'); |
|
88 | this.$dropbutton.attr('disabled','disabled'); | |
88 | this.$droplist.attr('disabled','disabled'); |
|
89 | this.$droplist.attr('disabled','disabled'); | |
89 | } else { |
|
90 | } else { | |
90 | this.$buttongroup.removeAttr('disabled'); |
|
91 | this.$buttongroup.removeAttr('disabled'); | |
91 | this.$droplabel.removeAttr('disabled'); |
|
92 | this.$droplabel.removeAttr('disabled'); | |
92 | this.$dropbutton.removeAttr('disabled'); |
|
93 | this.$dropbutton.removeAttr('disabled'); | |
93 | this.$droplist.removeAttr('disabled'); |
|
94 | this.$droplist.removeAttr('disabled'); | |
94 | } |
|
95 | } | |
95 |
|
96 | |||
96 | var description = this.model.get('description'); |
|
97 | var description = this.model.get('description'); | |
97 | if (description.length === 0) { |
|
98 | if (description.length === 0) { | |
98 | this.$label.hide(); |
|
99 | this.$label.hide(); | |
99 | } else { |
|
100 | } else { | |
100 | this.typeset(this.$label, description); |
|
101 | this.typeset(this.$label, description); | |
101 | this.$label.show(); |
|
102 | this.$label.show(); | |
102 | } |
|
103 | } | |
103 | } |
|
104 | } | |
104 | return DropdownView.__super__.update.apply(this); |
|
105 | return DropdownView.__super__.update.apply(this); | |
105 | }, |
|
106 | }, | |
106 |
|
107 | |||
107 | update_button_style: function(previous_trait_value) { |
|
108 | update_button_style: function(previous_trait_value) { | |
108 | var class_map = { |
|
109 | var class_map = { | |
109 | primary: ['btn-primary'], |
|
110 | primary: ['btn-primary'], | |
110 | success: ['btn-success'], |
|
111 | success: ['btn-success'], | |
111 | info: ['btn-info'], |
|
112 | info: ['btn-info'], | |
112 | warning: ['btn-warning'], |
|
113 | warning: ['btn-warning'], | |
113 | danger: ['btn-danger'] |
|
114 | danger: ['btn-danger'] | |
114 | }; |
|
115 | }; | |
115 | this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$droplabel); |
|
116 | this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$droplabel); | |
116 | this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$dropbutton); |
|
117 | this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$dropbutton); | |
117 | }, |
|
118 | }, | |
118 |
|
119 | |||
119 | update_attr: function(name, value) { |
|
120 | update_attr: function(name, value) { | |
120 | /** |
|
121 | /** | |
121 | * Set a css attr of the widget view. |
|
122 | * Set a css attr of the widget view. | |
122 | */ |
|
123 | */ | |
123 | if (name.substring(0, 6) == 'border' || name == 'background' || name == 'color') { |
|
124 | if (name.substring(0, 6) == 'border' || name == 'background' || name == 'color') { | |
124 | this.$droplabel.css(name, value); |
|
125 | this.$droplabel.css(name, value); | |
125 | this.$dropbutton.css(name, value); |
|
126 | this.$dropbutton.css(name, value); | |
126 | this.$droplist.css(name, value); |
|
127 | this.$droplist.css(name, value); | |
127 | } else if (name == 'width') { |
|
128 | } else if (name == 'width') { | |
128 | this.$droplist.css(name, value); |
|
129 | this.$droplist.css(name, value); | |
129 | this.$droplabel.css(name, value); |
|
130 | this.$droplabel.css(name, value); | |
130 | } else if (name == 'padding') { |
|
131 | } else if (name == 'padding') { | |
131 | this.$droplist.css(name, value); |
|
132 | this.$droplist.css(name, value); | |
132 | this.$buttongroup.css(name, value); |
|
133 | this.$buttongroup.css(name, value); | |
133 | } else if (name == 'margin') { |
|
134 | } else if (name == 'margin') { | |
134 | this.$buttongroup.css(name, value); |
|
135 | this.$buttongroup.css(name, value); | |
135 | } else if (name == 'height') { |
|
136 | } else if (name == 'height') { | |
136 | this.$droplabel.css(name, value); |
|
137 | this.$droplabel.css(name, value); | |
137 | this.$dropbutton.css(name, value); |
|
138 | this.$dropbutton.css(name, value); | |
138 | } else if (name == 'padding' || name == 'margin') { |
|
139 | } else if (name == 'padding' || name == 'margin') { | |
139 | this.$el.css(name, value); |
|
140 | this.$el.css(name, value); | |
140 | } else { |
|
141 | } else { | |
141 | this.$droplist.css(name, value); |
|
142 | this.$droplist.css(name, value); | |
142 | this.$droplabel.css(name, value); |
|
143 | this.$droplabel.css(name, value); | |
143 | } |
|
144 | } | |
144 | }, |
|
145 | }, | |
145 |
|
146 | |||
146 | handle_click: function (e) { |
|
147 | handle_click: function (e) { | |
147 | /** |
|
148 | /** | |
148 | * Handle when a value is clicked. |
|
149 | * Handle when a value is clicked. | |
149 | * |
|
150 | * | |
150 | * Calling model.set will trigger all of the other views of the |
|
151 | * Calling model.set will trigger all of the other views of the | |
151 | * model to update. |
|
152 | * model to update. | |
152 | */ |
|
153 | */ | |
153 |
this.model.set(' |
|
154 | this.model.set('selected_label', $(e.target).text(), {updated_view: this}); | |
154 | this.touch(); |
|
155 | this.touch(); | |
155 |
|
156 | |||
156 | // Manually hide the droplist. |
|
157 | // Manually hide the droplist. | |
157 | e.stopPropagation(); |
|
158 | e.stopPropagation(); | |
158 | e.preventDefault(); |
|
159 | e.preventDefault(); | |
159 | this.$buttongroup.removeClass('open'); |
|
160 | this.$buttongroup.removeClass('open'); | |
160 | }, |
|
161 | }, | |
161 |
|
162 | |||
162 | }); |
|
163 | }); | |
163 |
|
164 | |||
164 |
|
165 | |||
165 | var RadioButtonsView = widget.DOMWidgetView.extend({ |
|
166 | var RadioButtonsView = widget.DOMWidgetView.extend({ | |
166 | render : function(){ |
|
167 | render : function(){ | |
167 | /** |
|
168 | /** | |
168 | * Called when view is rendered. |
|
169 | * Called when view is rendered. | |
169 | */ |
|
170 | */ | |
170 | this.$el |
|
171 | this.$el | |
171 | .addClass('widget-hbox widget-radio'); |
|
172 | .addClass('widget-hbox widget-radio'); | |
172 | this.$label = $('<div />') |
|
173 | this.$label = $('<div />') | |
173 | .appendTo(this.$el) |
|
174 | .appendTo(this.$el) | |
174 | .addClass('widget-label') |
|
175 | .addClass('widget-label') | |
175 | .hide(); |
|
176 | .hide(); | |
176 | this.$container = $('<div />') |
|
177 | this.$container = $('<div />') | |
177 | .appendTo(this.$el) |
|
178 | .appendTo(this.$el) | |
178 | .addClass('widget-radio-box'); |
|
179 | .addClass('widget-radio-box'); | |
179 | this.update(); |
|
180 | this.update(); | |
180 | }, |
|
181 | }, | |
181 |
|
182 | |||
182 | update : function(options){ |
|
183 | update : function(options){ | |
183 | /** |
|
184 | /** | |
184 | * Update the contents of this view |
|
185 | * Update the contents of this view | |
185 | * |
|
186 | * | |
186 | * Called when the model is changed. The model may have been |
|
187 | * Called when the model is changed. The model may have been | |
187 | * changed by another view or by a state update from the back-end. |
|
188 | * changed by another view or by a state update from the back-end. | |
188 | */ |
|
189 | */ | |
189 | if (options === undefined || options.updated_view != this) { |
|
190 | if (options === undefined || options.updated_view != this) { | |
190 | // Add missing items to the DOM. |
|
191 | // Add missing items to the DOM. | |
191 |
var items = this.model.get('_ |
|
192 | var items = this.model.get('_options_labels'); | |
192 | var disabled = this.model.get('disabled'); |
|
193 | var disabled = this.model.get('disabled'); | |
193 | var that = this; |
|
194 | var that = this; | |
194 | _.each(items, function(item, index) { |
|
195 | _.each(items, function(item, index) { | |
195 | var item_query = ' :input[data-value="' + encodeURIComponent(item) + '"]'; |
|
196 | var item_query = ' :input[data-value="' + encodeURIComponent(item) + '"]'; | |
196 | if (that.$el.find(item_query).length === 0) { |
|
197 | if (that.$el.find(item_query).length === 0) { | |
197 | var $label = $('<label />') |
|
198 | var $label = $('<label />') | |
198 | .addClass('radio') |
|
199 | .addClass('radio') | |
199 | .text(item) |
|
200 | .text(item) | |
200 | .appendTo(that.$container); |
|
201 | .appendTo(that.$container); | |
201 |
|
202 | |||
202 | $('<input />') |
|
203 | $('<input />') | |
203 | .attr('type', 'radio') |
|
204 | .attr('type', 'radio') | |
204 | .addClass(that.model) |
|
205 | .addClass(that.model) | |
205 | .val(item) |
|
206 | .val(item) | |
206 | .attr('data-value', encodeURIComponent(item)) |
|
207 | .attr('data-value', encodeURIComponent(item)) | |
207 | .prependTo($label) |
|
208 | .prependTo($label) | |
208 | .on('click', $.proxy(that.handle_click, that)); |
|
209 | .on('click', $.proxy(that.handle_click, that)); | |
209 | } |
|
210 | } | |
210 |
|
211 | |||
211 | var $item_element = that.$container.find(item_query); |
|
212 | var $item_element = that.$container.find(item_query); | |
212 |
if (that.model.get(' |
|
213 | if (that.model.get('selected_label') == item) { | |
213 | $item_element.prop('checked', true); |
|
214 | $item_element.prop('checked', true); | |
214 | } else { |
|
215 | } else { | |
215 | $item_element.prop('checked', false); |
|
216 | $item_element.prop('checked', false); | |
216 | } |
|
217 | } | |
217 | $item_element.prop('disabled', disabled); |
|
218 | $item_element.prop('disabled', disabled); | |
218 | }); |
|
219 | }); | |
219 |
|
220 | |||
220 | // Remove items that no longer exist. |
|
221 | // Remove items that no longer exist. | |
221 | this.$container.find('input').each(function(i, obj) { |
|
222 | this.$container.find('input').each(function(i, obj) { | |
222 | var value = $(obj).val(); |
|
223 | var value = $(obj).val(); | |
223 | var found = false; |
|
224 | var found = false; | |
224 | _.each(items, function(item, index) { |
|
225 | _.each(items, function(item, index) { | |
225 | if (item == value) { |
|
226 | if (item == value) { | |
226 | found = true; |
|
227 | found = true; | |
227 | return false; |
|
228 | return false; | |
228 | } |
|
229 | } | |
229 | }); |
|
230 | }); | |
230 |
|
231 | |||
231 | if (!found) { |
|
232 | if (!found) { | |
232 | $(obj).parent().remove(); |
|
233 | $(obj).parent().remove(); | |
233 | } |
|
234 | } | |
234 | }); |
|
235 | }); | |
235 |
|
236 | |||
236 | var description = this.model.get('description'); |
|
237 | var description = this.model.get('description'); | |
237 | if (description.length === 0) { |
|
238 | if (description.length === 0) { | |
238 | this.$label.hide(); |
|
239 | this.$label.hide(); | |
239 | } else { |
|
240 | } else { | |
240 | this.$label.text(description); |
|
241 | this.$label.text(description); | |
241 | this.typeset(this.$label, description); |
|
242 | this.typeset(this.$label, description); | |
242 | this.$label.show(); |
|
243 | this.$label.show(); | |
243 | } |
|
244 | } | |
244 | } |
|
245 | } | |
245 | return RadioButtonsView.__super__.update.apply(this); |
|
246 | return RadioButtonsView.__super__.update.apply(this); | |
246 | }, |
|
247 | }, | |
247 |
|
248 | |||
248 | update_attr: function(name, value) { |
|
249 | update_attr: function(name, value) { | |
249 | /** |
|
250 | /** | |
250 | * Set a css attr of the widget view. |
|
251 | * Set a css attr of the widget view. | |
251 | */ |
|
252 | */ | |
252 | if (name == 'padding' || name == 'margin') { |
|
253 | if (name == 'padding' || name == 'margin') { | |
253 | this.$el.css(name, value); |
|
254 | this.$el.css(name, value); | |
254 | } else { |
|
255 | } else { | |
255 | this.$container.css(name, value); |
|
256 | this.$container.css(name, value); | |
256 | } |
|
257 | } | |
257 | }, |
|
258 | }, | |
258 |
|
259 | |||
259 | handle_click: function (e) { |
|
260 | handle_click: function (e) { | |
260 | /** |
|
261 | /** | |
261 | * Handle when a value is clicked. |
|
262 | * Handle when a value is clicked. | |
262 | * |
|
263 | * | |
263 | * Calling model.set will trigger all of the other views of the |
|
264 | * Calling model.set will trigger all of the other views of the | |
264 | * model to update. |
|
265 | * model to update. | |
265 | */ |
|
266 | */ | |
266 |
this.model.set(' |
|
267 | this.model.set('selected_label', $(e.target).val(), {updated_view: this}); | |
267 | this.touch(); |
|
268 | this.touch(); | |
268 | }, |
|
269 | }, | |
269 | }); |
|
270 | }); | |
270 |
|
271 | |||
271 |
|
272 | |||
272 | var ToggleButtonsView = widget.DOMWidgetView.extend({ |
|
273 | var ToggleButtonsView = widget.DOMWidgetView.extend({ | |
273 | initialize: function() { |
|
274 | initialize: function() { | |
274 | this._css_state = {}; |
|
275 | this._css_state = {}; | |
275 | ToggleButtonsView.__super__.initialize.apply(this, arguments); |
|
276 | ToggleButtonsView.__super__.initialize.apply(this, arguments); | |
276 | }, |
|
277 | }, | |
277 |
|
278 | |||
278 | render: function() { |
|
279 | render: function() { | |
279 | /** |
|
280 | /** | |
280 | * Called when view is rendered. |
|
281 | * Called when view is rendered. | |
281 | */ |
|
282 | */ | |
282 | this.$el |
|
283 | this.$el | |
283 | .addClass('widget-hbox widget-toggle-buttons'); |
|
284 | .addClass('widget-hbox widget-toggle-buttons'); | |
284 | this.$label = $('<div />') |
|
285 | this.$label = $('<div />') | |
285 | .appendTo(this.$el) |
|
286 | .appendTo(this.$el) | |
286 | .addClass('widget-label') |
|
287 | .addClass('widget-label') | |
287 | .hide(); |
|
288 | .hide(); | |
288 | this.$buttongroup = $('<div />') |
|
289 | this.$buttongroup = $('<div />') | |
289 | .addClass('btn-group') |
|
290 | .addClass('btn-group') | |
290 | .appendTo(this.$el); |
|
291 | .appendTo(this.$el); | |
291 |
|
292 | |||
292 | this.model.on('change:button_style', function(model, value) { |
|
293 | this.model.on('change:button_style', function(model, value) { | |
293 | this.update_button_style(); |
|
294 | this.update_button_style(); | |
294 | }, this); |
|
295 | }, this); | |
295 | this.update_button_style(''); |
|
296 | this.update_button_style(''); | |
296 | this.update(); |
|
297 | this.update(); | |
297 | }, |
|
298 | }, | |
298 |
|
299 | |||
299 | update : function(options){ |
|
300 | update : function(options){ | |
300 | /** |
|
301 | /** | |
301 | * Update the contents of this view |
|
302 | * Update the contents of this view | |
302 | * |
|
303 | * | |
303 | * Called when the model is changed. The model may have been |
|
304 | * Called when the model is changed. The model may have been | |
304 | * changed by another view or by a state update from the back-end. |
|
305 | * changed by another view or by a state update from the back-end. | |
305 | */ |
|
306 | */ | |
306 | if (options === undefined || options.updated_view != this) { |
|
307 | if (options === undefined || options.updated_view != this) { | |
307 | // Add missing items to the DOM. |
|
308 | // Add missing items to the DOM. | |
308 |
var items = this.model.get('_ |
|
309 | var items = this.model.get('_options_labels'); | |
309 | var disabled = this.model.get('disabled'); |
|
310 | var disabled = this.model.get('disabled'); | |
310 | var that = this; |
|
311 | var that = this; | |
311 | var item_html; |
|
312 | var item_html; | |
312 | _.each(items, function(item, index) { |
|
313 | _.each(items, function(item, index) { | |
313 | if (item.trim().length === 0) { |
|
314 | if (item.trim().length === 0) { | |
314 | item_html = " "; |
|
315 | item_html = " "; | |
315 | } else { |
|
316 | } else { | |
316 | item_html = utils.escape_html(item); |
|
317 | item_html = utils.escape_html(item); | |
317 | } |
|
318 | } | |
318 | var item_query = '[data-value="' + encodeURIComponent(item) + '"]'; |
|
319 | var item_query = '[data-value="' + encodeURIComponent(item) + '"]'; | |
319 | var $item_element = that.$buttongroup.find(item_query); |
|
320 | var $item_element = that.$buttongroup.find(item_query); | |
320 | if (!$item_element.length) { |
|
321 | if (!$item_element.length) { | |
321 | $item_element = $('<button/>') |
|
322 | $item_element = $('<button/>') | |
322 | .attr('type', 'button') |
|
323 | .attr('type', 'button') | |
323 | .addClass('btn btn-default') |
|
324 | .addClass('btn btn-default') | |
324 | .html(item_html) |
|
325 | .html(item_html) | |
325 | .appendTo(that.$buttongroup) |
|
326 | .appendTo(that.$buttongroup) | |
326 | .attr('data-value', encodeURIComponent(item)) |
|
327 | .attr('data-value', encodeURIComponent(item)) | |
327 | .attr('value', item) |
|
328 | .attr('value', item) | |
328 | .on('click', $.proxy(that.handle_click, that)); |
|
329 | .on('click', $.proxy(that.handle_click, that)); | |
329 | that.update_style_traits($item_element); |
|
330 | that.update_style_traits($item_element); | |
330 | } |
|
331 | } | |
331 |
if (that.model.get(' |
|
332 | if (that.model.get('selected_label') == item) { | |
332 | $item_element.addClass('active'); |
|
333 | $item_element.addClass('active'); | |
333 | } else { |
|
334 | } else { | |
334 | $item_element.removeClass('active'); |
|
335 | $item_element.removeClass('active'); | |
335 | } |
|
336 | } | |
336 | $item_element.prop('disabled', disabled); |
|
337 | $item_element.prop('disabled', disabled); | |
337 | }); |
|
338 | }); | |
338 |
|
339 | |||
339 | // Remove items that no longer exist. |
|
340 | // Remove items that no longer exist. | |
340 | this.$buttongroup.find('button').each(function(i, obj) { |
|
341 | this.$buttongroup.find('button').each(function(i, obj) { | |
341 | var value = $(obj).attr('value'); |
|
342 | var value = $(obj).attr('value'); | |
342 | var found = false; |
|
343 | var found = false; | |
343 | _.each(items, function(item, index) { |
|
344 | _.each(items, function(item, index) { | |
344 | if (item == value) { |
|
345 | if (item == value) { | |
345 | found = true; |
|
346 | found = true; | |
346 | return false; |
|
347 | return false; | |
347 | } |
|
348 | } | |
348 | }); |
|
349 | }); | |
349 |
|
350 | |||
350 | if (!found) { |
|
351 | if (!found) { | |
351 | $(obj).remove(); |
|
352 | $(obj).remove(); | |
352 | } |
|
353 | } | |
353 | }); |
|
354 | }); | |
354 |
|
355 | |||
355 | var description = this.model.get('description'); |
|
356 | var description = this.model.get('description'); | |
356 | if (description.length === 0) { |
|
357 | if (description.length === 0) { | |
357 | this.$label.hide(); |
|
358 | this.$label.hide(); | |
358 | } else { |
|
359 | } else { | |
359 | this.$label.text(); |
|
360 | this.$label.text(); | |
360 | this.typeset(this.$label, description); |
|
361 | this.typeset(this.$label, description); | |
361 | this.$label.show(); |
|
362 | this.$label.show(); | |
362 | } |
|
363 | } | |
363 | } |
|
364 | } | |
364 | return ToggleButtonsView.__super__.update.apply(this); |
|
365 | return ToggleButtonsView.__super__.update.apply(this); | |
365 | }, |
|
366 | }, | |
366 |
|
367 | |||
367 | update_attr: function(name, value) { |
|
368 | update_attr: function(name, value) { | |
368 | /** |
|
369 | /** | |
369 | * Set a css attr of the widget view. |
|
370 | * Set a css attr of the widget view. | |
370 | */ |
|
371 | */ | |
371 | if (name == 'padding' || name == 'margin') { |
|
372 | if (name == 'padding' || name == 'margin') { | |
372 | this.$el.css(name, value); |
|
373 | this.$el.css(name, value); | |
373 | } else { |
|
374 | } else { | |
374 | this._css_state[name] = value; |
|
375 | this._css_state[name] = value; | |
375 | this.update_style_traits(); |
|
376 | this.update_style_traits(); | |
376 | } |
|
377 | } | |
377 | }, |
|
378 | }, | |
378 |
|
379 | |||
379 | update_style_traits: function(button) { |
|
380 | update_style_traits: function(button) { | |
380 | for (var name in this._css_state) { |
|
381 | for (var name in this._css_state) { | |
381 | if (this._css_state.hasOwnProperty(name)) { |
|
382 | if (this._css_state.hasOwnProperty(name)) { | |
382 | if (name == 'margin') { |
|
383 | if (name == 'margin') { | |
383 | this.$buttongroup.css(name, this._css_state[name]); |
|
384 | this.$buttongroup.css(name, this._css_state[name]); | |
384 | } else if (name != 'width') { |
|
385 | } else if (name != 'width') { | |
385 | if (button) { |
|
386 | if (button) { | |
386 | button.css(name, this._css_state[name]); |
|
387 | button.css(name, this._css_state[name]); | |
387 | } else { |
|
388 | } else { | |
388 | this.$buttongroup.find('button').css(name, this._css_state[name]); |
|
389 | this.$buttongroup.find('button').css(name, this._css_state[name]); | |
389 | } |
|
390 | } | |
390 | } |
|
391 | } | |
391 | } |
|
392 | } | |
392 | } |
|
393 | } | |
393 | }, |
|
394 | }, | |
394 |
|
395 | |||
395 | update_button_style: function(previous_trait_value) { |
|
396 | update_button_style: function(previous_trait_value) { | |
396 | var class_map = { |
|
397 | var class_map = { | |
397 | primary: ['btn-primary'], |
|
398 | primary: ['btn-primary'], | |
398 | success: ['btn-success'], |
|
399 | success: ['btn-success'], | |
399 | info: ['btn-info'], |
|
400 | info: ['btn-info'], | |
400 | warning: ['btn-warning'], |
|
401 | warning: ['btn-warning'], | |
401 | danger: ['btn-danger'] |
|
402 | danger: ['btn-danger'] | |
402 | }; |
|
403 | }; | |
403 | this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$buttongroup.find('button')); |
|
404 | this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$buttongroup.find('button')); | |
404 | }, |
|
405 | }, | |
405 |
|
406 | |||
406 | handle_click: function (e) { |
|
407 | handle_click: function (e) { | |
407 | /** |
|
408 | /** | |
408 | * Handle when a value is clicked. |
|
409 | * Handle when a value is clicked. | |
409 | * |
|
410 | * | |
410 | * Calling model.set will trigger all of the other views of the |
|
411 | * Calling model.set will trigger all of the other views of the | |
411 | * model to update. |
|
412 | * model to update. | |
412 | */ |
|
413 | */ | |
413 |
this.model.set(' |
|
414 | this.model.set('selected_label', $(e.target).attr('value'), {updated_view: this}); | |
414 | this.touch(); |
|
415 | this.touch(); | |
415 | }, |
|
416 | }, | |
416 | }); |
|
417 | }); | |
417 |
|
418 | |||
418 |
|
419 | |||
419 | var SelectView = widget.DOMWidgetView.extend({ |
|
420 | var SelectView = widget.DOMWidgetView.extend({ | |
420 | render : function(){ |
|
421 | render : function(){ | |
421 | /** |
|
422 | /** | |
422 | * Called when view is rendered. |
|
423 | * Called when view is rendered. | |
423 | */ |
|
424 | */ | |
424 | this.$el |
|
425 | this.$el | |
425 | .addClass('widget-hbox widget-select'); |
|
426 | .addClass('widget-hbox widget-select'); | |
426 | this.$label = $('<div />') |
|
427 | this.$label = $('<div />') | |
427 | .appendTo(this.$el) |
|
428 | .appendTo(this.$el) | |
428 | .addClass('widget-label') |
|
429 | .addClass('widget-label') | |
429 | .hide(); |
|
430 | .hide(); | |
430 | this.$listbox = $('<select />') |
|
431 | this.$listbox = $('<select />') | |
431 | .addClass('widget-listbox form-control') |
|
432 | .addClass('widget-listbox form-control') | |
432 | .attr('size', 6) |
|
433 | .attr('size', 6) | |
433 | .appendTo(this.$el); |
|
434 | .appendTo(this.$el); | |
434 | this.update(); |
|
435 | this.update(); | |
435 | }, |
|
436 | }, | |
436 |
|
437 | |||
437 | update : function(options){ |
|
438 | update : function(options){ | |
438 | /** |
|
439 | /** | |
439 | * Update the contents of this view |
|
440 | * Update the contents of this view | |
440 | * |
|
441 | * | |
441 | * Called when the model is changed. The model may have been |
|
442 | * Called when the model is changed. The model may have been | |
442 | * changed by another view or by a state update from the back-end. |
|
443 | * changed by another view or by a state update from the back-end. | |
443 | */ |
|
444 | */ | |
444 | if (options === undefined || options.updated_view != this) { |
|
445 | if (options === undefined || options.updated_view != this) { | |
445 | // Add missing items to the DOM. |
|
446 | // Add missing items to the DOM. | |
446 |
var items = this.model.get('_ |
|
447 | var items = this.model.get('_options_labels'); | |
447 | var that = this; |
|
448 | var that = this; | |
448 | _.each(items, function(item, index) { |
|
449 | _.each(items, function(item, index) { | |
449 | var item_query = 'option[data-value="' + encodeURIComponent(item) + '"]'; |
|
450 | var item_query = 'option[data-value="' + encodeURIComponent(item) + '"]'; | |
450 | if (that.$listbox.find(item_query).length === 0) { |
|
451 | if (that.$listbox.find(item_query).length === 0) { | |
451 | $('<option />') |
|
452 | $('<option />') | |
452 | .text(item) |
|
453 | .text(item) | |
453 | .attr('data-value', encodeURIComponent(item)) |
|
454 | .attr('data-value', encodeURIComponent(item)) | |
454 |
.attr(' |
|
455 | .attr('selected_label', item) | |
455 | .appendTo(that.$listbox) |
|
456 | .appendTo(that.$listbox) | |
456 | .on('click', $.proxy(that.handle_click, that)); |
|
457 | .on('click', $.proxy(that.handle_click, that)); | |
457 | } |
|
458 | } | |
458 | }); |
|
459 | }); | |
459 |
|
460 | |||
460 | // Select the correct element |
|
461 | // Select the correct element | |
461 |
this.$listbox.val(this.model.get(' |
|
462 | this.$listbox.val(this.model.get('selected_label')); | |
462 |
|
463 | |||
463 | // Disable listbox if needed |
|
464 | // Disable listbox if needed | |
464 | var disabled = this.model.get('disabled'); |
|
465 | var disabled = this.model.get('disabled'); | |
465 | this.$listbox.prop('disabled', disabled); |
|
466 | this.$listbox.prop('disabled', disabled); | |
466 |
|
467 | |||
467 | // Remove items that no longer exist. |
|
468 | // Remove items that no longer exist. | |
468 | this.$listbox.find('option').each(function(i, obj) { |
|
469 | this.$listbox.find('option').each(function(i, obj) { | |
469 | var value = $(obj).text(); |
|
470 | var value = $(obj).text(); | |
470 | var found = false; |
|
471 | var found = false; | |
471 | _.each(items, function(item, index) { |
|
472 | _.each(items, function(item, index) { | |
472 | if (item == value) { |
|
473 | if (item == value) { | |
473 | found = true; |
|
474 | found = true; | |
474 | return false; |
|
475 | return false; | |
475 | } |
|
476 | } | |
476 | }); |
|
477 | }); | |
477 |
|
478 | |||
478 | if (!found) { |
|
479 | if (!found) { | |
479 | $(obj).remove(); |
|
480 | $(obj).remove(); | |
480 | } |
|
481 | } | |
481 | }); |
|
482 | }); | |
482 |
|
483 | |||
483 | var description = this.model.get('description'); |
|
484 | var description = this.model.get('description'); | |
484 | if (description.length === 0) { |
|
485 | if (description.length === 0) { | |
485 | this.$label.hide(); |
|
486 | this.$label.hide(); | |
486 | } else { |
|
487 | } else { | |
487 | this.typeset(this.$label, description); |
|
488 | this.typeset(this.$label, description); | |
488 | this.$label.show(); |
|
489 | this.$label.show(); | |
489 | } |
|
490 | } | |
490 | } |
|
491 | } | |
491 | return SelectView.__super__.update.apply(this); |
|
492 | return SelectView.__super__.update.apply(this); | |
492 | }, |
|
493 | }, | |
493 |
|
494 | |||
494 | update_attr: function(name, value) { |
|
495 | update_attr: function(name, value) { | |
495 | /** |
|
496 | /** | |
496 | * Set a css attr of the widget view. |
|
497 | * Set a css attr of the widget view. | |
497 | */ |
|
498 | */ | |
498 | if (name == 'padding' || name == 'margin') { |
|
499 | if (name == 'padding' || name == 'margin') { | |
499 | this.$el.css(name, value); |
|
500 | this.$el.css(name, value); | |
500 | } else { |
|
501 | } else { | |
501 | this.$listbox.css(name, value); |
|
502 | this.$listbox.css(name, value); | |
502 | } |
|
503 | } | |
503 | }, |
|
504 | }, | |
504 |
|
505 | |||
505 | handle_click: function (e) { |
|
506 | handle_click: function (e) { | |
506 | /** |
|
507 | /** | |
507 | * Handle when a value is clicked. |
|
508 | * Handle when a value is clicked. | |
508 | * |
|
509 | * | |
509 | * Calling model.set will trigger all of the other views of the |
|
510 | * Calling model.set will trigger all of the other views of the | |
510 | * model to update. |
|
511 | * model to update. | |
511 | */ |
|
512 | */ | |
512 |
this.model.set(' |
|
513 | this.model.set('selected_label', $(e.target).text(), {updated_view: this}); | |
513 | this.touch(); |
|
514 | this.touch(); | |
514 |
}, |
|
515 | }, | |
|
516 | }); | |||
|
517 | var SelectMultipleView = SelectView.extend({ | |||
|
518 | render: function(){ | |||
|
519 | SelectMultipleView.__super__.render.apply(this); | |||
|
520 | this.$el.removeClass('widget-select') | |||
|
521 | .addClass('widget-select-multiple'); | |||
|
522 | this.$listbox.attr('multiple', true) | |||
|
523 | .on('input', $.proxy(this.handle_click, this)); | |||
|
524 | return this; | |||
|
525 | }, | |||
|
526 | ||||
|
527 | update: function(){ | |||
|
528 | SelectMultipleView.__super__.update.apply(this, arguments); | |||
|
529 | this.$listbox.val(this.model.get('selected_labels')); | |||
|
530 | }, | |||
|
531 | ||||
|
532 | handle_click: function (e) { | |||
|
533 | // Handle when a value is clicked. | |||
|
534 | ||||
|
535 | // Calling model.set will trigger all of the other views of the | |||
|
536 | // model to update. | |||
|
537 | this.model.set('selected_labels', | |||
|
538 | (this.$listbox.val() || []).slice(), | |||
|
539 | {updated_view: this}); | |||
|
540 | this.touch(); | |||
|
541 | }, | |||
515 | }); |
|
542 | }); | |
516 |
|
543 | |||
517 | return { |
|
544 | return { | |
518 | 'DropdownView': DropdownView, |
|
545 | 'DropdownView': DropdownView, | |
519 | 'RadioButtonsView': RadioButtonsView, |
|
546 | 'RadioButtonsView': RadioButtonsView, | |
520 | 'ToggleButtonsView': ToggleButtonsView, |
|
547 | 'ToggleButtonsView': ToggleButtonsView, | |
521 | 'SelectView': SelectView, |
|
548 | 'SelectView': SelectView, | |
|
549 | 'SelectMultipleView': SelectMultipleView, | |||
522 | }; |
|
550 | }; | |
523 | }); |
|
551 | }); |
@@ -1,148 +1,148 b'' | |||||
1 | // Test selection class |
|
1 | // Test selection class | |
2 | casper.notebook_test(function () { |
|
2 | casper.notebook_test(function () { | |
3 | index = this.append_cell( |
|
3 | index = this.append_cell( | |
4 | 'from IPython.html import widgets\n' + |
|
4 | 'from IPython.html import widgets\n' + | |
5 | 'from IPython.display import display, clear_output\n' + |
|
5 | 'from IPython.display import display, clear_output\n' + | |
6 | 'print("Success")'); |
|
6 | 'print("Success")'); | |
7 | this.execute_cell_then(index); |
|
7 | this.execute_cell_then(index); | |
8 |
|
8 | |||
9 | var combo_selector = '.widget-area .widget-subarea .widget-hbox .btn-group .widget-combo-btn'; |
|
9 | var combo_selector = '.widget-area .widget-subarea .widget-hbox .btn-group .widget-combo-btn'; | |
10 | var multibtn_selector = '.widget-area .widget-subarea .widget-hbox.widget-toggle-buttons .btn-group'; |
|
10 | var multibtn_selector = '.widget-area .widget-subarea .widget-hbox.widget-toggle-buttons .btn-group'; | |
11 | var radio_selector = '.widget-area .widget-subarea .widget-hbox .widget-radio-box'; |
|
11 | var radio_selector = '.widget-area .widget-subarea .widget-hbox .widget-radio-box'; | |
12 | var list_selector = '.widget-area .widget-subarea .widget-hbox .widget-listbox'; |
|
12 | var list_selector = '.widget-area .widget-subarea .widget-hbox .widget-listbox'; | |
13 |
|
13 | |||
14 | var selection_index; |
|
14 | var selection_index; | |
15 | var selection_values = 'abcd'; |
|
15 | var selection_values = 'abcd'; | |
16 | var check_state = function(context, index, state){ |
|
16 | var check_state = function(context, index, state){ | |
17 | if (0 <= index && index < selection_values.length) { |
|
17 | if (0 <= index && index < selection_values.length) { | |
18 | var multibtn_state = context.cell_element_function(selection_index, multibtn_selector + ' .btn:nth-child(' + (index + 1) + ')', 'hasClass', ['active']); |
|
18 | var multibtn_state = context.cell_element_function(selection_index, multibtn_selector + ' .btn:nth-child(' + (index + 1) + ')', 'hasClass', ['active']); | |
19 | var radio_state = context.cell_element_function(selection_index, radio_selector + ' .radio:nth-child(' + (index + 1) + ') input', 'prop', ['checked']); |
|
19 | var radio_state = context.cell_element_function(selection_index, radio_selector + ' .radio:nth-child(' + (index + 1) + ') input', 'prop', ['checked']); | |
20 | var list_val = context.cell_element_function(selection_index, list_selector, 'val'); |
|
20 | var list_val = context.cell_element_function(selection_index, list_selector, 'val'); | |
21 | var combo_val = context.cell_element_function(selection_index, combo_selector, 'html'); |
|
21 | var combo_val = context.cell_element_function(selection_index, combo_selector, 'html'); | |
22 |
|
22 | |||
23 | var val = selection_values.charAt(index); |
|
23 | var val = selection_values.charAt(index); | |
24 | var list_state = (val == list_val); |
|
24 | var list_state = (val == list_val); | |
25 | var combo_state = (val == combo_val); |
|
25 | var combo_state = (val == combo_val); | |
26 |
|
26 | |||
27 | return multibtn_state == state && |
|
27 | return multibtn_state == state && | |
28 | radio_state == state && |
|
28 | radio_state == state && | |
29 | list_state == state && |
|
29 | list_state == state && | |
30 | combo_state == state; |
|
30 | combo_state == state; | |
31 | } |
|
31 | } | |
32 | return true; |
|
32 | return true; | |
33 | }; |
|
33 | }; | |
34 |
|
34 | |||
35 | var verify_selection = function(context, index){ |
|
35 | var verify_selection = function(context, index){ | |
36 | for (var i = 0; i < selection_values.length; i++) { |
|
36 | for (var i = 0; i < selection_values.length; i++) { | |
37 | if (!check_state(context, i, i==index)) { |
|
37 | if (!check_state(context, i, i==index)) { | |
38 | return false; |
|
38 | return false; | |
39 | } |
|
39 | } | |
40 | } |
|
40 | } | |
41 | return true; |
|
41 | return true; | |
42 | }; |
|
42 | }; | |
43 |
|
43 | |||
44 | //values=["' + selection_values + '"[i] for i in range(4)] |
|
44 | //values=["' + selection_values + '"[i] for i in range(4)] | |
45 | selection_index = this.append_cell( |
|
45 | selection_index = this.append_cell( | |
46 |
' |
|
46 | 'options=["' + selection_values + '"[i] for i in range(4)]\n' + | |
47 |
'selection = [widgets.Dropdown( |
|
47 | 'selection = [widgets.Dropdown(options=options),\n' + | |
48 |
' widgets.ToggleButtons( |
|
48 | ' widgets.ToggleButtons(options=options),\n' + | |
49 |
' widgets.RadioButtons( |
|
49 | ' widgets.RadioButtons(options=options),\n' + | |
50 |
' widgets.Select( |
|
50 | ' widgets.Select(options=options)]\n' + | |
51 | '[display(selection[i]) for i in range(4)]\n' + |
|
51 | '[display(selection[i]) for i in range(4)]\n' + | |
52 | 'for widget in selection:\n' + |
|
52 | 'for widget in selection:\n' + | |
53 | ' def handle_change(name,old,new):\n' + |
|
53 | ' def handle_change(name,old,new):\n' + | |
54 | ' for other_widget in selection:\n' + |
|
54 | ' for other_widget in selection:\n' + | |
55 | ' other_widget.value = new\n' + |
|
55 | ' other_widget.value = new\n' + | |
56 | ' widget.on_trait_change(handle_change, "value")\n' + |
|
56 | ' widget.on_trait_change(handle_change, "value")\n' + | |
57 | 'print("Success")\n'); |
|
57 | 'print("Success")\n'); | |
58 | this.execute_cell_then(selection_index, function(index){ |
|
58 | this.execute_cell_then(selection_index, function(index){ | |
59 | this.test.assertEquals(this.get_output_cell(index).text, 'Success\n', |
|
59 | this.test.assertEquals(this.get_output_cell(index).text, 'Success\n', | |
60 | 'Create selection cell executed with correct output.'); |
|
60 | 'Create selection cell executed with correct output.'); | |
61 | }); |
|
61 | }); | |
62 |
|
62 | |||
63 | // Wait for the widgets to actually display. |
|
63 | // Wait for the widgets to actually display. | |
64 | this.wait_for_element(selection_index, combo_selector); |
|
64 | this.wait_for_element(selection_index, combo_selector); | |
65 | this.wait_for_element(selection_index, multibtn_selector); |
|
65 | this.wait_for_element(selection_index, multibtn_selector); | |
66 | this.wait_for_element(selection_index, radio_selector); |
|
66 | this.wait_for_element(selection_index, radio_selector); | |
67 | this.wait_for_element(selection_index, list_selector); |
|
67 | this.wait_for_element(selection_index, list_selector); | |
68 |
|
68 | |||
69 | // Continue with the tests. |
|
69 | // Continue with the tests. | |
70 | this.then(function() { |
|
70 | this.then(function() { | |
71 | this.test.assert(this.cell_element_exists(selection_index, |
|
71 | this.test.assert(this.cell_element_exists(selection_index, | |
72 | '.widget-area .widget-subarea'), |
|
72 | '.widget-area .widget-subarea'), | |
73 | 'Widget subarea exists.'); |
|
73 | 'Widget subarea exists.'); | |
74 |
|
74 | |||
75 | this.test.assert(this.cell_element_exists(selection_index, combo_selector), |
|
75 | this.test.assert(this.cell_element_exists(selection_index, combo_selector), | |
76 | 'Widget combobox exists.'); |
|
76 | 'Widget combobox exists.'); | |
77 |
|
77 | |||
78 | this.test.assert(this.cell_element_exists(selection_index, multibtn_selector), |
|
78 | this.test.assert(this.cell_element_exists(selection_index, multibtn_selector), | |
79 | 'Widget multibutton exists.'); |
|
79 | 'Widget multibutton exists.'); | |
80 |
|
80 | |||
81 | this.test.assert(this.cell_element_exists(selection_index, radio_selector), |
|
81 | this.test.assert(this.cell_element_exists(selection_index, radio_selector), | |
82 | 'Widget radio buttons exists.'); |
|
82 | 'Widget radio buttons exists.'); | |
83 |
|
83 | |||
84 | this.test.assert(this.cell_element_exists(selection_index, list_selector), |
|
84 | this.test.assert(this.cell_element_exists(selection_index, list_selector), | |
85 | 'Widget list exists.'); |
|
85 | 'Widget list exists.'); | |
86 |
|
86 | |||
87 | // Verify that no items are selected. |
|
87 | // Verify that no items are selected. | |
88 | this.test.assert(verify_selection(this, 0), 'Default first item selected.'); |
|
88 | this.test.assert(verify_selection(this, 0), 'Default first item selected.'); | |
89 | }); |
|
89 | }); | |
90 |
|
90 | |||
91 | index = this.append_cell( |
|
91 | index = this.append_cell( | |
92 | 'for widget in selection:\n' + |
|
92 | 'for widget in selection:\n' + | |
93 | ' widget.value = "a"\n' + |
|
93 | ' widget.value = "a"\n' + | |
94 | 'print("Success")\n'); |
|
94 | 'print("Success")\n'); | |
95 | this.execute_cell_then(index, function(index){ |
|
95 | this.execute_cell_then(index, function(index){ | |
96 | this.test.assertEquals(this.get_output_cell(index).text, 'Success\n', |
|
96 | this.test.assertEquals(this.get_output_cell(index).text, 'Success\n', | |
97 | 'Python select item executed with correct output.'); |
|
97 | 'Python select item executed with correct output.'); | |
98 |
|
98 | |||
99 | // Verify that the first item is selected. |
|
99 | // Verify that the first item is selected. | |
100 | this.test.assert(verify_selection(this, 0), 'Python selected'); |
|
100 | this.test.assert(verify_selection(this, 0), 'Python selected'); | |
101 |
|
101 | |||
102 | // Verify that selecting a radio button updates all of the others. |
|
102 | // Verify that selecting a radio button updates all of the others. | |
103 | this.cell_element_function(selection_index, radio_selector + ' .radio:nth-child(2) input', 'click'); |
|
103 | this.cell_element_function(selection_index, radio_selector + ' .radio:nth-child(2) input', 'click'); | |
104 | }); |
|
104 | }); | |
105 | this.wait_for_idle(); |
|
105 | this.wait_for_idle(); | |
106 | this.then(function () { |
|
106 | this.then(function () { | |
107 | this.test.assert(verify_selection(this, 1), 'Radio button selection updated view states correctly.'); |
|
107 | this.test.assert(verify_selection(this, 1), 'Radio button selection updated view states correctly.'); | |
108 |
|
108 | |||
109 | // Verify that selecting a list option updates all of the others. |
|
109 | // Verify that selecting a list option updates all of the others. | |
110 | this.cell_element_function(selection_index, list_selector + ' option:nth-child(3)', 'click'); |
|
110 | this.cell_element_function(selection_index, list_selector + ' option:nth-child(3)', 'click'); | |
111 | }); |
|
111 | }); | |
112 | this.wait_for_idle(); |
|
112 | this.wait_for_idle(); | |
113 | this.then(function () { |
|
113 | this.then(function () { | |
114 | this.test.assert(verify_selection(this, 2), 'List selection updated view states correctly.'); |
|
114 | this.test.assert(verify_selection(this, 2), 'List selection updated view states correctly.'); | |
115 |
|
115 | |||
116 | // Verify that selecting a multibutton option updates all of the others. |
|
116 | // Verify that selecting a multibutton option updates all of the others. | |
117 | // Bootstrap3 has changed the toggle button group behavior. Two clicks |
|
117 | // Bootstrap3 has changed the toggle button group behavior. Two clicks | |
118 | // are required to actually select an item. |
|
118 | // are required to actually select an item. | |
119 | this.cell_element_function(selection_index, multibtn_selector + ' .btn:nth-child(4)', 'click'); |
|
119 | this.cell_element_function(selection_index, multibtn_selector + ' .btn:nth-child(4)', 'click'); | |
120 | this.cell_element_function(selection_index, multibtn_selector + ' .btn:nth-child(4)', 'click'); |
|
120 | this.cell_element_function(selection_index, multibtn_selector + ' .btn:nth-child(4)', 'click'); | |
121 | }); |
|
121 | }); | |
122 | this.wait_for_idle(); |
|
122 | this.wait_for_idle(); | |
123 | this.then(function () { |
|
123 | this.then(function () { | |
124 | this.test.assert(verify_selection(this, 3), 'Multibutton selection updated view states correctly.'); |
|
124 | this.test.assert(verify_selection(this, 3), 'Multibutton selection updated view states correctly.'); | |
125 |
|
125 | |||
126 | // Verify that selecting a combobox option updates all of the others. |
|
126 | // Verify that selecting a combobox option updates all of the others. | |
127 | this.cell_element_function(selection_index, '.widget-area .widget-subarea .widget-hbox .btn-group ul.dropdown-menu li:nth-child(3) a', 'click'); |
|
127 | this.cell_element_function(selection_index, '.widget-area .widget-subarea .widget-hbox .btn-group ul.dropdown-menu li:nth-child(3) a', 'click'); | |
128 | }); |
|
128 | }); | |
129 | this.wait_for_idle(); |
|
129 | this.wait_for_idle(); | |
130 | this.then(function () { |
|
130 | this.then(function () { | |
131 | this.test.assert(verify_selection(this, 2), 'Combobox selection updated view states correctly.'); |
|
131 | this.test.assert(verify_selection(this, 2), 'Combobox selection updated view states correctly.'); | |
132 | }); |
|
132 | }); | |
133 |
|
133 | |||
134 | this.wait_for_idle(); |
|
134 | this.wait_for_idle(); | |
135 |
|
135 | |||
136 | index = this.append_cell( |
|
136 | index = this.append_cell( | |
137 | 'from copy import copy\n' + |
|
137 | 'from copy import copy\n' + | |
138 | 'for widget in selection:\n' + |
|
138 | 'for widget in selection:\n' + | |
139 |
' d = copy(widget. |
|
139 | ' d = copy(widget.options)\n' + | |
140 | ' d.append("z")\n' + |
|
140 | ' d.append("z")\n' + | |
141 |
' widget. |
|
141 | ' widget.options = d\n' + | |
142 | 'selection[0].value = "z"'); |
|
142 | 'selection[0].value = "z"'); | |
143 | this.execute_cell_then(index, function(index){ |
|
143 | this.execute_cell_then(index, function(index){ | |
144 |
|
144 | |||
145 | // Verify that selecting a combobox option updates all of the others. |
|
145 | // Verify that selecting a combobox option updates all of the others. | |
146 | this.test.assert(verify_selection(this, 4), 'Item added to selection widget.'); |
|
146 | this.test.assert(verify_selection(this, 4), 'Item added to selection widget.'); | |
147 | }); |
|
147 | }); | |
148 | }); No newline at end of file |
|
148 | }); |
@@ -1,38 +1,38 b'' | |||||
1 | from .widget import Widget, DOMWidget, CallbackDispatcher, register |
|
1 | from .widget import Widget, DOMWidget, CallbackDispatcher, register | |
2 |
|
2 | |||
3 | from .widget_bool import Checkbox, ToggleButton |
|
3 | from .widget_bool import Checkbox, ToggleButton | |
4 | from .widget_button import Button |
|
4 | from .widget_button import Button | |
5 | from .widget_box import Box, FlexBox, HBox, VBox |
|
5 | from .widget_box import Box, FlexBox, HBox, VBox | |
6 | from .widget_float import FloatText, BoundedFloatText, FloatSlider, FloatProgress, FloatRangeSlider |
|
6 | from .widget_float import FloatText, BoundedFloatText, FloatSlider, FloatProgress, FloatRangeSlider | |
7 | from .widget_image import Image |
|
7 | from .widget_image import Image | |
8 | from .widget_int import IntText, BoundedIntText, IntSlider, IntProgress, IntRangeSlider |
|
8 | from .widget_int import IntText, BoundedIntText, IntSlider, IntProgress, IntRangeSlider | |
9 | from .widget_output import Output |
|
9 | from .widget_output import Output | |
10 | from .widget_selection import RadioButtons, ToggleButtons, Dropdown, Select |
|
10 | from .widget_selection import RadioButtons, ToggleButtons, Dropdown, Select, SelectMultiple | |
11 | from .widget_selectioncontainer import Tab, Accordion |
|
11 | from .widget_selectioncontainer import Tab, Accordion | |
12 | from .widget_string import HTML, Latex, Text, Textarea |
|
12 | from .widget_string import HTML, Latex, Text, Textarea | |
13 | from .interaction import interact, interactive, fixed, interact_manual |
|
13 | from .interaction import interact, interactive, fixed, interact_manual | |
14 | from .widget_link import jslink, jsdlink |
|
14 | from .widget_link import jslink, jsdlink | |
15 |
|
15 | |||
16 | # Deprecated classes |
|
16 | # Deprecated classes | |
17 | from .widget_bool import CheckboxWidget, ToggleButtonWidget |
|
17 | from .widget_bool import CheckboxWidget, ToggleButtonWidget | |
18 | from .widget_button import ButtonWidget |
|
18 | from .widget_button import ButtonWidget | |
19 | from .widget_box import ContainerWidget |
|
19 | from .widget_box import ContainerWidget | |
20 | from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget |
|
20 | from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget | |
21 | from .widget_image import ImageWidget |
|
21 | from .widget_image import ImageWidget | |
22 | from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget |
|
22 | from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget | |
23 | from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget |
|
23 | from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget | |
24 | from .widget_selectioncontainer import TabWidget, AccordionWidget |
|
24 | from .widget_selectioncontainer import TabWidget, AccordionWidget | |
25 | from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget |
|
25 | from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget | |
26 |
|
26 | |||
27 | # We use warn_explicit so we have very brief messages without file or line numbers. |
|
27 | # We use warn_explicit so we have very brief messages without file or line numbers. | |
28 | # The concern is that file or line numbers will confuse the interactive user. |
|
28 | # The concern is that file or line numbers will confuse the interactive user. | |
29 | # To ignore this warning, do: |
|
29 | # To ignore this warning, do: | |
30 | # |
|
30 | # | |
31 | # from warnings import filterwarnings |
|
31 | # from warnings import filterwarnings | |
32 | # filterwarnings('ignore', module='IPython.html.widgets') |
|
32 | # filterwarnings('ignore', module='IPython.html.widgets') | |
33 |
|
33 | |||
34 | from warnings import warn_explicit |
|
34 | from warnings import warn_explicit | |
35 | __warningregistry__ = {} |
|
35 | __warningregistry__ = {} | |
36 | warn_explicit("IPython widgets are experimental and may change in the future.", |
|
36 | warn_explicit("IPython widgets are experimental and may change in the future.", | |
37 | FutureWarning, '', 0, module = 'IPython.html.widgets', |
|
37 | FutureWarning, '', 0, module = 'IPython.html.widgets', | |
38 | registry = __warningregistry__, module_globals = globals) |
|
38 | registry = __warningregistry__, module_globals = globals) |
@@ -1,349 +1,349 b'' | |||||
1 | """Interact with functions using widgets.""" |
|
1 | """Interact with functions using widgets.""" | |
2 |
|
2 | |||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 | from __future__ import print_function |
|
6 | from __future__ import print_function | |
7 |
|
7 | |||
8 | try: # Python >= 3.3 |
|
8 | try: # Python >= 3.3 | |
9 | from inspect import signature, Parameter |
|
9 | from inspect import signature, Parameter | |
10 | except ImportError: |
|
10 | except ImportError: | |
11 | from IPython.utils.signatures import signature, Parameter |
|
11 | from IPython.utils.signatures import signature, Parameter | |
12 | from inspect import getcallargs |
|
12 | from inspect import getcallargs | |
13 |
|
13 | |||
14 | from IPython.core.getipython import get_ipython |
|
14 | from IPython.core.getipython import get_ipython | |
15 | from IPython.html.widgets import (Widget, Text, |
|
15 | from IPython.html.widgets import (Widget, Text, | |
16 | FloatSlider, IntSlider, Checkbox, Dropdown, |
|
16 | FloatSlider, IntSlider, Checkbox, Dropdown, | |
17 | Box, Button, DOMWidget, Output) |
|
17 | Box, Button, DOMWidget, Output) | |
18 | from IPython.display import display, clear_output |
|
18 | from IPython.display import display, clear_output | |
19 | from IPython.utils.py3compat import string_types, unicode_type |
|
19 | from IPython.utils.py3compat import string_types, unicode_type | |
20 | from IPython.utils.traitlets import HasTraits, Any, Unicode |
|
20 | from IPython.utils.traitlets import HasTraits, Any, Unicode | |
21 |
|
21 | |||
22 | empty = Parameter.empty |
|
22 | empty = Parameter.empty | |
23 |
|
23 | |||
24 |
|
24 | |||
25 | def _matches(o, pattern): |
|
25 | def _matches(o, pattern): | |
26 | """Match a pattern of types in a sequence.""" |
|
26 | """Match a pattern of types in a sequence.""" | |
27 | if not len(o) == len(pattern): |
|
27 | if not len(o) == len(pattern): | |
28 | return False |
|
28 | return False | |
29 | comps = zip(o,pattern) |
|
29 | comps = zip(o,pattern) | |
30 | return all(isinstance(obj,kind) for obj,kind in comps) |
|
30 | return all(isinstance(obj,kind) for obj,kind in comps) | |
31 |
|
31 | |||
32 |
|
32 | |||
33 | def _get_min_max_value(min, max, value=None, step=None): |
|
33 | def _get_min_max_value(min, max, value=None, step=None): | |
34 | """Return min, max, value given input values with possible None.""" |
|
34 | """Return min, max, value given input values with possible None.""" | |
35 | if value is None: |
|
35 | if value is None: | |
36 | if not max > min: |
|
36 | if not max > min: | |
37 | raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max)) |
|
37 | raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max)) | |
38 | value = min + abs(min-max)/2 |
|
38 | value = min + abs(min-max)/2 | |
39 | value = type(min)(value) |
|
39 | value = type(min)(value) | |
40 | elif min is None and max is None: |
|
40 | elif min is None and max is None: | |
41 | if value == 0.0: |
|
41 | if value == 0.0: | |
42 | min, max, value = 0.0, 1.0, 0.5 |
|
42 | min, max, value = 0.0, 1.0, 0.5 | |
43 | elif value == 0: |
|
43 | elif value == 0: | |
44 | min, max, value = 0, 1, 0 |
|
44 | min, max, value = 0, 1, 0 | |
45 | elif isinstance(value, (int, float)): |
|
45 | elif isinstance(value, (int, float)): | |
46 | min, max = (-value, 3*value) if value > 0 else (3*value, -value) |
|
46 | min, max = (-value, 3*value) if value > 0 else (3*value, -value) | |
47 | else: |
|
47 | else: | |
48 | raise TypeError('expected a number, got: %r' % value) |
|
48 | raise TypeError('expected a number, got: %r' % value) | |
49 | else: |
|
49 | else: | |
50 | raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value)) |
|
50 | raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value)) | |
51 | if step is not None: |
|
51 | if step is not None: | |
52 | # ensure value is on a step |
|
52 | # ensure value is on a step | |
53 | r = (value - min) % step |
|
53 | r = (value - min) % step | |
54 | value = value - r |
|
54 | value = value - r | |
55 | return min, max, value |
|
55 | return min, max, value | |
56 |
|
56 | |||
57 | def _widget_abbrev_single_value(o): |
|
57 | def _widget_abbrev_single_value(o): | |
58 | """Make widgets from single values, which can be used as parameter defaults.""" |
|
58 | """Make widgets from single values, which can be used as parameter defaults.""" | |
59 | if isinstance(o, string_types): |
|
59 | if isinstance(o, string_types): | |
60 | return Text(value=unicode_type(o)) |
|
60 | return Text(value=unicode_type(o)) | |
61 | elif isinstance(o, dict): |
|
61 | elif isinstance(o, dict): | |
62 |
return Dropdown( |
|
62 | return Dropdown(options=o) | |
63 | elif isinstance(o, bool): |
|
63 | elif isinstance(o, bool): | |
64 | return Checkbox(value=o) |
|
64 | return Checkbox(value=o) | |
65 | elif isinstance(o, float): |
|
65 | elif isinstance(o, float): | |
66 | min, max, value = _get_min_max_value(None, None, o) |
|
66 | min, max, value = _get_min_max_value(None, None, o) | |
67 | return FloatSlider(value=o, min=min, max=max) |
|
67 | return FloatSlider(value=o, min=min, max=max) | |
68 | elif isinstance(o, int): |
|
68 | elif isinstance(o, int): | |
69 | min, max, value = _get_min_max_value(None, None, o) |
|
69 | min, max, value = _get_min_max_value(None, None, o) | |
70 | return IntSlider(value=o, min=min, max=max) |
|
70 | return IntSlider(value=o, min=min, max=max) | |
71 | else: |
|
71 | else: | |
72 | return None |
|
72 | return None | |
73 |
|
73 | |||
74 | def _widget_abbrev(o): |
|
74 | def _widget_abbrev(o): | |
75 | """Make widgets from abbreviations: single values, lists or tuples.""" |
|
75 | """Make widgets from abbreviations: single values, lists or tuples.""" | |
76 | float_or_int = (float, int) |
|
76 | float_or_int = (float, int) | |
77 | if isinstance(o, (list, tuple)): |
|
77 | if isinstance(o, (list, tuple)): | |
78 | if o and all(isinstance(x, string_types) for x in o): |
|
78 | if o and all(isinstance(x, string_types) for x in o): | |
79 |
return Dropdown( |
|
79 | return Dropdown(options=[unicode_type(k) for k in o]) | |
80 | elif _matches(o, (float_or_int, float_or_int)): |
|
80 | elif _matches(o, (float_or_int, float_or_int)): | |
81 | min, max, value = _get_min_max_value(o[0], o[1]) |
|
81 | min, max, value = _get_min_max_value(o[0], o[1]) | |
82 | if all(isinstance(_, int) for _ in o): |
|
82 | if all(isinstance(_, int) for _ in o): | |
83 | cls = IntSlider |
|
83 | cls = IntSlider | |
84 | else: |
|
84 | else: | |
85 | cls = FloatSlider |
|
85 | cls = FloatSlider | |
86 | return cls(value=value, min=min, max=max) |
|
86 | return cls(value=value, min=min, max=max) | |
87 | elif _matches(o, (float_or_int, float_or_int, float_or_int)): |
|
87 | elif _matches(o, (float_or_int, float_or_int, float_or_int)): | |
88 | step = o[2] |
|
88 | step = o[2] | |
89 | if step <= 0: |
|
89 | if step <= 0: | |
90 | raise ValueError("step must be >= 0, not %r" % step) |
|
90 | raise ValueError("step must be >= 0, not %r" % step) | |
91 | min, max, value = _get_min_max_value(o[0], o[1], step=step) |
|
91 | min, max, value = _get_min_max_value(o[0], o[1], step=step) | |
92 | if all(isinstance(_, int) for _ in o): |
|
92 | if all(isinstance(_, int) for _ in o): | |
93 | cls = IntSlider |
|
93 | cls = IntSlider | |
94 | else: |
|
94 | else: | |
95 | cls = FloatSlider |
|
95 | cls = FloatSlider | |
96 | return cls(value=value, min=min, max=max, step=step) |
|
96 | return cls(value=value, min=min, max=max, step=step) | |
97 | else: |
|
97 | else: | |
98 | return _widget_abbrev_single_value(o) |
|
98 | return _widget_abbrev_single_value(o) | |
99 |
|
99 | |||
100 | def _widget_from_abbrev(abbrev, default=empty): |
|
100 | def _widget_from_abbrev(abbrev, default=empty): | |
101 | """Build a Widget instance given an abbreviation or Widget.""" |
|
101 | """Build a Widget instance given an abbreviation or Widget.""" | |
102 | if isinstance(abbrev, Widget) or isinstance(abbrev, fixed): |
|
102 | if isinstance(abbrev, Widget) or isinstance(abbrev, fixed): | |
103 | return abbrev |
|
103 | return abbrev | |
104 |
|
104 | |||
105 | widget = _widget_abbrev(abbrev) |
|
105 | widget = _widget_abbrev(abbrev) | |
106 | if default is not empty and isinstance(abbrev, (list, tuple, dict)): |
|
106 | if default is not empty and isinstance(abbrev, (list, tuple, dict)): | |
107 | # if it's not a single-value abbreviation, |
|
107 | # if it's not a single-value abbreviation, | |
108 | # set the initial value from the default |
|
108 | # set the initial value from the default | |
109 | try: |
|
109 | try: | |
110 | widget.value = default |
|
110 | widget.value = default | |
111 | except Exception: |
|
111 | except Exception: | |
112 | # ignore failure to set default |
|
112 | # ignore failure to set default | |
113 | pass |
|
113 | pass | |
114 | if widget is None: |
|
114 | if widget is None: | |
115 | raise ValueError("%r cannot be transformed to a Widget" % (abbrev,)) |
|
115 | raise ValueError("%r cannot be transformed to a Widget" % (abbrev,)) | |
116 | return widget |
|
116 | return widget | |
117 |
|
117 | |||
118 | def _yield_abbreviations_for_parameter(param, kwargs): |
|
118 | def _yield_abbreviations_for_parameter(param, kwargs): | |
119 | """Get an abbreviation for a function parameter.""" |
|
119 | """Get an abbreviation for a function parameter.""" | |
120 | name = param.name |
|
120 | name = param.name | |
121 | kind = param.kind |
|
121 | kind = param.kind | |
122 | ann = param.annotation |
|
122 | ann = param.annotation | |
123 | default = param.default |
|
123 | default = param.default | |
124 | not_found = (name, empty, empty) |
|
124 | not_found = (name, empty, empty) | |
125 | if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY): |
|
125 | if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY): | |
126 | if name in kwargs: |
|
126 | if name in kwargs: | |
127 | value = kwargs.pop(name) |
|
127 | value = kwargs.pop(name) | |
128 | elif ann is not empty: |
|
128 | elif ann is not empty: | |
129 | value = ann |
|
129 | value = ann | |
130 | elif default is not empty: |
|
130 | elif default is not empty: | |
131 | value = default |
|
131 | value = default | |
132 | else: |
|
132 | else: | |
133 | yield not_found |
|
133 | yield not_found | |
134 | yield (name, value, default) |
|
134 | yield (name, value, default) | |
135 | elif kind == Parameter.VAR_KEYWORD: |
|
135 | elif kind == Parameter.VAR_KEYWORD: | |
136 | # In this case name=kwargs and we yield the items in kwargs with their keys. |
|
136 | # In this case name=kwargs and we yield the items in kwargs with their keys. | |
137 | for k, v in kwargs.copy().items(): |
|
137 | for k, v in kwargs.copy().items(): | |
138 | kwargs.pop(k) |
|
138 | kwargs.pop(k) | |
139 | yield k, v, empty |
|
139 | yield k, v, empty | |
140 |
|
140 | |||
141 | def _find_abbreviations(f, kwargs): |
|
141 | def _find_abbreviations(f, kwargs): | |
142 | """Find the abbreviations for a function and kwargs passed to interact.""" |
|
142 | """Find the abbreviations for a function and kwargs passed to interact.""" | |
143 | new_kwargs = [] |
|
143 | new_kwargs = [] | |
144 | for param in signature(f).parameters.values(): |
|
144 | for param in signature(f).parameters.values(): | |
145 | for name, value, default in _yield_abbreviations_for_parameter(param, kwargs): |
|
145 | for name, value, default in _yield_abbreviations_for_parameter(param, kwargs): | |
146 | if value is empty: |
|
146 | if value is empty: | |
147 | raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name)) |
|
147 | raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name)) | |
148 | new_kwargs.append((name, value, default)) |
|
148 | new_kwargs.append((name, value, default)) | |
149 | return new_kwargs |
|
149 | return new_kwargs | |
150 |
|
150 | |||
151 | def _widgets_from_abbreviations(seq): |
|
151 | def _widgets_from_abbreviations(seq): | |
152 | """Given a sequence of (name, abbrev) tuples, return a sequence of Widgets.""" |
|
152 | """Given a sequence of (name, abbrev) tuples, return a sequence of Widgets.""" | |
153 | result = [] |
|
153 | result = [] | |
154 | for name, abbrev, default in seq: |
|
154 | for name, abbrev, default in seq: | |
155 | widget = _widget_from_abbrev(abbrev, default) |
|
155 | widget = _widget_from_abbrev(abbrev, default) | |
156 | if not widget.description: |
|
156 | if not widget.description: | |
157 | widget.description = name |
|
157 | widget.description = name | |
158 | widget._kwarg = name |
|
158 | widget._kwarg = name | |
159 | result.append(widget) |
|
159 | result.append(widget) | |
160 | return result |
|
160 | return result | |
161 |
|
161 | |||
162 | def interactive(__interact_f, **kwargs): |
|
162 | def interactive(__interact_f, **kwargs): | |
163 | """ |
|
163 | """ | |
164 | Builds a group of interactive widgets tied to a function and places the |
|
164 | Builds a group of interactive widgets tied to a function and places the | |
165 | group into a Box container. |
|
165 | group into a Box container. | |
166 |
|
166 | |||
167 | Returns |
|
167 | Returns | |
168 | ------- |
|
168 | ------- | |
169 | container : a Box instance containing multiple widgets |
|
169 | container : a Box instance containing multiple widgets | |
170 |
|
170 | |||
171 | Parameters |
|
171 | Parameters | |
172 | ---------- |
|
172 | ---------- | |
173 | __interact_f : function |
|
173 | __interact_f : function | |
174 | The function to which the interactive widgets are tied. The **kwargs |
|
174 | The function to which the interactive widgets are tied. The **kwargs | |
175 | should match the function signature. |
|
175 | should match the function signature. | |
176 | **kwargs : various, optional |
|
176 | **kwargs : various, optional | |
177 | An interactive widget is created for each keyword argument that is a |
|
177 | An interactive widget is created for each keyword argument that is a | |
178 | valid widget abbreviation. |
|
178 | valid widget abbreviation. | |
179 | """ |
|
179 | """ | |
180 | f = __interact_f |
|
180 | f = __interact_f | |
181 | co = kwargs.pop('clear_output', True) |
|
181 | co = kwargs.pop('clear_output', True) | |
182 | manual = kwargs.pop('__manual', False) |
|
182 | manual = kwargs.pop('__manual', False) | |
183 | kwargs_widgets = [] |
|
183 | kwargs_widgets = [] | |
184 | container = Box() |
|
184 | container = Box() | |
185 | container.result = None |
|
185 | container.result = None | |
186 | container.args = [] |
|
186 | container.args = [] | |
187 | container.kwargs = dict() |
|
187 | container.kwargs = dict() | |
188 | kwargs = kwargs.copy() |
|
188 | kwargs = kwargs.copy() | |
189 |
|
189 | |||
190 | new_kwargs = _find_abbreviations(f, kwargs) |
|
190 | new_kwargs = _find_abbreviations(f, kwargs) | |
191 | # Before we proceed, let's make sure that the user has passed a set of args+kwargs |
|
191 | # Before we proceed, let's make sure that the user has passed a set of args+kwargs | |
192 | # that will lead to a valid call of the function. This protects against unspecified |
|
192 | # that will lead to a valid call of the function. This protects against unspecified | |
193 | # and doubly-specified arguments. |
|
193 | # and doubly-specified arguments. | |
194 | getcallargs(f, **{n:v for n,v,_ in new_kwargs}) |
|
194 | getcallargs(f, **{n:v for n,v,_ in new_kwargs}) | |
195 | # Now build the widgets from the abbreviations. |
|
195 | # Now build the widgets from the abbreviations. | |
196 | kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs)) |
|
196 | kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs)) | |
197 |
|
197 | |||
198 | # This has to be done as an assignment, not using container.children.append, |
|
198 | # This has to be done as an assignment, not using container.children.append, | |
199 | # so that traitlets notices the update. We skip any objects (such as fixed) that |
|
199 | # so that traitlets notices the update. We skip any objects (such as fixed) that | |
200 | # are not DOMWidgets. |
|
200 | # are not DOMWidgets. | |
201 | c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)] |
|
201 | c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)] | |
202 |
|
202 | |||
203 | # If we are only to run the function on demand, add a button to request this |
|
203 | # If we are only to run the function on demand, add a button to request this | |
204 | if manual: |
|
204 | if manual: | |
205 | manual_button = Button(description="Run %s" % f.__name__) |
|
205 | manual_button = Button(description="Run %s" % f.__name__) | |
206 | c.append(manual_button) |
|
206 | c.append(manual_button) | |
207 |
|
207 | |||
208 | # Use an output widget to capture the output of interact. |
|
208 | # Use an output widget to capture the output of interact. | |
209 | output = Output() |
|
209 | output = Output() | |
210 | c.append(output) |
|
210 | c.append(output) | |
211 | container.children = c |
|
211 | container.children = c | |
212 |
|
212 | |||
213 | # Build the callback |
|
213 | # Build the callback | |
214 | def call_f(name=None, old=None, new=None): |
|
214 | def call_f(name=None, old=None, new=None): | |
215 | with output: |
|
215 | with output: | |
216 | container.kwargs = {} |
|
216 | container.kwargs = {} | |
217 | for widget in kwargs_widgets: |
|
217 | for widget in kwargs_widgets: | |
218 | value = widget.value |
|
218 | value = widget.value | |
219 | container.kwargs[widget._kwarg] = value |
|
219 | container.kwargs[widget._kwarg] = value | |
220 | if co: |
|
220 | if co: | |
221 | clear_output(wait=True) |
|
221 | clear_output(wait=True) | |
222 | if manual: |
|
222 | if manual: | |
223 | manual_button.disabled = True |
|
223 | manual_button.disabled = True | |
224 | try: |
|
224 | try: | |
225 | container.result = f(**container.kwargs) |
|
225 | container.result = f(**container.kwargs) | |
226 | except Exception as e: |
|
226 | except Exception as e: | |
227 | ip = get_ipython() |
|
227 | ip = get_ipython() | |
228 | if ip is None: |
|
228 | if ip is None: | |
229 | container.log.warn("Exception in interact callback: %s", e, exc_info=True) |
|
229 | container.log.warn("Exception in interact callback: %s", e, exc_info=True) | |
230 | else: |
|
230 | else: | |
231 | ip.showtraceback() |
|
231 | ip.showtraceback() | |
232 | finally: |
|
232 | finally: | |
233 | if manual: |
|
233 | if manual: | |
234 | manual_button.disabled = False |
|
234 | manual_button.disabled = False | |
235 |
|
235 | |||
236 | # Wire up the widgets |
|
236 | # Wire up the widgets | |
237 | # If we are doing manual running, the callback is only triggered by the button |
|
237 | # If we are doing manual running, the callback is only triggered by the button | |
238 | # Otherwise, it is triggered for every trait change received |
|
238 | # Otherwise, it is triggered for every trait change received | |
239 | # On-demand running also suppresses running the function with the initial parameters |
|
239 | # On-demand running also suppresses running the function with the initial parameters | |
240 | if manual: |
|
240 | if manual: | |
241 | manual_button.on_click(call_f) |
|
241 | manual_button.on_click(call_f) | |
242 | else: |
|
242 | else: | |
243 | for widget in kwargs_widgets: |
|
243 | for widget in kwargs_widgets: | |
244 | widget.on_trait_change(call_f, 'value') |
|
244 | widget.on_trait_change(call_f, 'value') | |
245 |
|
245 | |||
246 | container.on_displayed(lambda _: call_f(None, None, None)) |
|
246 | container.on_displayed(lambda _: call_f(None, None, None)) | |
247 |
|
247 | |||
248 | return container |
|
248 | return container | |
249 |
|
249 | |||
250 | def interact(__interact_f=None, **kwargs): |
|
250 | def interact(__interact_f=None, **kwargs): | |
251 | """ |
|
251 | """ | |
252 | Displays interactive widgets which are tied to a function. |
|
252 | Displays interactive widgets which are tied to a function. | |
253 | Expects the first argument to be a function. Parameters to this function are |
|
253 | Expects the first argument to be a function. Parameters to this function are | |
254 | widget abbreviations passed in as keyword arguments (**kwargs). Can be used |
|
254 | widget abbreviations passed in as keyword arguments (**kwargs). Can be used | |
255 | as a decorator (see examples). |
|
255 | as a decorator (see examples). | |
256 |
|
256 | |||
257 | Returns |
|
257 | Returns | |
258 | ------- |
|
258 | ------- | |
259 | f : __interact_f with interactive widget attached to it. |
|
259 | f : __interact_f with interactive widget attached to it. | |
260 |
|
260 | |||
261 | Parameters |
|
261 | Parameters | |
262 | ---------- |
|
262 | ---------- | |
263 | __interact_f : function |
|
263 | __interact_f : function | |
264 | The function to which the interactive widgets are tied. The **kwargs |
|
264 | The function to which the interactive widgets are tied. The **kwargs | |
265 | should match the function signature. Passed to :func:`interactive()` |
|
265 | should match the function signature. Passed to :func:`interactive()` | |
266 | **kwargs : various, optional |
|
266 | **kwargs : various, optional | |
267 | An interactive widget is created for each keyword argument that is a |
|
267 | An interactive widget is created for each keyword argument that is a | |
268 | valid widget abbreviation. Passed to :func:`interactive()` |
|
268 | valid widget abbreviation. Passed to :func:`interactive()` | |
269 |
|
269 | |||
270 | Examples |
|
270 | Examples | |
271 | -------- |
|
271 | -------- | |
272 | Renders an interactive text field that shows the greeting with the passed in |
|
272 | Renders an interactive text field that shows the greeting with the passed in | |
273 | text. |
|
273 | text. | |
274 |
|
274 | |||
275 | 1. Invocation of interact as a function |
|
275 | 1. Invocation of interact as a function | |
276 | def greeting(text="World"): |
|
276 | def greeting(text="World"): | |
277 | print "Hello {}".format(text) |
|
277 | print "Hello {}".format(text) | |
278 | interact(greeting, text="IPython Widgets") |
|
278 | interact(greeting, text="IPython Widgets") | |
279 |
|
279 | |||
280 | 2. Invocation of interact as a decorator |
|
280 | 2. Invocation of interact as a decorator | |
281 | @interact |
|
281 | @interact | |
282 | def greeting(text="World"): |
|
282 | def greeting(text="World"): | |
283 | print "Hello {}".format(text) |
|
283 | print "Hello {}".format(text) | |
284 |
|
284 | |||
285 | 3. Invocation of interact as a decorator with named parameters |
|
285 | 3. Invocation of interact as a decorator with named parameters | |
286 | @interact(text="IPython Widgets") |
|
286 | @interact(text="IPython Widgets") | |
287 | def greeting(text="World"): |
|
287 | def greeting(text="World"): | |
288 | print "Hello {}".format(text) |
|
288 | print "Hello {}".format(text) | |
289 |
|
289 | |||
290 | Renders an interactive slider widget and prints square of number. |
|
290 | Renders an interactive slider widget and prints square of number. | |
291 |
|
291 | |||
292 | 1. Invocation of interact as a function |
|
292 | 1. Invocation of interact as a function | |
293 | def square(num=1): |
|
293 | def square(num=1): | |
294 | print "{} squared is {}".format(num, num*num) |
|
294 | print "{} squared is {}".format(num, num*num) | |
295 | interact(square, num=5) |
|
295 | interact(square, num=5) | |
296 |
|
296 | |||
297 | 2. Invocation of interact as a decorator |
|
297 | 2. Invocation of interact as a decorator | |
298 | @interact |
|
298 | @interact | |
299 | def square(num=2): |
|
299 | def square(num=2): | |
300 | print "{} squared is {}".format(num, num*num) |
|
300 | print "{} squared is {}".format(num, num*num) | |
301 |
|
301 | |||
302 | 3. Invocation of interact as a decorator with named parameters |
|
302 | 3. Invocation of interact as a decorator with named parameters | |
303 | @interact(num=5) |
|
303 | @interact(num=5) | |
304 | def square(num=2): |
|
304 | def square(num=2): | |
305 | print "{} squared is {}".format(num, num*num) |
|
305 | print "{} squared is {}".format(num, num*num) | |
306 | """ |
|
306 | """ | |
307 | # positional arg support in: https://gist.github.com/8851331 |
|
307 | # positional arg support in: https://gist.github.com/8851331 | |
308 | if __interact_f is not None: |
|
308 | if __interact_f is not None: | |
309 | # This branch handles the cases 1 and 2 |
|
309 | # This branch handles the cases 1 and 2 | |
310 | # 1. interact(f, **kwargs) |
|
310 | # 1. interact(f, **kwargs) | |
311 | # 2. @interact |
|
311 | # 2. @interact | |
312 | # def f(*args, **kwargs): |
|
312 | # def f(*args, **kwargs): | |
313 | # ... |
|
313 | # ... | |
314 | f = __interact_f |
|
314 | f = __interact_f | |
315 | w = interactive(f, **kwargs) |
|
315 | w = interactive(f, **kwargs) | |
316 | try: |
|
316 | try: | |
317 | f.widget = w |
|
317 | f.widget = w | |
318 | except AttributeError: |
|
318 | except AttributeError: | |
319 | # some things (instancemethods) can't have attributes attached, |
|
319 | # some things (instancemethods) can't have attributes attached, | |
320 | # so wrap in a lambda |
|
320 | # so wrap in a lambda | |
321 | f = lambda *args, **kwargs: __interact_f(*args, **kwargs) |
|
321 | f = lambda *args, **kwargs: __interact_f(*args, **kwargs) | |
322 | f.widget = w |
|
322 | f.widget = w | |
323 | display(w) |
|
323 | display(w) | |
324 | return f |
|
324 | return f | |
325 | else: |
|
325 | else: | |
326 | # This branch handles the case 3 |
|
326 | # This branch handles the case 3 | |
327 | # @interact(a=30, b=40) |
|
327 | # @interact(a=30, b=40) | |
328 | # def f(*args, **kwargs): |
|
328 | # def f(*args, **kwargs): | |
329 | # ... |
|
329 | # ... | |
330 | def dec(f): |
|
330 | def dec(f): | |
331 | return interact(f, **kwargs) |
|
331 | return interact(f, **kwargs) | |
332 | return dec |
|
332 | return dec | |
333 |
|
333 | |||
334 | def interact_manual(__interact_f=None, **kwargs): |
|
334 | def interact_manual(__interact_f=None, **kwargs): | |
335 | """interact_manual(f, **kwargs) |
|
335 | """interact_manual(f, **kwargs) | |
336 |
|
336 | |||
337 | As `interact()`, generates widgets for each argument, but rather than running |
|
337 | As `interact()`, generates widgets for each argument, but rather than running | |
338 | the function after each widget change, adds a "Run" button and waits for it |
|
338 | the function after each widget change, adds a "Run" button and waits for it | |
339 | to be clicked. Useful if the function is long-running and has several |
|
339 | to be clicked. Useful if the function is long-running and has several | |
340 | parameters to change. |
|
340 | parameters to change. | |
341 | """ |
|
341 | """ | |
342 | return interact(__interact_f, __manual=True, **kwargs) |
|
342 | return interact(__interact_f, __manual=True, **kwargs) | |
343 |
|
343 | |||
344 | class fixed(HasTraits): |
|
344 | class fixed(HasTraits): | |
345 | """A pseudo-widget whose value is fixed and never synced to the client.""" |
|
345 | """A pseudo-widget whose value is fixed and never synced to the client.""" | |
346 | value = Any(help="Any Python object") |
|
346 | value = Any(help="Any Python object") | |
347 | description = Unicode('', help="Any Python object") |
|
347 | description = Unicode('', help="Any Python object") | |
348 | def __init__(self, value, **kwargs): |
|
348 | def __init__(self, value, **kwargs): | |
349 | super(fixed, self).__init__(value=value, **kwargs) |
|
349 | super(fixed, self).__init__(value=value, **kwargs) |
@@ -1,636 +1,692 b'' | |||||
1 | """Test interact and interactive.""" |
|
1 | """Test interact and interactive.""" | |
2 |
|
2 | |||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 | from __future__ import print_function |
|
6 | from __future__ import print_function | |
7 |
|
7 | |||
8 | from collections import OrderedDict |
|
8 | from collections import OrderedDict | |
9 |
|
9 | |||
10 | import nose.tools as nt |
|
10 | import nose.tools as nt | |
11 | import IPython.testing.tools as tt |
|
11 | import IPython.testing.tools as tt | |
12 |
|
12 | |||
13 | from IPython.kernel.comm import Comm |
|
13 | from IPython.kernel.comm import Comm | |
14 | from IPython.html import widgets |
|
14 | from IPython.html import widgets | |
15 | from IPython.html.widgets import interact, interactive, Widget, interaction |
|
15 | from IPython.html.widgets import interact, interactive, Widget, interaction | |
16 | from IPython.utils.py3compat import annotate |
|
16 | from IPython.utils.py3compat import annotate | |
17 |
|
17 | |||
18 | #----------------------------------------------------------------------------- |
|
18 | #----------------------------------------------------------------------------- | |
19 | # Utility stuff |
|
19 | # Utility stuff | |
20 | #----------------------------------------------------------------------------- |
|
20 | #----------------------------------------------------------------------------- | |
21 |
|
21 | |||
22 | class DummyComm(Comm): |
|
22 | class DummyComm(Comm): | |
23 | comm_id = 'a-b-c-d' |
|
23 | comm_id = 'a-b-c-d' | |
24 |
|
24 | |||
25 | def open(self, *args, **kwargs): |
|
25 | def open(self, *args, **kwargs): | |
26 | pass |
|
26 | pass | |
27 |
|
27 | |||
28 | def send(self, *args, **kwargs): |
|
28 | def send(self, *args, **kwargs): | |
29 | pass |
|
29 | pass | |
30 |
|
30 | |||
31 | def close(self, *args, **kwargs): |
|
31 | def close(self, *args, **kwargs): | |
32 | pass |
|
32 | pass | |
33 |
|
33 | |||
34 | _widget_attrs = {} |
|
34 | _widget_attrs = {} | |
35 | displayed = [] |
|
35 | displayed = [] | |
36 | undefined = object() |
|
36 | undefined = object() | |
37 |
|
37 | |||
38 | def setup(): |
|
38 | def setup(): | |
39 | _widget_attrs['_comm_default'] = getattr(Widget, '_comm_default', undefined) |
|
39 | _widget_attrs['_comm_default'] = getattr(Widget, '_comm_default', undefined) | |
40 | Widget._comm_default = lambda self: DummyComm() |
|
40 | Widget._comm_default = lambda self: DummyComm() | |
41 | _widget_attrs['_ipython_display_'] = Widget._ipython_display_ |
|
41 | _widget_attrs['_ipython_display_'] = Widget._ipython_display_ | |
42 | def raise_not_implemented(*args, **kwargs): |
|
42 | def raise_not_implemented(*args, **kwargs): | |
43 | raise NotImplementedError() |
|
43 | raise NotImplementedError() | |
44 | Widget._ipython_display_ = raise_not_implemented |
|
44 | Widget._ipython_display_ = raise_not_implemented | |
45 |
|
45 | |||
46 | def teardown(): |
|
46 | def teardown(): | |
47 | for attr, value in _widget_attrs.items(): |
|
47 | for attr, value in _widget_attrs.items(): | |
48 | if value is undefined: |
|
48 | if value is undefined: | |
49 | delattr(Widget, attr) |
|
49 | delattr(Widget, attr) | |
50 | else: |
|
50 | else: | |
51 | setattr(Widget, attr, value) |
|
51 | setattr(Widget, attr, value) | |
52 |
|
52 | |||
53 | def f(**kwargs): |
|
53 | def f(**kwargs): | |
54 | pass |
|
54 | pass | |
55 |
|
55 | |||
56 | def clear_display(): |
|
56 | def clear_display(): | |
57 | global displayed |
|
57 | global displayed | |
58 | displayed = [] |
|
58 | displayed = [] | |
59 |
|
59 | |||
60 | def record_display(*args): |
|
60 | def record_display(*args): | |
61 | displayed.extend(args) |
|
61 | displayed.extend(args) | |
62 |
|
62 | |||
63 | #----------------------------------------------------------------------------- |
|
63 | #----------------------------------------------------------------------------- | |
64 | # Actual tests |
|
64 | # Actual tests | |
65 | #----------------------------------------------------------------------------- |
|
65 | #----------------------------------------------------------------------------- | |
66 |
|
66 | |||
67 | def check_widget(w, **d): |
|
67 | def check_widget(w, **d): | |
68 | """Check a single widget against a dict""" |
|
68 | """Check a single widget against a dict""" | |
69 | for attr, expected in d.items(): |
|
69 | for attr, expected in d.items(): | |
70 | if attr == 'cls': |
|
70 | if attr == 'cls': | |
71 | nt.assert_is(w.__class__, expected) |
|
71 | nt.assert_is(w.__class__, expected) | |
72 | else: |
|
72 | else: | |
73 | value = getattr(w, attr) |
|
73 | value = getattr(w, attr) | |
74 | nt.assert_equal(value, expected, |
|
74 | nt.assert_equal(value, expected, | |
75 | "%s.%s = %r != %r" % (w.__class__.__name__, attr, value, expected) |
|
75 | "%s.%s = %r != %r" % (w.__class__.__name__, attr, value, expected) | |
76 | ) |
|
76 | ) | |
77 |
|
77 | |||
78 | def check_widgets(container, **to_check): |
|
78 | def check_widgets(container, **to_check): | |
79 | """Check that widgets are created as expected""" |
|
79 | """Check that widgets are created as expected""" | |
80 | # build a widget dictionary, so it matches |
|
80 | # build a widget dictionary, so it matches | |
81 | widgets = {} |
|
81 | widgets = {} | |
82 | for w in container.children: |
|
82 | for w in container.children: | |
83 | if hasattr(w, 'description'): |
|
83 | if hasattr(w, 'description'): | |
84 | widgets[w.description] = w |
|
84 | widgets[w.description] = w | |
85 |
|
85 | |||
86 | for key, d in to_check.items(): |
|
86 | for key, d in to_check.items(): | |
87 | nt.assert_in(key, widgets) |
|
87 | nt.assert_in(key, widgets) | |
88 | check_widget(widgets[key], **d) |
|
88 | check_widget(widgets[key], **d) | |
89 |
|
89 | |||
90 |
|
90 | |||
91 | def test_single_value_string(): |
|
91 | def test_single_value_string(): | |
92 | a = u'hello' |
|
92 | a = u'hello' | |
93 | c = interactive(f, a=a) |
|
93 | c = interactive(f, a=a) | |
94 | w = c.children[0] |
|
94 | w = c.children[0] | |
95 | check_widget(w, |
|
95 | check_widget(w, | |
96 | cls=widgets.Text, |
|
96 | cls=widgets.Text, | |
97 | description='a', |
|
97 | description='a', | |
98 | value=a, |
|
98 | value=a, | |
99 | ) |
|
99 | ) | |
100 |
|
100 | |||
101 | def test_single_value_bool(): |
|
101 | def test_single_value_bool(): | |
102 | for a in (True, False): |
|
102 | for a in (True, False): | |
103 | c = interactive(f, a=a) |
|
103 | c = interactive(f, a=a) | |
104 | w = c.children[0] |
|
104 | w = c.children[0] | |
105 | check_widget(w, |
|
105 | check_widget(w, | |
106 | cls=widgets.Checkbox, |
|
106 | cls=widgets.Checkbox, | |
107 | description='a', |
|
107 | description='a', | |
108 | value=a, |
|
108 | value=a, | |
109 | ) |
|
109 | ) | |
110 |
|
110 | |||
111 | def test_single_value_dict(): |
|
111 | def test_single_value_dict(): | |
112 | for d in [ |
|
112 | for d in [ | |
113 | dict(a=5), |
|
113 | dict(a=5), | |
114 | dict(a=5, b='b', c=dict), |
|
114 | dict(a=5, b='b', c=dict), | |
115 | ]: |
|
115 | ]: | |
116 | c = interactive(f, d=d) |
|
116 | c = interactive(f, d=d) | |
117 | w = c.children[0] |
|
117 | w = c.children[0] | |
118 | check_widget(w, |
|
118 | check_widget(w, | |
119 | cls=widgets.Dropdown, |
|
119 | cls=widgets.Dropdown, | |
120 | description='d', |
|
120 | description='d', | |
121 |
|
|
121 | options=d, | |
122 | value=next(iter(d.values())), |
|
122 | value=next(iter(d.values())), | |
123 | ) |
|
123 | ) | |
124 |
|
124 | |||
125 | def test_single_value_float(): |
|
125 | def test_single_value_float(): | |
126 | for a in (2.25, 1.0, -3.5): |
|
126 | for a in (2.25, 1.0, -3.5): | |
127 | c = interactive(f, a=a) |
|
127 | c = interactive(f, a=a) | |
128 | w = c.children[0] |
|
128 | w = c.children[0] | |
129 | check_widget(w, |
|
129 | check_widget(w, | |
130 | cls=widgets.FloatSlider, |
|
130 | cls=widgets.FloatSlider, | |
131 | description='a', |
|
131 | description='a', | |
132 | value=a, |
|
132 | value=a, | |
133 | min= -a if a > 0 else 3*a, |
|
133 | min= -a if a > 0 else 3*a, | |
134 | max= 3*a if a > 0 else -a, |
|
134 | max= 3*a if a > 0 else -a, | |
135 | step=0.1, |
|
135 | step=0.1, | |
136 | readout=True, |
|
136 | readout=True, | |
137 | ) |
|
137 | ) | |
138 |
|
138 | |||
139 | def test_single_value_int(): |
|
139 | def test_single_value_int(): | |
140 | for a in (1, 5, -3): |
|
140 | for a in (1, 5, -3): | |
141 | c = interactive(f, a=a) |
|
141 | c = interactive(f, a=a) | |
142 | nt.assert_equal(len(c.children), 2) |
|
142 | nt.assert_equal(len(c.children), 2) | |
143 | w = c.children[0] |
|
143 | w = c.children[0] | |
144 | check_widget(w, |
|
144 | check_widget(w, | |
145 | cls=widgets.IntSlider, |
|
145 | cls=widgets.IntSlider, | |
146 | description='a', |
|
146 | description='a', | |
147 | value=a, |
|
147 | value=a, | |
148 | min= -a if a > 0 else 3*a, |
|
148 | min= -a if a > 0 else 3*a, | |
149 | max= 3*a if a > 0 else -a, |
|
149 | max= 3*a if a > 0 else -a, | |
150 | step=1, |
|
150 | step=1, | |
151 | readout=True, |
|
151 | readout=True, | |
152 | ) |
|
152 | ) | |
153 |
|
153 | |||
154 | def test_list_tuple_2_int(): |
|
154 | def test_list_tuple_2_int(): | |
155 | with nt.assert_raises(ValueError): |
|
155 | with nt.assert_raises(ValueError): | |
156 | c = interactive(f, tup=(1,1)) |
|
156 | c = interactive(f, tup=(1,1)) | |
157 | with nt.assert_raises(ValueError): |
|
157 | with nt.assert_raises(ValueError): | |
158 | c = interactive(f, tup=(1,-1)) |
|
158 | c = interactive(f, tup=(1,-1)) | |
159 | for min, max in [ (0,1), (1,10), (1,2), (-5,5), (-20,-19) ]: |
|
159 | for min, max in [ (0,1), (1,10), (1,2), (-5,5), (-20,-19) ]: | |
160 | c = interactive(f, tup=(min, max), lis=[min, max]) |
|
160 | c = interactive(f, tup=(min, max), lis=[min, max]) | |
161 | nt.assert_equal(len(c.children), 3) |
|
161 | nt.assert_equal(len(c.children), 3) | |
162 | d = dict( |
|
162 | d = dict( | |
163 | cls=widgets.IntSlider, |
|
163 | cls=widgets.IntSlider, | |
164 | min=min, |
|
164 | min=min, | |
165 | max=max, |
|
165 | max=max, | |
166 | step=1, |
|
166 | step=1, | |
167 | readout=True, |
|
167 | readout=True, | |
168 | ) |
|
168 | ) | |
169 | check_widgets(c, tup=d, lis=d) |
|
169 | check_widgets(c, tup=d, lis=d) | |
170 |
|
170 | |||
171 | def test_list_tuple_3_int(): |
|
171 | def test_list_tuple_3_int(): | |
172 | with nt.assert_raises(ValueError): |
|
172 | with nt.assert_raises(ValueError): | |
173 | c = interactive(f, tup=(1,2,0)) |
|
173 | c = interactive(f, tup=(1,2,0)) | |
174 | with nt.assert_raises(ValueError): |
|
174 | with nt.assert_raises(ValueError): | |
175 | c = interactive(f, tup=(1,2,-1)) |
|
175 | c = interactive(f, tup=(1,2,-1)) | |
176 | for min, max, step in [ (0,2,1), (1,10,2), (1,100,2), (-5,5,4), (-100,-20,4) ]: |
|
176 | for min, max, step in [ (0,2,1), (1,10,2), (1,100,2), (-5,5,4), (-100,-20,4) ]: | |
177 | c = interactive(f, tup=(min, max, step), lis=[min, max, step]) |
|
177 | c = interactive(f, tup=(min, max, step), lis=[min, max, step]) | |
178 | nt.assert_equal(len(c.children), 3) |
|
178 | nt.assert_equal(len(c.children), 3) | |
179 | d = dict( |
|
179 | d = dict( | |
180 | cls=widgets.IntSlider, |
|
180 | cls=widgets.IntSlider, | |
181 | min=min, |
|
181 | min=min, | |
182 | max=max, |
|
182 | max=max, | |
183 | step=step, |
|
183 | step=step, | |
184 | readout=True, |
|
184 | readout=True, | |
185 | ) |
|
185 | ) | |
186 | check_widgets(c, tup=d, lis=d) |
|
186 | check_widgets(c, tup=d, lis=d) | |
187 |
|
187 | |||
188 | def test_list_tuple_2_float(): |
|
188 | def test_list_tuple_2_float(): | |
189 | with nt.assert_raises(ValueError): |
|
189 | with nt.assert_raises(ValueError): | |
190 | c = interactive(f, tup=(1.0,1.0)) |
|
190 | c = interactive(f, tup=(1.0,1.0)) | |
191 | with nt.assert_raises(ValueError): |
|
191 | with nt.assert_raises(ValueError): | |
192 | c = interactive(f, tup=(0.5,-0.5)) |
|
192 | c = interactive(f, tup=(0.5,-0.5)) | |
193 | for min, max in [ (0.5, 1.5), (1.1,10.2), (1,2.2), (-5.,5), (-20,-19.) ]: |
|
193 | for min, max in [ (0.5, 1.5), (1.1,10.2), (1,2.2), (-5.,5), (-20,-19.) ]: | |
194 | c = interactive(f, tup=(min, max), lis=[min, max]) |
|
194 | c = interactive(f, tup=(min, max), lis=[min, max]) | |
195 | nt.assert_equal(len(c.children), 3) |
|
195 | nt.assert_equal(len(c.children), 3) | |
196 | d = dict( |
|
196 | d = dict( | |
197 | cls=widgets.FloatSlider, |
|
197 | cls=widgets.FloatSlider, | |
198 | min=min, |
|
198 | min=min, | |
199 | max=max, |
|
199 | max=max, | |
200 | step=.1, |
|
200 | step=.1, | |
201 | readout=True, |
|
201 | readout=True, | |
202 | ) |
|
202 | ) | |
203 | check_widgets(c, tup=d, lis=d) |
|
203 | check_widgets(c, tup=d, lis=d) | |
204 |
|
204 | |||
205 | def test_list_tuple_3_float(): |
|
205 | def test_list_tuple_3_float(): | |
206 | with nt.assert_raises(ValueError): |
|
206 | with nt.assert_raises(ValueError): | |
207 | c = interactive(f, tup=(1,2,0.0)) |
|
207 | c = interactive(f, tup=(1,2,0.0)) | |
208 | with nt.assert_raises(ValueError): |
|
208 | with nt.assert_raises(ValueError): | |
209 | c = interactive(f, tup=(-1,-2,1.)) |
|
209 | c = interactive(f, tup=(-1,-2,1.)) | |
210 | with nt.assert_raises(ValueError): |
|
210 | with nt.assert_raises(ValueError): | |
211 | c = interactive(f, tup=(1,2.,-1.)) |
|
211 | c = interactive(f, tup=(1,2.,-1.)) | |
212 | for min, max, step in [ (0.,2,1), (1,10.,2), (1,100,2.), (-5.,5.,4), (-100,-20.,4.) ]: |
|
212 | for min, max, step in [ (0.,2,1), (1,10.,2), (1,100,2.), (-5.,5.,4), (-100,-20.,4.) ]: | |
213 | c = interactive(f, tup=(min, max, step), lis=[min, max, step]) |
|
213 | c = interactive(f, tup=(min, max, step), lis=[min, max, step]) | |
214 | nt.assert_equal(len(c.children), 3) |
|
214 | nt.assert_equal(len(c.children), 3) | |
215 | d = dict( |
|
215 | d = dict( | |
216 | cls=widgets.FloatSlider, |
|
216 | cls=widgets.FloatSlider, | |
217 | min=min, |
|
217 | min=min, | |
218 | max=max, |
|
218 | max=max, | |
219 | step=step, |
|
219 | step=step, | |
220 | readout=True, |
|
220 | readout=True, | |
221 | ) |
|
221 | ) | |
222 | check_widgets(c, tup=d, lis=d) |
|
222 | check_widgets(c, tup=d, lis=d) | |
223 |
|
223 | |||
224 | def test_list_tuple_str(): |
|
224 | def test_list_tuple_str(): | |
225 | values = ['hello', 'there', 'guy'] |
|
225 | values = ['hello', 'there', 'guy'] | |
226 | first = values[0] |
|
226 | first = values[0] | |
227 | c = interactive(f, tup=tuple(values), lis=list(values)) |
|
227 | c = interactive(f, tup=tuple(values), lis=list(values)) | |
228 | nt.assert_equal(len(c.children), 3) |
|
228 | nt.assert_equal(len(c.children), 3) | |
229 | d = dict( |
|
229 | d = dict( | |
230 | cls=widgets.Dropdown, |
|
230 | cls=widgets.Dropdown, | |
231 | value=first, |
|
231 | value=first, | |
232 |
|
|
232 | options=values | |
233 | ) |
|
233 | ) | |
234 | check_widgets(c, tup=d, lis=d) |
|
234 | check_widgets(c, tup=d, lis=d) | |
235 |
|
235 | |||
236 | def test_list_tuple_invalid(): |
|
236 | def test_list_tuple_invalid(): | |
237 | for bad in [ |
|
237 | for bad in [ | |
238 | (), |
|
238 | (), | |
239 | (5, 'hi'), |
|
239 | (5, 'hi'), | |
240 | ('hi', 5), |
|
240 | ('hi', 5), | |
241 | ({},), |
|
241 | ({},), | |
242 | (None,), |
|
242 | (None,), | |
243 | ]: |
|
243 | ]: | |
244 | with nt.assert_raises(ValueError): |
|
244 | with nt.assert_raises(ValueError): | |
245 | print(bad) # because there is no custom message in assert_raises |
|
245 | print(bad) # because there is no custom message in assert_raises | |
246 | c = interactive(f, tup=bad) |
|
246 | c = interactive(f, tup=bad) | |
247 |
|
247 | |||
248 | def test_defaults(): |
|
248 | def test_defaults(): | |
249 | @annotate(n=10) |
|
249 | @annotate(n=10) | |
250 | def f(n, f=4.5, g=1): |
|
250 | def f(n, f=4.5, g=1): | |
251 | pass |
|
251 | pass | |
252 |
|
252 | |||
253 | c = interactive(f) |
|
253 | c = interactive(f) | |
254 | check_widgets(c, |
|
254 | check_widgets(c, | |
255 | n=dict( |
|
255 | n=dict( | |
256 | cls=widgets.IntSlider, |
|
256 | cls=widgets.IntSlider, | |
257 | value=10, |
|
257 | value=10, | |
258 | ), |
|
258 | ), | |
259 | f=dict( |
|
259 | f=dict( | |
260 | cls=widgets.FloatSlider, |
|
260 | cls=widgets.FloatSlider, | |
261 | value=4.5, |
|
261 | value=4.5, | |
262 | ), |
|
262 | ), | |
263 | g=dict( |
|
263 | g=dict( | |
264 | cls=widgets.IntSlider, |
|
264 | cls=widgets.IntSlider, | |
265 | value=1, |
|
265 | value=1, | |
266 | ), |
|
266 | ), | |
267 | ) |
|
267 | ) | |
268 |
|
268 | |||
269 | def test_default_values(): |
|
269 | def test_default_values(): | |
270 | @annotate(n=10, f=(0, 10.), g=5, h={'a': 1, 'b': 2}, j=['hi', 'there']) |
|
270 | @annotate(n=10, f=(0, 10.), g=5, h={'a': 1, 'b': 2}, j=['hi', 'there']) | |
271 | def f(n, f=4.5, g=1, h=2, j='there'): |
|
271 | def f(n, f=4.5, g=1, h=2, j='there'): | |
272 | pass |
|
272 | pass | |
273 |
|
273 | |||
274 | c = interactive(f) |
|
274 | c = interactive(f) | |
275 | check_widgets(c, |
|
275 | check_widgets(c, | |
276 | n=dict( |
|
276 | n=dict( | |
277 | cls=widgets.IntSlider, |
|
277 | cls=widgets.IntSlider, | |
278 | value=10, |
|
278 | value=10, | |
279 | ), |
|
279 | ), | |
280 | f=dict( |
|
280 | f=dict( | |
281 | cls=widgets.FloatSlider, |
|
281 | cls=widgets.FloatSlider, | |
282 | value=4.5, |
|
282 | value=4.5, | |
283 | ), |
|
283 | ), | |
284 | g=dict( |
|
284 | g=dict( | |
285 | cls=widgets.IntSlider, |
|
285 | cls=widgets.IntSlider, | |
286 | value=5, |
|
286 | value=5, | |
287 | ), |
|
287 | ), | |
288 | h=dict( |
|
288 | h=dict( | |
289 | cls=widgets.Dropdown, |
|
289 | cls=widgets.Dropdown, | |
290 |
|
|
290 | options={'a': 1, 'b': 2}, | |
291 | value=2 |
|
291 | value=2 | |
292 | ), |
|
292 | ), | |
293 | j=dict( |
|
293 | j=dict( | |
294 | cls=widgets.Dropdown, |
|
294 | cls=widgets.Dropdown, | |
295 |
|
|
295 | options=['hi', 'there'], | |
296 | value='there' |
|
296 | value='there' | |
297 | ), |
|
297 | ), | |
298 | ) |
|
298 | ) | |
299 |
|
299 | |||
300 | def test_default_out_of_bounds(): |
|
300 | def test_default_out_of_bounds(): | |
301 | @annotate(f=(0, 10.), h={'a': 1}, j=['hi', 'there']) |
|
301 | @annotate(f=(0, 10.), h={'a': 1}, j=['hi', 'there']) | |
302 | def f(f='hi', h=5, j='other'): |
|
302 | def f(f='hi', h=5, j='other'): | |
303 | pass |
|
303 | pass | |
304 |
|
304 | |||
305 | c = interactive(f) |
|
305 | c = interactive(f) | |
306 | check_widgets(c, |
|
306 | check_widgets(c, | |
307 | f=dict( |
|
307 | f=dict( | |
308 | cls=widgets.FloatSlider, |
|
308 | cls=widgets.FloatSlider, | |
309 | value=5., |
|
309 | value=5., | |
310 | ), |
|
310 | ), | |
311 | h=dict( |
|
311 | h=dict( | |
312 | cls=widgets.Dropdown, |
|
312 | cls=widgets.Dropdown, | |
313 |
|
|
313 | options={'a': 1}, | |
314 | value=1, |
|
314 | value=1, | |
315 | ), |
|
315 | ), | |
316 | j=dict( |
|
316 | j=dict( | |
317 | cls=widgets.Dropdown, |
|
317 | cls=widgets.Dropdown, | |
318 |
|
|
318 | options=['hi', 'there'], | |
319 | value='hi', |
|
319 | value='hi', | |
320 | ), |
|
320 | ), | |
321 | ) |
|
321 | ) | |
322 |
|
322 | |||
323 | def test_annotations(): |
|
323 | def test_annotations(): | |
324 | @annotate(n=10, f=widgets.FloatText()) |
|
324 | @annotate(n=10, f=widgets.FloatText()) | |
325 | def f(n, f): |
|
325 | def f(n, f): | |
326 | pass |
|
326 | pass | |
327 |
|
327 | |||
328 | c = interactive(f) |
|
328 | c = interactive(f) | |
329 | check_widgets(c, |
|
329 | check_widgets(c, | |
330 | n=dict( |
|
330 | n=dict( | |
331 | cls=widgets.IntSlider, |
|
331 | cls=widgets.IntSlider, | |
332 | value=10, |
|
332 | value=10, | |
333 | ), |
|
333 | ), | |
334 | f=dict( |
|
334 | f=dict( | |
335 | cls=widgets.FloatText, |
|
335 | cls=widgets.FloatText, | |
336 | ), |
|
336 | ), | |
337 | ) |
|
337 | ) | |
338 |
|
338 | |||
339 | def test_priority(): |
|
339 | def test_priority(): | |
340 | @annotate(annotate='annotate', kwarg='annotate') |
|
340 | @annotate(annotate='annotate', kwarg='annotate') | |
341 | def f(kwarg='default', annotate='default', default='default'): |
|
341 | def f(kwarg='default', annotate='default', default='default'): | |
342 | pass |
|
342 | pass | |
343 |
|
343 | |||
344 | c = interactive(f, kwarg='kwarg') |
|
344 | c = interactive(f, kwarg='kwarg') | |
345 | check_widgets(c, |
|
345 | check_widgets(c, | |
346 | kwarg=dict( |
|
346 | kwarg=dict( | |
347 | cls=widgets.Text, |
|
347 | cls=widgets.Text, | |
348 | value='kwarg', |
|
348 | value='kwarg', | |
349 | ), |
|
349 | ), | |
350 | annotate=dict( |
|
350 | annotate=dict( | |
351 | cls=widgets.Text, |
|
351 | cls=widgets.Text, | |
352 | value='annotate', |
|
352 | value='annotate', | |
353 | ), |
|
353 | ), | |
354 | ) |
|
354 | ) | |
355 |
|
355 | |||
356 | @nt.with_setup(clear_display) |
|
356 | @nt.with_setup(clear_display) | |
357 | def test_decorator_kwarg(): |
|
357 | def test_decorator_kwarg(): | |
358 | with tt.monkeypatch(interaction, 'display', record_display): |
|
358 | with tt.monkeypatch(interaction, 'display', record_display): | |
359 | @interact(a=5) |
|
359 | @interact(a=5) | |
360 | def foo(a): |
|
360 | def foo(a): | |
361 | pass |
|
361 | pass | |
362 | nt.assert_equal(len(displayed), 1) |
|
362 | nt.assert_equal(len(displayed), 1) | |
363 | w = displayed[0].children[0] |
|
363 | w = displayed[0].children[0] | |
364 | check_widget(w, |
|
364 | check_widget(w, | |
365 | cls=widgets.IntSlider, |
|
365 | cls=widgets.IntSlider, | |
366 | value=5, |
|
366 | value=5, | |
367 | ) |
|
367 | ) | |
368 |
|
368 | |||
369 | @nt.with_setup(clear_display) |
|
369 | @nt.with_setup(clear_display) | |
370 | def test_interact_instancemethod(): |
|
370 | def test_interact_instancemethod(): | |
371 | class Foo(object): |
|
371 | class Foo(object): | |
372 | def show(self, x): |
|
372 | def show(self, x): | |
373 | print(x) |
|
373 | print(x) | |
374 |
|
374 | |||
375 | f = Foo() |
|
375 | f = Foo() | |
376 |
|
376 | |||
377 | with tt.monkeypatch(interaction, 'display', record_display): |
|
377 | with tt.monkeypatch(interaction, 'display', record_display): | |
378 | g = interact(f.show, x=(1,10)) |
|
378 | g = interact(f.show, x=(1,10)) | |
379 | nt.assert_equal(len(displayed), 1) |
|
379 | nt.assert_equal(len(displayed), 1) | |
380 | w = displayed[0].children[0] |
|
380 | w = displayed[0].children[0] | |
381 | check_widget(w, |
|
381 | check_widget(w, | |
382 | cls=widgets.IntSlider, |
|
382 | cls=widgets.IntSlider, | |
383 | value=5, |
|
383 | value=5, | |
384 | ) |
|
384 | ) | |
385 |
|
385 | |||
386 | @nt.with_setup(clear_display) |
|
386 | @nt.with_setup(clear_display) | |
387 | def test_decorator_no_call(): |
|
387 | def test_decorator_no_call(): | |
388 | with tt.monkeypatch(interaction, 'display', record_display): |
|
388 | with tt.monkeypatch(interaction, 'display', record_display): | |
389 | @interact |
|
389 | @interact | |
390 | def foo(a='default'): |
|
390 | def foo(a='default'): | |
391 | pass |
|
391 | pass | |
392 | nt.assert_equal(len(displayed), 1) |
|
392 | nt.assert_equal(len(displayed), 1) | |
393 | w = displayed[0].children[0] |
|
393 | w = displayed[0].children[0] | |
394 | check_widget(w, |
|
394 | check_widget(w, | |
395 | cls=widgets.Text, |
|
395 | cls=widgets.Text, | |
396 | value='default', |
|
396 | value='default', | |
397 | ) |
|
397 | ) | |
398 |
|
398 | |||
399 | @nt.with_setup(clear_display) |
|
399 | @nt.with_setup(clear_display) | |
400 | def test_call_interact(): |
|
400 | def test_call_interact(): | |
401 | def foo(a='default'): |
|
401 | def foo(a='default'): | |
402 | pass |
|
402 | pass | |
403 | with tt.monkeypatch(interaction, 'display', record_display): |
|
403 | with tt.monkeypatch(interaction, 'display', record_display): | |
404 | ifoo = interact(foo) |
|
404 | ifoo = interact(foo) | |
405 | nt.assert_equal(len(displayed), 1) |
|
405 | nt.assert_equal(len(displayed), 1) | |
406 | w = displayed[0].children[0] |
|
406 | w = displayed[0].children[0] | |
407 | check_widget(w, |
|
407 | check_widget(w, | |
408 | cls=widgets.Text, |
|
408 | cls=widgets.Text, | |
409 | value='default', |
|
409 | value='default', | |
410 | ) |
|
410 | ) | |
411 |
|
411 | |||
412 | @nt.with_setup(clear_display) |
|
412 | @nt.with_setup(clear_display) | |
413 | def test_call_interact_kwargs(): |
|
413 | def test_call_interact_kwargs(): | |
414 | def foo(a='default'): |
|
414 | def foo(a='default'): | |
415 | pass |
|
415 | pass | |
416 | with tt.monkeypatch(interaction, 'display', record_display): |
|
416 | with tt.monkeypatch(interaction, 'display', record_display): | |
417 | ifoo = interact(foo, a=10) |
|
417 | ifoo = interact(foo, a=10) | |
418 | nt.assert_equal(len(displayed), 1) |
|
418 | nt.assert_equal(len(displayed), 1) | |
419 | w = displayed[0].children[0] |
|
419 | w = displayed[0].children[0] | |
420 | check_widget(w, |
|
420 | check_widget(w, | |
421 | cls=widgets.IntSlider, |
|
421 | cls=widgets.IntSlider, | |
422 | value=10, |
|
422 | value=10, | |
423 | ) |
|
423 | ) | |
424 |
|
424 | |||
425 | @nt.with_setup(clear_display) |
|
425 | @nt.with_setup(clear_display) | |
426 | def test_call_decorated_on_trait_change(): |
|
426 | def test_call_decorated_on_trait_change(): | |
427 | """test calling @interact decorated functions""" |
|
427 | """test calling @interact decorated functions""" | |
428 | d = {} |
|
428 | d = {} | |
429 | with tt.monkeypatch(interaction, 'display', record_display): |
|
429 | with tt.monkeypatch(interaction, 'display', record_display): | |
430 | @interact |
|
430 | @interact | |
431 | def foo(a='default'): |
|
431 | def foo(a='default'): | |
432 | d['a'] = a |
|
432 | d['a'] = a | |
433 | return a |
|
433 | return a | |
434 | nt.assert_equal(len(displayed), 1) |
|
434 | nt.assert_equal(len(displayed), 1) | |
435 | w = displayed[0].children[0] |
|
435 | w = displayed[0].children[0] | |
436 | check_widget(w, |
|
436 | check_widget(w, | |
437 | cls=widgets.Text, |
|
437 | cls=widgets.Text, | |
438 | value='default', |
|
438 | value='default', | |
439 | ) |
|
439 | ) | |
440 | # test calling the function directly |
|
440 | # test calling the function directly | |
441 | a = foo('hello') |
|
441 | a = foo('hello') | |
442 | nt.assert_equal(a, 'hello') |
|
442 | nt.assert_equal(a, 'hello') | |
443 | nt.assert_equal(d['a'], 'hello') |
|
443 | nt.assert_equal(d['a'], 'hello') | |
444 |
|
444 | |||
445 | # test that setting trait values calls the function |
|
445 | # test that setting trait values calls the function | |
446 | w.value = 'called' |
|
446 | w.value = 'called' | |
447 | nt.assert_equal(d['a'], 'called') |
|
447 | nt.assert_equal(d['a'], 'called') | |
448 |
|
448 | |||
449 | @nt.with_setup(clear_display) |
|
449 | @nt.with_setup(clear_display) | |
450 | def test_call_decorated_kwargs_on_trait_change(): |
|
450 | def test_call_decorated_kwargs_on_trait_change(): | |
451 | """test calling @interact(foo=bar) decorated functions""" |
|
451 | """test calling @interact(foo=bar) decorated functions""" | |
452 | d = {} |
|
452 | d = {} | |
453 | with tt.monkeypatch(interaction, 'display', record_display): |
|
453 | with tt.monkeypatch(interaction, 'display', record_display): | |
454 | @interact(a='kwarg') |
|
454 | @interact(a='kwarg') | |
455 | def foo(a='default'): |
|
455 | def foo(a='default'): | |
456 | d['a'] = a |
|
456 | d['a'] = a | |
457 | return a |
|
457 | return a | |
458 | nt.assert_equal(len(displayed), 1) |
|
458 | nt.assert_equal(len(displayed), 1) | |
459 | w = displayed[0].children[0] |
|
459 | w = displayed[0].children[0] | |
460 | check_widget(w, |
|
460 | check_widget(w, | |
461 | cls=widgets.Text, |
|
461 | cls=widgets.Text, | |
462 | value='kwarg', |
|
462 | value='kwarg', | |
463 | ) |
|
463 | ) | |
464 | # test calling the function directly |
|
464 | # test calling the function directly | |
465 | a = foo('hello') |
|
465 | a = foo('hello') | |
466 | nt.assert_equal(a, 'hello') |
|
466 | nt.assert_equal(a, 'hello') | |
467 | nt.assert_equal(d['a'], 'hello') |
|
467 | nt.assert_equal(d['a'], 'hello') | |
468 |
|
468 | |||
469 | # test that setting trait values calls the function |
|
469 | # test that setting trait values calls the function | |
470 | w.value = 'called' |
|
470 | w.value = 'called' | |
471 | nt.assert_equal(d['a'], 'called') |
|
471 | nt.assert_equal(d['a'], 'called') | |
472 |
|
472 | |||
473 | def test_fixed(): |
|
473 | def test_fixed(): | |
474 | c = interactive(f, a=widgets.fixed(5), b='text') |
|
474 | c = interactive(f, a=widgets.fixed(5), b='text') | |
475 | nt.assert_equal(len(c.children), 2) |
|
475 | nt.assert_equal(len(c.children), 2) | |
476 | w = c.children[0] |
|
476 | w = c.children[0] | |
477 | check_widget(w, |
|
477 | check_widget(w, | |
478 | cls=widgets.Text, |
|
478 | cls=widgets.Text, | |
479 | value='text', |
|
479 | value='text', | |
480 | description='b', |
|
480 | description='b', | |
481 | ) |
|
481 | ) | |
482 |
|
482 | |||
483 | def test_default_description(): |
|
483 | def test_default_description(): | |
484 | c = interactive(f, b='text') |
|
484 | c = interactive(f, b='text') | |
485 | w = c.children[0] |
|
485 | w = c.children[0] | |
486 | check_widget(w, |
|
486 | check_widget(w, | |
487 | cls=widgets.Text, |
|
487 | cls=widgets.Text, | |
488 | value='text', |
|
488 | value='text', | |
489 | description='b', |
|
489 | description='b', | |
490 | ) |
|
490 | ) | |
491 |
|
491 | |||
492 | def test_custom_description(): |
|
492 | def test_custom_description(): | |
493 | d = {} |
|
493 | d = {} | |
494 | def record_kwargs(**kwargs): |
|
494 | def record_kwargs(**kwargs): | |
495 | d.clear() |
|
495 | d.clear() | |
496 | d.update(kwargs) |
|
496 | d.update(kwargs) | |
497 |
|
497 | |||
498 | c = interactive(record_kwargs, b=widgets.Text(value='text', description='foo')) |
|
498 | c = interactive(record_kwargs, b=widgets.Text(value='text', description='foo')) | |
499 | w = c.children[0] |
|
499 | w = c.children[0] | |
500 | check_widget(w, |
|
500 | check_widget(w, | |
501 | cls=widgets.Text, |
|
501 | cls=widgets.Text, | |
502 | value='text', |
|
502 | value='text', | |
503 | description='foo', |
|
503 | description='foo', | |
504 | ) |
|
504 | ) | |
505 | w.value = 'different text' |
|
505 | w.value = 'different text' | |
506 | nt.assert_equal(d, {'b': 'different text'}) |
|
506 | nt.assert_equal(d, {'b': 'different text'}) | |
507 |
|
507 | |||
508 | def test_interact_manual_button(): |
|
508 | def test_interact_manual_button(): | |
509 | c = interactive(f, __manual=True) |
|
509 | c = interactive(f, __manual=True) | |
510 | w = c.children[0] |
|
510 | w = c.children[0] | |
511 | check_widget(w, cls=widgets.Button) |
|
511 | check_widget(w, cls=widgets.Button) | |
512 |
|
512 | |||
513 | def test_interact_manual_nocall(): |
|
513 | def test_interact_manual_nocall(): | |
514 | callcount = 0 |
|
514 | callcount = 0 | |
515 | def calltest(testarg): |
|
515 | def calltest(testarg): | |
516 | callcount += 1 |
|
516 | callcount += 1 | |
517 | c = interactive(calltest, testarg=5, __manual=True) |
|
517 | c = interactive(calltest, testarg=5, __manual=True) | |
518 | c.children[0].value = 10 |
|
518 | c.children[0].value = 10 | |
519 | nt.assert_equal(callcount, 0) |
|
519 | nt.assert_equal(callcount, 0) | |
520 |
|
520 | |||
521 | def test_int_range_logic(): |
|
521 | def test_int_range_logic(): | |
522 | irsw = widgets.IntRangeSlider |
|
522 | irsw = widgets.IntRangeSlider | |
523 | w = irsw(value=(2, 4), min=0, max=6) |
|
523 | w = irsw(value=(2, 4), min=0, max=6) | |
524 | check_widget(w, cls=irsw, value=(2, 4), min=0, max=6) |
|
524 | check_widget(w, cls=irsw, value=(2, 4), min=0, max=6) | |
525 | w.value = (4, 2) |
|
525 | w.value = (4, 2) | |
526 | check_widget(w, cls=irsw, value=(2, 4), min=0, max=6) |
|
526 | check_widget(w, cls=irsw, value=(2, 4), min=0, max=6) | |
527 | w.value = (-1, 7) |
|
527 | w.value = (-1, 7) | |
528 | check_widget(w, cls=irsw, value=(0, 6), min=0, max=6) |
|
528 | check_widget(w, cls=irsw, value=(0, 6), min=0, max=6) | |
529 | w.min = 3 |
|
529 | w.min = 3 | |
530 | check_widget(w, cls=irsw, value=(3, 6), min=3, max=6) |
|
530 | check_widget(w, cls=irsw, value=(3, 6), min=3, max=6) | |
531 | w.max = 3 |
|
531 | w.max = 3 | |
532 | check_widget(w, cls=irsw, value=(3, 3), min=3, max=3) |
|
532 | check_widget(w, cls=irsw, value=(3, 3), min=3, max=3) | |
533 |
|
533 | |||
534 | w.min = 0 |
|
534 | w.min = 0 | |
535 | w.max = 6 |
|
535 | w.max = 6 | |
536 | w.lower = 2 |
|
536 | w.lower = 2 | |
537 | w.upper = 4 |
|
537 | w.upper = 4 | |
538 | check_widget(w, cls=irsw, value=(2, 4), min=0, max=6) |
|
538 | check_widget(w, cls=irsw, value=(2, 4), min=0, max=6) | |
539 | w.value = (0, 1) #lower non-overlapping range |
|
539 | w.value = (0, 1) #lower non-overlapping range | |
540 | check_widget(w, cls=irsw, value=(0, 1), min=0, max=6) |
|
540 | check_widget(w, cls=irsw, value=(0, 1), min=0, max=6) | |
541 | w.value = (5, 6) #upper non-overlapping range |
|
541 | w.value = (5, 6) #upper non-overlapping range | |
542 | check_widget(w, cls=irsw, value=(5, 6), min=0, max=6) |
|
542 | check_widget(w, cls=irsw, value=(5, 6), min=0, max=6) | |
543 | w.value = (-1, 4) #semi out-of-range |
|
543 | w.value = (-1, 4) #semi out-of-range | |
544 | check_widget(w, cls=irsw, value=(0, 4), min=0, max=6) |
|
544 | check_widget(w, cls=irsw, value=(0, 4), min=0, max=6) | |
545 | w.lower = 2 |
|
545 | w.lower = 2 | |
546 | check_widget(w, cls=irsw, value=(2, 4), min=0, max=6) |
|
546 | check_widget(w, cls=irsw, value=(2, 4), min=0, max=6) | |
547 | w.value = (-2, -1) #wholly out of range |
|
547 | w.value = (-2, -1) #wholly out of range | |
548 | check_widget(w, cls=irsw, value=(0, 0), min=0, max=6) |
|
548 | check_widget(w, cls=irsw, value=(0, 0), min=0, max=6) | |
549 | w.value = (7, 8) |
|
549 | w.value = (7, 8) | |
550 | check_widget(w, cls=irsw, value=(6, 6), min=0, max=6) |
|
550 | check_widget(w, cls=irsw, value=(6, 6), min=0, max=6) | |
551 |
|
551 | |||
552 | with nt.assert_raises(ValueError): |
|
552 | with nt.assert_raises(ValueError): | |
553 | w.min = 7 |
|
553 | w.min = 7 | |
554 | with nt.assert_raises(ValueError): |
|
554 | with nt.assert_raises(ValueError): | |
555 | w.max = -1 |
|
555 | w.max = -1 | |
556 | with nt.assert_raises(ValueError): |
|
556 | with nt.assert_raises(ValueError): | |
557 | w.lower = 5 |
|
557 | w.lower = 5 | |
558 | with nt.assert_raises(ValueError): |
|
558 | with nt.assert_raises(ValueError): | |
559 | w.upper = 1 |
|
559 | w.upper = 1 | |
560 |
|
560 | |||
561 | w = irsw(min=2, max=3) |
|
561 | w = irsw(min=2, max=3) | |
562 | check_widget(w, min=2, max=3) |
|
562 | check_widget(w, min=2, max=3) | |
563 | w = irsw(min=100, max=200) |
|
563 | w = irsw(min=100, max=200) | |
564 | check_widget(w, lower=125, upper=175, value=(125, 175)) |
|
564 | check_widget(w, lower=125, upper=175, value=(125, 175)) | |
565 |
|
565 | |||
566 | with nt.assert_raises(ValueError): |
|
566 | with nt.assert_raises(ValueError): | |
567 | irsw(value=(2, 4), lower=3) |
|
567 | irsw(value=(2, 4), lower=3) | |
568 | with nt.assert_raises(ValueError): |
|
568 | with nt.assert_raises(ValueError): | |
569 | irsw(value=(2, 4), upper=3) |
|
569 | irsw(value=(2, 4), upper=3) | |
570 | with nt.assert_raises(ValueError): |
|
570 | with nt.assert_raises(ValueError): | |
571 | irsw(value=(2, 4), lower=3, upper=3) |
|
571 | irsw(value=(2, 4), lower=3, upper=3) | |
572 | with nt.assert_raises(ValueError): |
|
572 | with nt.assert_raises(ValueError): | |
573 | irsw(min=2, max=1) |
|
573 | irsw(min=2, max=1) | |
574 | with nt.assert_raises(ValueError): |
|
574 | with nt.assert_raises(ValueError): | |
575 | irsw(lower=5) |
|
575 | irsw(lower=5) | |
576 | with nt.assert_raises(ValueError): |
|
576 | with nt.assert_raises(ValueError): | |
577 | irsw(upper=5) |
|
577 | irsw(upper=5) | |
578 |
|
578 | |||
579 |
|
579 | |||
580 | def test_float_range_logic(): |
|
580 | def test_float_range_logic(): | |
581 | frsw = widgets.FloatRangeSlider |
|
581 | frsw = widgets.FloatRangeSlider | |
582 | w = frsw(value=(.2, .4), min=0., max=.6) |
|
582 | w = frsw(value=(.2, .4), min=0., max=.6) | |
583 | check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6) |
|
583 | check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6) | |
584 | w.value = (.4, .2) |
|
584 | w.value = (.4, .2) | |
585 | check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6) |
|
585 | check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6) | |
586 | w.value = (-.1, .7) |
|
586 | w.value = (-.1, .7) | |
587 | check_widget(w, cls=frsw, value=(0., .6), min=0., max=.6) |
|
587 | check_widget(w, cls=frsw, value=(0., .6), min=0., max=.6) | |
588 | w.min = .3 |
|
588 | w.min = .3 | |
589 | check_widget(w, cls=frsw, value=(.3, .6), min=.3, max=.6) |
|
589 | check_widget(w, cls=frsw, value=(.3, .6), min=.3, max=.6) | |
590 | w.max = .3 |
|
590 | w.max = .3 | |
591 | check_widget(w, cls=frsw, value=(.3, .3), min=.3, max=.3) |
|
591 | check_widget(w, cls=frsw, value=(.3, .3), min=.3, max=.3) | |
592 |
|
592 | |||
593 | w.min = 0. |
|
593 | w.min = 0. | |
594 | w.max = .6 |
|
594 | w.max = .6 | |
595 | w.lower = .2 |
|
595 | w.lower = .2 | |
596 | w.upper = .4 |
|
596 | w.upper = .4 | |
597 | check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6) |
|
597 | check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6) | |
598 | w.value = (0., .1) #lower non-overlapping range |
|
598 | w.value = (0., .1) #lower non-overlapping range | |
599 | check_widget(w, cls=frsw, value=(0., .1), min=0., max=.6) |
|
599 | check_widget(w, cls=frsw, value=(0., .1), min=0., max=.6) | |
600 | w.value = (.5, .6) #upper non-overlapping range |
|
600 | w.value = (.5, .6) #upper non-overlapping range | |
601 | check_widget(w, cls=frsw, value=(.5, .6), min=0., max=.6) |
|
601 | check_widget(w, cls=frsw, value=(.5, .6), min=0., max=.6) | |
602 | w.value = (-.1, .4) #semi out-of-range |
|
602 | w.value = (-.1, .4) #semi out-of-range | |
603 | check_widget(w, cls=frsw, value=(0., .4), min=0., max=.6) |
|
603 | check_widget(w, cls=frsw, value=(0., .4), min=0., max=.6) | |
604 | w.lower = .2 |
|
604 | w.lower = .2 | |
605 | check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6) |
|
605 | check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6) | |
606 | w.value = (-.2, -.1) #wholly out of range |
|
606 | w.value = (-.2, -.1) #wholly out of range | |
607 | check_widget(w, cls=frsw, value=(0., 0.), min=0., max=.6) |
|
607 | check_widget(w, cls=frsw, value=(0., 0.), min=0., max=.6) | |
608 | w.value = (.7, .8) |
|
608 | w.value = (.7, .8) | |
609 | check_widget(w, cls=frsw, value=(.6, .6), min=.0, max=.6) |
|
609 | check_widget(w, cls=frsw, value=(.6, .6), min=.0, max=.6) | |
610 |
|
610 | |||
611 | with nt.assert_raises(ValueError): |
|
611 | with nt.assert_raises(ValueError): | |
612 | w.min = .7 |
|
612 | w.min = .7 | |
613 | with nt.assert_raises(ValueError): |
|
613 | with nt.assert_raises(ValueError): | |
614 | w.max = -.1 |
|
614 | w.max = -.1 | |
615 | with nt.assert_raises(ValueError): |
|
615 | with nt.assert_raises(ValueError): | |
616 | w.lower = .5 |
|
616 | w.lower = .5 | |
617 | with nt.assert_raises(ValueError): |
|
617 | with nt.assert_raises(ValueError): | |
618 | w.upper = .1 |
|
618 | w.upper = .1 | |
619 |
|
619 | |||
620 | w = frsw(min=2, max=3) |
|
620 | w = frsw(min=2, max=3) | |
621 | check_widget(w, min=2, max=3) |
|
621 | check_widget(w, min=2, max=3) | |
622 | w = frsw(min=1., max=2.) |
|
622 | w = frsw(min=1., max=2.) | |
623 | check_widget(w, lower=1.25, upper=1.75, value=(1.25, 1.75)) |
|
623 | check_widget(w, lower=1.25, upper=1.75, value=(1.25, 1.75)) | |
624 |
|
624 | |||
625 | with nt.assert_raises(ValueError): |
|
625 | with nt.assert_raises(ValueError): | |
626 | frsw(value=(2, 4), lower=3) |
|
626 | frsw(value=(2, 4), lower=3) | |
627 | with nt.assert_raises(ValueError): |
|
627 | with nt.assert_raises(ValueError): | |
628 | frsw(value=(2, 4), upper=3) |
|
628 | frsw(value=(2, 4), upper=3) | |
629 | with nt.assert_raises(ValueError): |
|
629 | with nt.assert_raises(ValueError): | |
630 | frsw(value=(2, 4), lower=3, upper=3) |
|
630 | frsw(value=(2, 4), lower=3, upper=3) | |
631 | with nt.assert_raises(ValueError): |
|
631 | with nt.assert_raises(ValueError): | |
632 | frsw(min=.2, max=.1) |
|
632 | frsw(min=.2, max=.1) | |
633 | with nt.assert_raises(ValueError): |
|
633 | with nt.assert_raises(ValueError): | |
634 | frsw(lower=5) |
|
634 | frsw(lower=5) | |
635 | with nt.assert_raises(ValueError): |
|
635 | with nt.assert_raises(ValueError): | |
636 | frsw(upper=5) |
|
636 | frsw(upper=5) | |
|
637 | ||||
|
638 | ||||
|
639 | def test_multiple_selection(): | |||
|
640 | smw = widgets.SelectMultiple | |||
|
641 | ||||
|
642 | # degenerate multiple select | |||
|
643 | w = smw() | |||
|
644 | check_widget(w, value=tuple(), options=None, selected_labels=tuple()) | |||
|
645 | ||||
|
646 | # don't accept random other value when no options | |||
|
647 | with nt.assert_raises(KeyError): | |||
|
648 | w.value = (2,) | |||
|
649 | check_widget(w, value=tuple(), selected_labels=tuple()) | |||
|
650 | ||||
|
651 | # basic multiple select | |||
|
652 | w = smw(options=[(1, 1)], value=[1]) | |||
|
653 | check_widget(w, cls=smw, value=(1,), options=[(1, 1)]) | |||
|
654 | ||||
|
655 | # don't accept random other value | |||
|
656 | with nt.assert_raises(KeyError): | |||
|
657 | w.value = w.value + (2,) | |||
|
658 | check_widget(w, value=(1,), selected_labels=(1,)) | |||
|
659 | ||||
|
660 | # change options | |||
|
661 | w.options = w.options + [(2, 2)] | |||
|
662 | check_widget(w, options=[(1, 1), (2,2)]) | |||
|
663 | ||||
|
664 | # change value | |||
|
665 | w.value = w.value + (2,) | |||
|
666 | check_widget(w, value=(1, 2), selected_labels=(1, 2)) | |||
|
667 | ||||
|
668 | # change value name | |||
|
669 | w.selected_labels = (1,) | |||
|
670 | check_widget(w, value=(1,)) | |||
|
671 | ||||
|
672 | # don't accept random other names when no options | |||
|
673 | with nt.assert_raises(KeyError): | |||
|
674 | w.selected_labels = (3,) | |||
|
675 | check_widget(w, value=(1,)) | |||
|
676 | ||||
|
677 | # don't accept selected_label (from superclass) | |||
|
678 | with nt.assert_raises(AttributeError): | |||
|
679 | w.selected_label = 3 | |||
|
680 | ||||
|
681 | # don't return selected_label (from superclass) | |||
|
682 | with nt.assert_raises(AttributeError): | |||
|
683 | print(w.selected_label) | |||
|
684 | ||||
|
685 | # dict style | |||
|
686 | w.options = {1: 1} | |||
|
687 | check_widget(w, options={1: 1}) | |||
|
688 | ||||
|
689 | # updating | |||
|
690 | with nt.assert_raises(KeyError): | |||
|
691 | w.value = (2,) | |||
|
692 | check_widget(w, options={1: 1}) |
@@ -1,172 +1,238 b'' | |||||
1 | """Selection classes. |
|
1 | """Selection classes. | |
2 |
|
2 | |||
3 | Represents an enumeration using a widget. |
|
3 | Represents an enumeration 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 |
|
16 | |||
17 | from collections import OrderedDict |
|
17 | from collections import OrderedDict | |
18 | from threading import Lock |
|
18 | from threading import Lock | |
19 |
|
19 | |||
20 | from .widget import DOMWidget, register |
|
20 | from .widget import DOMWidget, register | |
21 | from IPython.utils.traitlets import ( |
|
21 | from IPython.utils.traitlets import ( | |
22 | Unicode, Bool, Any, Dict, TraitError, CaselessStrEnum, Tuple |
|
22 | Unicode, Bool, Any, Dict, TraitError, CaselessStrEnum, Tuple | |
23 | ) |
|
23 | ) | |
24 | from IPython.utils.py3compat import unicode_type |
|
24 | from IPython.utils.py3compat import unicode_type | |
25 | from IPython.utils.warn import DeprecatedClass |
|
25 | from IPython.utils.warn import DeprecatedClass | |
26 |
|
26 | |||
27 | #----------------------------------------------------------------------------- |
|
27 | #----------------------------------------------------------------------------- | |
28 | # SelectionWidget |
|
28 | # SelectionWidget | |
29 | #----------------------------------------------------------------------------- |
|
29 | #----------------------------------------------------------------------------- | |
30 | class _Selection(DOMWidget): |
|
30 | class _Selection(DOMWidget): | |
31 | """Base class for Selection widgets |
|
31 | """Base class for Selection widgets | |
32 |
|
32 | |||
33 |
`` |
|
33 | ``options`` can be specified as a list or dict. If given as a list, | |
34 | it will be transformed to a dict of the form ``{str(value):value}``. |
|
34 | it will be transformed to a dict of the form ``{str(value):value}``. | |
35 | """ |
|
35 | """ | |
36 |
|
36 | |||
37 | value = Any(help="Selected value") |
|
37 | value = Any(help="Selected value") | |
38 |
|
|
38 | selected_label = Unicode(help="The label of the selected value", sync=True) | |
39 |
|
|
39 | options = Any(help="""List of (key, value) tuples or dict of values that the | |
40 | user can select. |
|
40 | user can select. | |
41 |
|
41 | |||
42 | The keys of this list are the strings that will be displayed in the UI, |
|
42 | The keys of this list are the strings that will be displayed in the UI, | |
43 | representing the actual Python choices. |
|
43 | representing the actual Python choices. | |
44 |
|
44 | |||
45 |
The keys of this list are also available as _ |
|
45 | The keys of this list are also available as _options_labels. | |
46 | """) |
|
46 | """) | |
47 |
|
47 | |||
48 |
_ |
|
48 | _options_dict = Dict() | |
49 |
_ |
|
49 | _options_labels = Tuple(sync=True) | |
50 |
_ |
|
50 | _options_values = Tuple() | |
51 |
|
51 | |||
52 | disabled = Bool(False, help="Enable or disable user changes", sync=True) |
|
52 | disabled = Bool(False, help="Enable or disable user changes", sync=True) | |
53 | description = Unicode(help="Description of the value this widget represents", sync=True) |
|
53 | description = Unicode(help="Description of the value this widget represents", sync=True) | |
54 |
|
54 | |||
55 | def __init__(self, *args, **kwargs): |
|
55 | def __init__(self, *args, **kwargs): | |
56 | self.value_lock = Lock() |
|
56 | self.value_lock = Lock() | |
57 |
self. |
|
57 | self.options_lock = Lock() | |
58 |
self.on_trait_change(self._ |
|
58 | self.on_trait_change(self._options_readonly_changed, ['_options_dict', '_options_labels', '_options_values', '_options']) | |
59 |
if ' |
|
59 | if 'options' in kwargs: | |
60 |
self. |
|
60 | self.options = kwargs.pop('options') | |
61 | DOMWidget.__init__(self, *args, **kwargs) |
|
61 | DOMWidget.__init__(self, *args, **kwargs) | |
62 |
self._value_in_ |
|
62 | self._value_in_options() | |
63 |
|
63 | |||
64 |
def _make_ |
|
64 | def _make_options(self, x): | |
65 | # If x is a dict, convert it to list format. |
|
65 | # If x is a dict, convert it to list format. | |
66 | if isinstance(x, (OrderedDict, dict)): |
|
66 | if isinstance(x, (OrderedDict, dict)): | |
67 | return [(k, v) for k, v in x.items()] |
|
67 | return [(k, v) for k, v in x.items()] | |
68 |
|
68 | |||
69 | # Make sure x is a list or tuple. |
|
69 | # Make sure x is a list or tuple. | |
70 | if not isinstance(x, (list, tuple)): |
|
70 | if not isinstance(x, (list, tuple)): | |
71 | raise ValueError('x') |
|
71 | raise ValueError('x') | |
72 |
|
72 | |||
73 | # If x is an ordinary list, use the values as names. |
|
73 | # If x is an ordinary list, use the option values as names. | |
74 | for y in x: |
|
74 | for y in x: | |
75 | if not isinstance(y, (list, tuple)) or len(y) < 2: |
|
75 | if not isinstance(y, (list, tuple)) or len(y) < 2: | |
76 | return [(i, i) for i in x] |
|
76 | return [(i, i) for i in x] | |
77 |
|
77 | |||
78 | # Value is already in the correct format. |
|
78 | # Value is already in the correct format. | |
79 | return x |
|
79 | return x | |
80 |
|
80 | |||
81 |
def _ |
|
81 | def _options_changed(self, name, old, new): | |
82 |
"""Handles when the |
|
82 | """Handles when the options tuple has been changed. | |
83 |
|
83 | |||
84 |
Setting |
|
84 | Setting options implies setting option labels from the keys of the dict. | |
85 |
""" |
|
85 | """ | |
86 |
if self. |
|
86 | if self.options_lock.acquire(False): | |
87 | try: |
|
87 | try: | |
88 |
self. |
|
88 | self.options = new | |
89 |
|
89 | |||
90 |
|
|
90 | options = self._make_options(new) | |
91 |
self._ |
|
91 | self._options_dict = {i[0]: i[1] for i in options} | |
92 |
self._ |
|
92 | self._options_labels = [i[0] for i in options] | |
93 |
self._ |
|
93 | self._options_values = [i[1] for i in options] | |
94 |
self._value_in_ |
|
94 | self._value_in_options() | |
95 | finally: |
|
95 | finally: | |
96 |
self. |
|
96 | self.options_lock.release() | |
97 |
|
97 | |||
98 |
def _value_in_ |
|
98 | def _value_in_options(self): | |
99 | # ensure that the chosen value is one of the choices |
|
99 | # ensure that the chosen value is one of the choices | |
100 | if self._value_values: |
|
|||
101 | if self.value not in self._value_values: |
|
|||
102 | self.value = next(iter(self._value_values)) |
|
|||
103 |
|
100 | |||
104 | def _values_readonly_changed(self, name, old, new): |
|
101 | if self._options_values: | |
105 | if not self.values_lock.locked(): |
|
102 | if self.value not in self._options_values: | |
106 | raise TraitError("`.%s` is a read-only trait. Use the `.values` tuple instead." % name) |
|
103 | self.value = next(iter(self._options_values)) | |
107 |
|
104 | |||
|
105 | def _options_readonly_changed(self, name, old, new): | |||
|
106 | if not self.options_lock.locked(): | |||
|
107 | raise TraitError("`.%s` is a read-only trait. Use the `.options` tuple instead." % name) | |||
108 | def _value_changed(self, name, old, new): |
|
108 | def _value_changed(self, name, old, new): | |
109 | """Called when value has been changed""" |
|
109 | """Called when value has been changed""" | |
110 | if self.value_lock.acquire(False): |
|
110 | if self.value_lock.acquire(False): | |
111 | try: |
|
111 | try: | |
112 | # Reverse dictionary lookup for the value name |
|
112 | # Reverse dictionary lookup for the value name | |
113 |
for k,v in self._ |
|
113 | for k, v in self._options_dict.items(): | |
114 | if new == v: |
|
114 | if new == v: | |
115 | # set the selected value name |
|
115 | # set the selected value name | |
116 |
self. |
|
116 | self.selected_label = k | |
117 | return |
|
117 | return | |
118 | # undo the change, and raise KeyError |
|
118 | # undo the change, and raise KeyError | |
119 | self.value = old |
|
119 | self.value = old | |
120 | raise KeyError(new) |
|
120 | raise KeyError(new) | |
121 | finally: |
|
121 | finally: | |
122 | self.value_lock.release() |
|
122 | self.value_lock.release() | |
123 |
|
123 | |||
124 |
def _ |
|
124 | def _selected_label_changed(self, name, old, new): | |
125 | """Called when the value name has been changed (typically by the frontend).""" |
|
125 | """Called when the value name has been changed (typically by the frontend).""" | |
126 | if self.value_lock.acquire(False): |
|
126 | if self.value_lock.acquire(False): | |
127 | try: |
|
127 | try: | |
128 |
self.value = self._ |
|
128 | self.value = self._options_dict[new] | |
|
129 | finally: | |||
|
130 | self.value_lock.release() | |||
|
131 | ||||
|
132 | ||||
|
133 | class _MultipleSelection(_Selection): | |||
|
134 | """Base class for MultipleSelection widgets. | |||
|
135 | ||||
|
136 | As with ``_Selection``, ``options`` can be specified as a list or dict. If | |||
|
137 | given as a list, it will be transformed to a dict of the form | |||
|
138 | ``{str(value): value}``. | |||
|
139 | ||||
|
140 | Despite their names, ``value`` (and ``selected_label``) will be tuples, even | |||
|
141 | if only a single option is selected. | |||
|
142 | """ | |||
|
143 | ||||
|
144 | value = Tuple(help="Selected values") | |||
|
145 | selected_labels = Tuple(help="The labels of the selected options", | |||
|
146 | sync=True) | |||
|
147 | ||||
|
148 | @property | |||
|
149 | def selected_label(self): | |||
|
150 | raise AttributeError( | |||
|
151 | "Does not support selected_label, use selected_labels") | |||
|
152 | ||||
|
153 | def _value_in_options(self): | |||
|
154 | # ensure that the chosen value is one of the choices | |||
|
155 | if self.options: | |||
|
156 | old_value = self.value or [] | |||
|
157 | new_value = [] | |||
|
158 | for value in old_value: | |||
|
159 | if value in self._options_dict.values(): | |||
|
160 | new_value.append(value) | |||
|
161 | if new_value: | |||
|
162 | self.value = new_value | |||
|
163 | else: | |||
|
164 | self.value = [next(iter(self._options_dict.values()))] | |||
|
165 | ||||
|
166 | def _value_changed(self, name, old, new): | |||
|
167 | """Called when value has been changed""" | |||
|
168 | if self.value_lock.acquire(False): | |||
|
169 | try: | |||
|
170 | self.selected_labels = [ | |||
|
171 | self._options_labels[self._options_values.index(v)] | |||
|
172 | for v in new | |||
|
173 | ] | |||
|
174 | except: | |||
|
175 | self.value = old | |||
|
176 | raise KeyError(new) | |||
|
177 | finally: | |||
|
178 | self.value_lock.release() | |||
|
179 | ||||
|
180 | def _selected_labels_changed(self, name, old, new): | |||
|
181 | """Called when the selected label has been changed (typically by the | |||
|
182 | frontend).""" | |||
|
183 | if self.value_lock.acquire(False): | |||
|
184 | try: | |||
|
185 | self.value = [self._options_dict[name] for name in new] | |||
129 | finally: |
|
186 | finally: | |
130 | self.value_lock.release() |
|
187 | self.value_lock.release() | |
131 |
|
188 | |||
132 |
|
189 | |||
133 | @register('IPython.ToggleButtons') |
|
190 | @register('IPython.ToggleButtons') | |
134 | class ToggleButtons(_Selection): |
|
191 | class ToggleButtons(_Selection): | |
135 | """Group of toggle buttons that represent an enumeration. Only one toggle |
|
192 | """Group of toggle buttons that represent an enumeration. Only one toggle | |
136 | button can be toggled at any point in time.""" |
|
193 | button can be toggled at any point in time.""" | |
137 | _view_name = Unicode('ToggleButtonsView', sync=True) |
|
194 | _view_name = Unicode('ToggleButtonsView', sync=True) | |
138 |
|
195 | |||
139 | button_style = CaselessStrEnum( |
|
196 | button_style = CaselessStrEnum( | |
140 | values=['primary', 'success', 'info', 'warning', 'danger', ''], |
|
197 | values=['primary', 'success', 'info', 'warning', 'danger', ''], | |
141 | default_value='', allow_none=True, sync=True, help="""Use a |
|
198 | default_value='', allow_none=True, sync=True, help="""Use a | |
142 | predefined styling for the buttons.""") |
|
199 | predefined styling for the buttons.""") | |
143 |
|
200 | |||
144 | @register('IPython.Dropdown') |
|
201 | @register('IPython.Dropdown') | |
145 | class Dropdown(_Selection): |
|
202 | class Dropdown(_Selection): | |
146 | """Allows you to select a single item from a dropdown.""" |
|
203 | """Allows you to select a single item from a dropdown.""" | |
147 | _view_name = Unicode('DropdownView', sync=True) |
|
204 | _view_name = Unicode('DropdownView', sync=True) | |
148 |
|
205 | |||
149 | button_style = CaselessStrEnum( |
|
206 | button_style = CaselessStrEnum( | |
150 | values=['primary', 'success', 'info', 'warning', 'danger', ''], |
|
207 | values=['primary', 'success', 'info', 'warning', 'danger', ''], | |
151 | default_value='', allow_none=True, sync=True, help="""Use a |
|
208 | default_value='', allow_none=True, sync=True, help="""Use a | |
152 | predefined styling for the buttons.""") |
|
209 | predefined styling for the buttons.""") | |
153 |
|
210 | |||
154 | @register('IPython.RadioButtons') |
|
211 | @register('IPython.RadioButtons') | |
155 | class RadioButtons(_Selection): |
|
212 | class RadioButtons(_Selection): | |
156 | """Group of radio buttons that represent an enumeration. Only one radio |
|
213 | """Group of radio buttons that represent an enumeration. Only one radio | |
157 | button can be toggled at any point in time.""" |
|
214 | button can be toggled at any point in time.""" | |
158 | _view_name = Unicode('RadioButtonsView', sync=True) |
|
215 | _view_name = Unicode('RadioButtonsView', sync=True) | |
159 |
|
216 | |||
160 |
|
217 | |||
161 |
|
218 | |||
162 | @register('IPython.Select') |
|
219 | @register('IPython.Select') | |
163 | class Select(_Selection): |
|
220 | class Select(_Selection): | |
164 | """Listbox that only allows one item to be selected at any given time.""" |
|
221 | """Listbox that only allows one item to be selected at any given time.""" | |
165 | _view_name = Unicode('SelectView', sync=True) |
|
222 | _view_name = Unicode('SelectView', sync=True) | |
166 |
|
223 | |||
167 |
|
224 | |||
|
225 | @register('IPython.SelectMultiple') | |||
|
226 | class SelectMultiple(_MultipleSelection): | |||
|
227 | """Listbox that allows many items to be selected at any given time. | |||
|
228 | Despite their names, inherited from ``_Selection``, the currently chosen | |||
|
229 | option values, ``value``, or their labels, ``selected_labels`` must both be | |||
|
230 | updated with a list-like object.""" | |||
|
231 | _view_name = Unicode('SelectMultipleView', sync=True) | |||
|
232 | ||||
|
233 | ||||
168 | # Remove in IPython 4.0 |
|
234 | # Remove in IPython 4.0 | |
169 | ToggleButtonsWidget = DeprecatedClass(ToggleButtons, 'ToggleButtonsWidget') |
|
235 | ToggleButtonsWidget = DeprecatedClass(ToggleButtons, 'ToggleButtonsWidget') | |
170 | DropdownWidget = DeprecatedClass(Dropdown, 'DropdownWidget') |
|
236 | DropdownWidget = DeprecatedClass(Dropdown, 'DropdownWidget') | |
171 | RadioButtonsWidget = DeprecatedClass(RadioButtons, 'RadioButtonsWidget') |
|
237 | RadioButtonsWidget = DeprecatedClass(RadioButtons, 'RadioButtonsWidget') | |
172 | SelectWidget = DeprecatedClass(Select, 'SelectWidget') |
|
238 | SelectWidget = DeprecatedClass(Select, 'SelectWidget') |
@@ -1,176 +1,176 b'' | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "code", |
|
4 | "cell_type": "code", | |
5 | "execution_count": null, |
|
5 | "execution_count": null, | |
6 | "metadata": { |
|
6 | "metadata": { | |
7 | "collapsed": false |
|
7 | "collapsed": false | |
8 | }, |
|
8 | }, | |
9 | "outputs": [], |
|
9 | "outputs": [], | |
10 | "source": [ |
|
10 | "source": [ | |
11 | "# Widget related imports\n", |
|
11 | "# Widget related imports\n", | |
12 | "from IPython.html import widgets\n", |
|
12 | "from IPython.html import widgets\n", | |
13 | "from IPython.display import display, clear_output, Javascript\n", |
|
13 | "from IPython.display import display, clear_output, Javascript\n", | |
14 | "from IPython.utils.traitlets import Unicode\n", |
|
14 | "from IPython.utils.traitlets import Unicode\n", | |
15 | "\n", |
|
15 | "\n", | |
16 | "# nbconvert related imports\n", |
|
16 | "# nbconvert related imports\n", | |
17 | "from IPython.nbconvert import get_export_names, export_by_name\n", |
|
17 | "from IPython.nbconvert import get_export_names, export_by_name\n", | |
18 | "from IPython.nbconvert.writers import FilesWriter\n", |
|
18 | "from IPython.nbconvert.writers import FilesWriter\n", | |
19 | "from IPython.nbformat import current\n", |
|
19 | "from IPython.nbformat import current\n", | |
20 | "from IPython.nbconvert.utils.exceptions import ConversionException" |
|
20 | "from IPython.nbconvert.utils.exceptions import ConversionException" | |
21 | ] |
|
21 | ] | |
22 | }, |
|
22 | }, | |
23 | { |
|
23 | { | |
24 | "cell_type": "markdown", |
|
24 | "cell_type": "markdown", | |
25 | "metadata": {}, |
|
25 | "metadata": {}, | |
26 | "source": [ |
|
26 | "source": [ | |
27 | "Create a text Widget without displaying it. The widget will be used to store the notebook's name which is otherwise only available in the front-end." |
|
27 | "Create a text Widget without displaying it. The widget will be used to store the notebook's name which is otherwise only available in the front-end." | |
28 | ] |
|
28 | ] | |
29 | }, |
|
29 | }, | |
30 | { |
|
30 | { | |
31 | "cell_type": "code", |
|
31 | "cell_type": "code", | |
32 | "execution_count": null, |
|
32 | "execution_count": null, | |
33 | "metadata": { |
|
33 | "metadata": { | |
34 | "collapsed": false |
|
34 | "collapsed": false | |
35 | }, |
|
35 | }, | |
36 | "outputs": [], |
|
36 | "outputs": [], | |
37 | "source": [ |
|
37 | "source": [ | |
38 | "notebook_name = widgets.Text()" |
|
38 | "notebook_name = widgets.Text()" | |
39 | ] |
|
39 | ] | |
40 | }, |
|
40 | }, | |
41 | { |
|
41 | { | |
42 | "cell_type": "markdown", |
|
42 | "cell_type": "markdown", | |
43 | "metadata": {}, |
|
43 | "metadata": {}, | |
44 | "source": [ |
|
44 | "source": [ | |
45 | "Get the current notebook's name by pushing JavaScript to the browser that sets the notebook name in a string widget." |
|
45 | "Get the current notebook's name by pushing JavaScript to the browser that sets the notebook name in a string widget." | |
46 | ] |
|
46 | ] | |
47 | }, |
|
47 | }, | |
48 | { |
|
48 | { | |
49 | "cell_type": "code", |
|
49 | "cell_type": "code", | |
50 | "execution_count": null, |
|
50 | "execution_count": null, | |
51 | "metadata": { |
|
51 | "metadata": { | |
52 | "collapsed": false |
|
52 | "collapsed": false | |
53 | }, |
|
53 | }, | |
54 | "outputs": [], |
|
54 | "outputs": [], | |
55 | "source": [ |
|
55 | "source": [ | |
56 | "js = \"\"\"var model = IPython.notebook.kernel.widget_manager.get_model('{model_id}');\n", |
|
56 | "js = \"\"\"var model = IPython.notebook.kernel.widget_manager.get_model('{model_id}');\n", | |
57 | "model.set('value', IPython.notebook.notebook_name);\n", |
|
57 | "model.set('value', IPython.notebook.notebook_name);\n", | |
58 | "model.save();\"\"\".format(model_id=notebook_name.model_id)\n", |
|
58 | "model.save();\"\"\".format(model_id=notebook_name.model_id)\n", | |
59 | "display(Javascript(data=js))" |
|
59 | "display(Javascript(data=js))" | |
60 | ] |
|
60 | ] | |
61 | }, |
|
61 | }, | |
62 | { |
|
62 | { | |
63 | "cell_type": "code", |
|
63 | "cell_type": "code", | |
64 | "execution_count": null, |
|
64 | "execution_count": null, | |
65 | "metadata": { |
|
65 | "metadata": { | |
66 | "collapsed": false |
|
66 | "collapsed": false | |
67 | }, |
|
67 | }, | |
68 | "outputs": [], |
|
68 | "outputs": [], | |
69 | "source": [ |
|
69 | "source": [ | |
70 | "filename = notebook_name.value\n", |
|
70 | "filename = notebook_name.value\n", | |
71 | "filename" |
|
71 | "filename" | |
72 | ] |
|
72 | ] | |
73 | }, |
|
73 | }, | |
74 | { |
|
74 | { | |
75 | "cell_type": "markdown", |
|
75 | "cell_type": "markdown", | |
76 | "metadata": {}, |
|
76 | "metadata": {}, | |
77 | "source": [ |
|
77 | "source": [ | |
78 | "Create the widget that will allow the user to Export the current notebook." |
|
78 | "Create the widget that will allow the user to Export the current notebook." | |
79 | ] |
|
79 | ] | |
80 | }, |
|
80 | }, | |
81 | { |
|
81 | { | |
82 | "cell_type": "code", |
|
82 | "cell_type": "code", | |
83 | "execution_count": null, |
|
83 | "execution_count": null, | |
84 | "metadata": { |
|
84 | "metadata": { | |
85 | "collapsed": false |
|
85 | "collapsed": false | |
86 | }, |
|
86 | }, | |
87 | "outputs": [], |
|
87 | "outputs": [], | |
88 | "source": [ |
|
88 | "source": [ | |
89 |
"exporter_names = widgets.Dropdown( |
|
89 | "exporter_names = widgets.Dropdown(options=get_export_names(), value='html')\n", | |
90 | "export_button = widgets.Button(description=\"Export\")\n", |
|
90 | "export_button = widgets.Button(description=\"Export\")\n", | |
91 | "download_link = widgets.HTML(visible=False)" |
|
91 | "download_link = widgets.HTML(visible=False)" | |
92 | ] |
|
92 | ] | |
93 | }, |
|
93 | }, | |
94 | { |
|
94 | { | |
95 | "cell_type": "markdown", |
|
95 | "cell_type": "markdown", | |
96 | "metadata": {}, |
|
96 | "metadata": {}, | |
97 | "source": [ |
|
97 | "source": [ | |
98 | "Export the notebook when the export button is clicked." |
|
98 | "Export the notebook when the export button is clicked." | |
99 | ] |
|
99 | ] | |
100 | }, |
|
100 | }, | |
101 | { |
|
101 | { | |
102 | "cell_type": "code", |
|
102 | "cell_type": "code", | |
103 | "execution_count": null, |
|
103 | "execution_count": null, | |
104 | "metadata": { |
|
104 | "metadata": { | |
105 | "collapsed": false |
|
105 | "collapsed": false | |
106 | }, |
|
106 | }, | |
107 | "outputs": [], |
|
107 | "outputs": [], | |
108 | "source": [ |
|
108 | "source": [ | |
109 | "file_writer = FilesWriter()\n", |
|
109 | "file_writer = FilesWriter()\n", | |
110 | "\n", |
|
110 | "\n", | |
111 | "def export(name, nb):\n", |
|
111 | "def export(name, nb):\n", | |
112 | " \n", |
|
112 | " \n", | |
113 | " # Get a unique key for the notebook and set it in the resources object.\n", |
|
113 | " # Get a unique key for the notebook and set it in the resources object.\n", | |
114 | " notebook_name = name[:name.rfind('.')]\n", |
|
114 | " notebook_name = name[:name.rfind('.')]\n", | |
115 | " resources = {}\n", |
|
115 | " resources = {}\n", | |
116 | " resources['unique_key'] = notebook_name\n", |
|
116 | " resources['unique_key'] = notebook_name\n", | |
117 | " resources['output_files_dir'] = '%s_files' % notebook_name\n", |
|
117 | " resources['output_files_dir'] = '%s_files' % notebook_name\n", | |
118 | "\n", |
|
118 | "\n", | |
119 | " # Try to export\n", |
|
119 | " # Try to export\n", | |
120 | " try:\n", |
|
120 | " try:\n", | |
121 | " output, resources = export_by_name(exporter_names.value, nb)\n", |
|
121 | " output, resources = export_by_name(exporter_names.value, nb)\n", | |
122 | " except ConversionException as e:\n", |
|
122 | " except ConversionException as e:\n", | |
123 | " download_link.value = \"<br>Could not export notebook!\"\n", |
|
123 | " download_link.value = \"<br>Could not export notebook!\"\n", | |
124 | " else:\n", |
|
124 | " else:\n", | |
125 | " write_results = file_writer.write(output, resources, notebook_name=notebook_name)\n", |
|
125 | " write_results = file_writer.write(output, resources, notebook_name=notebook_name)\n", | |
126 | " \n", |
|
126 | " \n", | |
127 | " download_link.value = \"<br>Results: <a href='files/{filename}'><i>\\\"{filename}\\\"</i></a>\".format(filename=write_results)\n", |
|
127 | " download_link.value = \"<br>Results: <a href='files/{filename}'><i>\\\"{filename}\\\"</i></a>\".format(filename=write_results)\n", | |
128 | " download_link.visible = True\n", |
|
128 | " download_link.visible = True\n", | |
129 | " \n", |
|
129 | " \n", | |
130 | "def handle_export(widget):\n", |
|
130 | "def handle_export(widget):\n", | |
131 | " with open(filename, 'r') as f:\n", |
|
131 | " with open(filename, 'r') as f:\n", | |
132 | " export(filename, current.read(f, 'json'))\n", |
|
132 | " export(filename, current.read(f, 'json'))\n", | |
133 | "export_button.on_click(handle_export)" |
|
133 | "export_button.on_click(handle_export)" | |
134 | ] |
|
134 | ] | |
135 | }, |
|
135 | }, | |
136 | { |
|
136 | { | |
137 | "cell_type": "markdown", |
|
137 | "cell_type": "markdown", | |
138 | "metadata": {}, |
|
138 | "metadata": {}, | |
139 | "source": [ |
|
139 | "source": [ | |
140 | "Display the controls." |
|
140 | "Display the controls." | |
141 | ] |
|
141 | ] | |
142 | }, |
|
142 | }, | |
143 | { |
|
143 | { | |
144 | "cell_type": "code", |
|
144 | "cell_type": "code", | |
145 | "execution_count": null, |
|
145 | "execution_count": null, | |
146 | "metadata": { |
|
146 | "metadata": { | |
147 | "collapsed": false |
|
147 | "collapsed": false | |
148 | }, |
|
148 | }, | |
149 | "outputs": [], |
|
149 | "outputs": [], | |
150 | "source": [ |
|
150 | "source": [ | |
151 | "display(exporter_names, export_button, download_link)" |
|
151 | "display(exporter_names, export_button, download_link)" | |
152 | ] |
|
152 | ] | |
153 | } |
|
153 | } | |
154 | ], |
|
154 | ], | |
155 | "metadata": { |
|
155 | "metadata": { | |
156 | "kernelspec": { |
|
156 | "kernelspec": { | |
157 | "display_name": "Python 3", |
|
157 | "display_name": "Python 3", | |
158 | "language": "python", |
|
158 | "language": "python", | |
159 | "name": "python3" |
|
159 | "name": "python3" | |
160 | }, |
|
160 | }, | |
161 | "language_info": { |
|
161 | "language_info": { | |
162 | "codemirror_mode": { |
|
162 | "codemirror_mode": { | |
163 | "name": "ipython", |
|
163 | "name": "ipython", | |
164 | "version": 3 |
|
164 | "version": 3 | |
165 | }, |
|
165 | }, | |
166 | "file_extension": ".py", |
|
166 | "file_extension": ".py", | |
167 | "mimetype": "text/x-python", |
|
167 | "mimetype": "text/x-python", | |
168 | "name": "python", |
|
168 | "name": "python", | |
169 | "nbconvert_exporter": "python", |
|
169 | "nbconvert_exporter": "python", | |
170 | "pygments_lexer": "ipython3", |
|
170 | "pygments_lexer": "ipython3", | |
171 | "version": "3.4.2" |
|
171 | "version": "3.4.2" | |
172 | } |
|
172 | } | |
173 | }, |
|
173 | }, | |
174 | "nbformat": 4, |
|
174 | "nbformat": 4, | |
175 | "nbformat_minor": 0 |
|
175 | "nbformat_minor": 0 | |
176 | } |
|
176 | } |
@@ -1,587 +1,621 b'' | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "markdown", |
|
4 | "cell_type": "markdown", | |
5 | "metadata": {}, |
|
5 | "metadata": {}, | |
6 | "source": [ |
|
6 | "source": [ | |
7 | "[Index](Index.ipynb) - [Back](Widget Basics.ipynb) - [Next](Widget Events.ipynb)" |
|
7 | "[Index](Index.ipynb) - [Back](Widget Basics.ipynb) - [Next](Widget Events.ipynb)" | |
8 | ] |
|
8 | ] | |
9 | }, |
|
9 | }, | |
10 | { |
|
10 | { | |
11 | "cell_type": "markdown", |
|
11 | "cell_type": "markdown", | |
12 | "metadata": {}, |
|
12 | "metadata": {}, | |
13 | "source": [ |
|
13 | "source": [ | |
14 | "# Widget List" |
|
14 | "# Widget List" | |
15 | ] |
|
15 | ] | |
16 | }, |
|
16 | }, | |
17 | { |
|
17 | { | |
18 | "cell_type": "markdown", |
|
18 | "cell_type": "markdown", | |
19 | "metadata": {}, |
|
19 | "metadata": {}, | |
20 | "source": [ |
|
20 | "source": [ | |
21 | "## Complete list" |
|
21 | "## Complete list" | |
22 | ] |
|
22 | ] | |
23 | }, |
|
23 | }, | |
24 | { |
|
24 | { | |
25 | "cell_type": "markdown", |
|
25 | "cell_type": "markdown", | |
26 | "metadata": { |
|
26 | "metadata": { | |
27 | "slideshow": { |
|
27 | "slideshow": { | |
28 | "slide_type": "slide" |
|
28 | "slide_type": "slide" | |
29 | } |
|
29 | } | |
30 | }, |
|
30 | }, | |
31 | "source": [ |
|
31 | "source": [ | |
32 | "For a complete list of the widgets available to you, you can list the classes in the widget namespace (as seen below). `Widget` and `DOMWidget`, not listed below, are base classes." |
|
32 | "For a complete list of the widgets available to you, you can list the classes in the widget namespace (as seen below). `Widget` and `DOMWidget`, not listed below, are base classes." | |
33 | ] |
|
33 | ] | |
34 | }, |
|
34 | }, | |
35 | { |
|
35 | { | |
36 | "cell_type": "code", |
|
36 | "cell_type": "code", | |
37 | "execution_count": null, |
|
37 | "execution_count": null, | |
38 | "metadata": { |
|
38 | "metadata": { | |
39 | "collapsed": false |
|
39 | "collapsed": false | |
40 | }, |
|
40 | }, | |
41 | "outputs": [], |
|
41 | "outputs": [], | |
42 | "source": [ |
|
42 | "source": [ | |
43 | "from IPython.html import widgets\n", |
|
43 | "from IPython.html import widgets\n", | |
44 | "[n for n in dir(widgets) if not n.endswith('Widget') and n[0] == n[0].upper() and not n[0] == '_']" |
|
44 | "[n for n in dir(widgets) if not n.endswith('Widget') and n[0] == n[0].upper() and not n[0] == '_']" | |
45 | ] |
|
45 | ] | |
46 | }, |
|
46 | }, | |
47 | { |
|
47 | { | |
48 | "cell_type": "markdown", |
|
48 | "cell_type": "markdown", | |
49 | "metadata": { |
|
49 | "metadata": { | |
50 | "slideshow": { |
|
50 | "slideshow": { | |
51 | "slide_type": "slide" |
|
51 | "slide_type": "slide" | |
52 | } |
|
52 | } | |
53 | }, |
|
53 | }, | |
54 | "source": [ |
|
54 | "source": [ | |
55 | "## Numeric widgets" |
|
55 | "## Numeric widgets" | |
56 | ] |
|
56 | ] | |
57 | }, |
|
57 | }, | |
58 | { |
|
58 | { | |
59 | "cell_type": "markdown", |
|
59 | "cell_type": "markdown", | |
60 | "metadata": {}, |
|
60 | "metadata": {}, | |
61 | "source": [ |
|
61 | "source": [ | |
62 | "There are 8 widgets distributed with IPython that are designed to display numeric values. Widgets exist for displaying integers and floats, both bounded and unbounded. The integer widgets share a similar naming scheme to their floating point counterparts. By replacing `Float` with `Int` in the widget name, you can find the Integer equivalent." |
|
62 | "There are 8 widgets distributed with IPython that are designed to display numeric values. Widgets exist for displaying integers and floats, both bounded and unbounded. The integer widgets share a similar naming scheme to their floating point counterparts. By replacing `Float` with `Int` in the widget name, you can find the Integer equivalent." | |
63 | ] |
|
63 | ] | |
64 | }, |
|
64 | }, | |
65 | { |
|
65 | { | |
66 | "cell_type": "markdown", |
|
66 | "cell_type": "markdown", | |
67 | "metadata": { |
|
67 | "metadata": { | |
68 | "slideshow": { |
|
68 | "slideshow": { | |
69 | "slide_type": "slide" |
|
69 | "slide_type": "slide" | |
70 | } |
|
70 | } | |
71 | }, |
|
71 | }, | |
72 | "source": [ |
|
72 | "source": [ | |
73 | "### FloatSlider" |
|
73 | "### FloatSlider" | |
74 | ] |
|
74 | ] | |
75 | }, |
|
75 | }, | |
76 | { |
|
76 | { | |
77 | "cell_type": "code", |
|
77 | "cell_type": "code", | |
78 | "execution_count": null, |
|
78 | "execution_count": null, | |
79 | "metadata": { |
|
79 | "metadata": { | |
80 | "collapsed": false |
|
80 | "collapsed": false | |
81 | }, |
|
81 | }, | |
82 | "outputs": [], |
|
82 | "outputs": [], | |
83 | "source": [ |
|
83 | "source": [ | |
84 | "widgets.FloatSlider(\n", |
|
84 | "widgets.FloatSlider(\n", | |
85 | " value=7.5,\n", |
|
85 | " value=7.5,\n", | |
86 | " min=5.0,\n", |
|
86 | " min=5.0,\n", | |
87 | " max=10.0,\n", |
|
87 | " max=10.0,\n", | |
88 | " step=0.1,\n", |
|
88 | " step=0.1,\n", | |
89 | " description='Test:',\n", |
|
89 | " description='Test:',\n", | |
90 | ")" |
|
90 | ")" | |
91 | ] |
|
91 | ] | |
92 | }, |
|
92 | }, | |
93 | { |
|
93 | { | |
94 | "cell_type": "markdown", |
|
94 | "cell_type": "markdown", | |
95 | "metadata": {}, |
|
95 | "metadata": {}, | |
96 | "source": [ |
|
96 | "source": [ | |
97 | "Sliders can also be **displayed vertically**." |
|
97 | "Sliders can also be **displayed vertically**." | |
98 | ] |
|
98 | ] | |
99 | }, |
|
99 | }, | |
100 | { |
|
100 | { | |
101 | "cell_type": "code", |
|
101 | "cell_type": "code", | |
102 | "execution_count": null, |
|
102 | "execution_count": null, | |
103 | "metadata": { |
|
103 | "metadata": { | |
104 | "collapsed": false |
|
104 | "collapsed": false | |
105 | }, |
|
105 | }, | |
106 | "outputs": [], |
|
106 | "outputs": [], | |
107 | "source": [ |
|
107 | "source": [ | |
108 | "widgets.FloatSlider(\n", |
|
108 | "widgets.FloatSlider(\n", | |
109 | " value=7.5,\n", |
|
109 | " value=7.5,\n", | |
110 | " min=5.0,\n", |
|
110 | " min=5.0,\n", | |
111 | " max=10.0,\n", |
|
111 | " max=10.0,\n", | |
112 | " step=0.1,\n", |
|
112 | " step=0.1,\n", | |
113 | " description='Test',\n", |
|
113 | " description='Test',\n", | |
114 | " orientation='vertical',\n", |
|
114 | " orientation='vertical',\n", | |
115 | ")" |
|
115 | ")" | |
116 | ] |
|
116 | ] | |
117 | }, |
|
117 | }, | |
118 | { |
|
118 | { | |
119 | "cell_type": "markdown", |
|
119 | "cell_type": "markdown", | |
120 | "metadata": { |
|
120 | "metadata": { | |
121 | "slideshow": { |
|
121 | "slideshow": { | |
122 | "slide_type": "slide" |
|
122 | "slide_type": "slide" | |
123 | } |
|
123 | } | |
124 | }, |
|
124 | }, | |
125 | "source": [ |
|
125 | "source": [ | |
126 | "### FloatProgress" |
|
126 | "### FloatProgress" | |
127 | ] |
|
127 | ] | |
128 | }, |
|
128 | }, | |
129 | { |
|
129 | { | |
130 | "cell_type": "code", |
|
130 | "cell_type": "code", | |
131 | "execution_count": null, |
|
131 | "execution_count": null, | |
132 | "metadata": { |
|
132 | "metadata": { | |
133 | "collapsed": false |
|
133 | "collapsed": false | |
134 | }, |
|
134 | }, | |
135 | "outputs": [], |
|
135 | "outputs": [], | |
136 | "source": [ |
|
136 | "source": [ | |
137 | "widgets.FloatProgress(\n", |
|
137 | "widgets.FloatProgress(\n", | |
138 | " value=7.5,\n", |
|
138 | " value=7.5,\n", | |
139 | " min=5.0,\n", |
|
139 | " min=5.0,\n", | |
140 | " max=10.0,\n", |
|
140 | " max=10.0,\n", | |
141 | " step=0.1,\n", |
|
141 | " step=0.1,\n", | |
142 | " description='Loading:',\n", |
|
142 | " description='Loading:',\n", | |
143 | ")" |
|
143 | ")" | |
144 | ] |
|
144 | ] | |
145 | }, |
|
145 | }, | |
146 | { |
|
146 | { | |
147 | "cell_type": "markdown", |
|
147 | "cell_type": "markdown", | |
148 | "metadata": { |
|
148 | "metadata": { | |
149 | "slideshow": { |
|
149 | "slideshow": { | |
150 | "slide_type": "slide" |
|
150 | "slide_type": "slide" | |
151 | } |
|
151 | } | |
152 | }, |
|
152 | }, | |
153 | "source": [ |
|
153 | "source": [ | |
154 | "### BoundedFloatText" |
|
154 | "### BoundedFloatText" | |
155 | ] |
|
155 | ] | |
156 | }, |
|
156 | }, | |
157 | { |
|
157 | { | |
158 | "cell_type": "code", |
|
158 | "cell_type": "code", | |
159 | "execution_count": null, |
|
159 | "execution_count": null, | |
160 | "metadata": { |
|
160 | "metadata": { | |
161 | "collapsed": false |
|
161 | "collapsed": false | |
162 | }, |
|
162 | }, | |
163 | "outputs": [], |
|
163 | "outputs": [], | |
164 | "source": [ |
|
164 | "source": [ | |
165 | "widgets.BoundedFloatText(\n", |
|
165 | "widgets.BoundedFloatText(\n", | |
166 | " value=7.5,\n", |
|
166 | " value=7.5,\n", | |
167 | " min=5.0,\n", |
|
167 | " min=5.0,\n", | |
168 | " max=10.0,\n", |
|
168 | " max=10.0,\n", | |
169 | " description='Text:',\n", |
|
169 | " description='Text:',\n", | |
170 | ")" |
|
170 | ")" | |
171 | ] |
|
171 | ] | |
172 | }, |
|
172 | }, | |
173 | { |
|
173 | { | |
174 | "cell_type": "markdown", |
|
174 | "cell_type": "markdown", | |
175 | "metadata": { |
|
175 | "metadata": { | |
176 | "slideshow": { |
|
176 | "slideshow": { | |
177 | "slide_type": "slide" |
|
177 | "slide_type": "slide" | |
178 | } |
|
178 | } | |
179 | }, |
|
179 | }, | |
180 | "source": [ |
|
180 | "source": [ | |
181 | "### FloatText" |
|
181 | "### FloatText" | |
182 | ] |
|
182 | ] | |
183 | }, |
|
183 | }, | |
184 | { |
|
184 | { | |
185 | "cell_type": "code", |
|
185 | "cell_type": "code", | |
186 | "execution_count": null, |
|
186 | "execution_count": null, | |
187 | "metadata": { |
|
187 | "metadata": { | |
188 | "collapsed": false |
|
188 | "collapsed": false | |
189 | }, |
|
189 | }, | |
190 | "outputs": [], |
|
190 | "outputs": [], | |
191 | "source": [ |
|
191 | "source": [ | |
192 | "widgets.FloatText(\n", |
|
192 | "widgets.FloatText(\n", | |
193 | " value=7.5,\n", |
|
193 | " value=7.5,\n", | |
194 | " description='Any:',\n", |
|
194 | " description='Any:',\n", | |
195 | ")" |
|
195 | ")" | |
196 | ] |
|
196 | ] | |
197 | }, |
|
197 | }, | |
198 | { |
|
198 | { | |
199 | "cell_type": "markdown", |
|
199 | "cell_type": "markdown", | |
200 | "metadata": { |
|
200 | "metadata": { | |
201 | "slideshow": { |
|
201 | "slideshow": { | |
202 | "slide_type": "slide" |
|
202 | "slide_type": "slide" | |
203 | } |
|
203 | } | |
204 | }, |
|
204 | }, | |
205 | "source": [ |
|
205 | "source": [ | |
206 | "## Boolean widgets" |
|
206 | "## Boolean widgets" | |
207 | ] |
|
207 | ] | |
208 | }, |
|
208 | }, | |
209 | { |
|
209 | { | |
210 | "cell_type": "markdown", |
|
210 | "cell_type": "markdown", | |
211 | "metadata": {}, |
|
211 | "metadata": {}, | |
212 | "source": [ |
|
212 | "source": [ | |
213 | "There are two widgets that are designed to display a boolean value." |
|
213 | "There are two widgets that are designed to display a boolean value." | |
214 | ] |
|
214 | ] | |
215 | }, |
|
215 | }, | |
216 | { |
|
216 | { | |
217 | "cell_type": "markdown", |
|
217 | "cell_type": "markdown", | |
218 | "metadata": {}, |
|
218 | "metadata": {}, | |
219 | "source": [ |
|
219 | "source": [ | |
220 | "### ToggleButton" |
|
220 | "### ToggleButton" | |
221 | ] |
|
221 | ] | |
222 | }, |
|
222 | }, | |
223 | { |
|
223 | { | |
224 | "cell_type": "code", |
|
224 | "cell_type": "code", | |
225 | "execution_count": null, |
|
225 | "execution_count": null, | |
226 | "metadata": { |
|
226 | "metadata": { | |
227 | "collapsed": false |
|
227 | "collapsed": false | |
228 | }, |
|
228 | }, | |
229 | "outputs": [], |
|
229 | "outputs": [], | |
230 | "source": [ |
|
230 | "source": [ | |
231 | "widgets.ToggleButton(\n", |
|
231 | "widgets.ToggleButton(\n", | |
232 | " description='Click me',\n", |
|
232 | " description='Click me',\n", | |
233 | " value=False,\n", |
|
233 | " value=False,\n", | |
234 | ")" |
|
234 | ")" | |
235 | ] |
|
235 | ] | |
236 | }, |
|
236 | }, | |
237 | { |
|
237 | { | |
238 | "cell_type": "markdown", |
|
238 | "cell_type": "markdown", | |
239 | "metadata": { |
|
239 | "metadata": { | |
240 | "slideshow": { |
|
240 | "slideshow": { | |
241 | "slide_type": "slide" |
|
241 | "slide_type": "slide" | |
242 | } |
|
242 | } | |
243 | }, |
|
243 | }, | |
244 | "source": [ |
|
244 | "source": [ | |
245 | "### Checkbox" |
|
245 | "### Checkbox" | |
246 | ] |
|
246 | ] | |
247 | }, |
|
247 | }, | |
248 | { |
|
248 | { | |
249 | "cell_type": "code", |
|
249 | "cell_type": "code", | |
250 | "execution_count": null, |
|
250 | "execution_count": null, | |
251 | "metadata": { |
|
251 | "metadata": { | |
252 | "collapsed": false |
|
252 | "collapsed": false | |
253 | }, |
|
253 | }, | |
254 | "outputs": [], |
|
254 | "outputs": [], | |
255 | "source": [ |
|
255 | "source": [ | |
256 | "widgets.Checkbox(\n", |
|
256 | "widgets.Checkbox(\n", | |
257 | " description='Check me',\n", |
|
257 | " description='Check me',\n", | |
258 | " value=True,\n", |
|
258 | " value=True,\n", | |
259 | ")" |
|
259 | ")" | |
260 | ] |
|
260 | ] | |
261 | }, |
|
261 | }, | |
262 | { |
|
262 | { | |
263 | "cell_type": "markdown", |
|
263 | "cell_type": "markdown", | |
264 | "metadata": { |
|
264 | "metadata": { | |
265 | "slideshow": { |
|
265 | "slideshow": { | |
266 | "slide_type": "slide" |
|
266 | "slide_type": "slide" | |
267 | } |
|
267 | } | |
268 | }, |
|
268 | }, | |
269 | "source": [ |
|
269 | "source": [ | |
270 | "## Selection widgets" |
|
270 | "## Selection widgets" | |
271 | ] |
|
271 | ] | |
272 | }, |
|
272 | }, | |
273 | { |
|
273 | { | |
274 | "cell_type": "markdown", |
|
274 | "cell_type": "markdown", | |
275 | "metadata": {}, |
|
275 | "metadata": {}, | |
276 | "source": [ |
|
276 | "source": [ | |
277 |
"There are four widgets that can be used to display single selection lists. All |
|
277 | "There are four widgets that can be used to display single selection lists, and one that can be used to display multiple selection lists. All inherit from the same base class. You can specify the **enumeration of selectable options by passing a list**. You can **also specify the enumeration as a dictionary**, in which case the **keys will be used as the item displayed** in the list and the corresponding **value will be returned** when an item is selected." | |
278 | ] |
|
278 | ] | |
279 | }, |
|
279 | }, | |
280 | { |
|
280 | { | |
281 | "cell_type": "markdown", |
|
281 | "cell_type": "markdown", | |
282 | "metadata": { |
|
282 | "metadata": { | |
283 | "slideshow": { |
|
283 | "slideshow": { | |
284 | "slide_type": "slide" |
|
284 | "slide_type": "slide" | |
285 | } |
|
285 | } | |
286 | }, |
|
286 | }, | |
287 | "source": [ |
|
287 | "source": [ | |
288 | "### Dropdown" |
|
288 | "### Dropdown" | |
289 | ] |
|
289 | ] | |
290 | }, |
|
290 | }, | |
291 | { |
|
291 | { | |
292 | "cell_type": "code", |
|
292 | "cell_type": "code", | |
293 | "execution_count": null, |
|
293 | "execution_count": null, | |
294 | "metadata": { |
|
294 | "metadata": { | |
295 | "collapsed": false |
|
295 | "collapsed": false | |
296 | }, |
|
296 | }, | |
297 | "outputs": [], |
|
297 | "outputs": [], | |
298 | "source": [ |
|
298 | "source": [ | |
299 | "from IPython.display import display\n", |
|
299 | "from IPython.display import display\n", | |
300 | "w = widgets.Dropdown(\n", |
|
300 | "w = widgets.Dropdown(\n", | |
301 |
" |
|
301 | " options=['1', '2', '3'],\n", | |
302 | " value='2',\n", |
|
302 | " value='2',\n", | |
303 | " description='Number:',\n", |
|
303 | " description='Number:',\n", | |
304 | ")\n", |
|
304 | ")\n", | |
305 | "display(w)" |
|
305 | "display(w)" | |
306 | ] |
|
306 | ] | |
307 | }, |
|
307 | }, | |
308 | { |
|
308 | { | |
309 | "cell_type": "code", |
|
309 | "cell_type": "code", | |
310 | "execution_count": null, |
|
310 | "execution_count": null, | |
311 | "metadata": { |
|
311 | "metadata": { | |
312 | "collapsed": false |
|
312 | "collapsed": false | |
313 | }, |
|
313 | }, | |
314 | "outputs": [], |
|
314 | "outputs": [], | |
315 | "source": [ |
|
315 | "source": [ | |
316 | "w.value" |
|
316 | "w.value" | |
317 | ] |
|
317 | ] | |
318 | }, |
|
318 | }, | |
319 | { |
|
319 | { | |
320 | "cell_type": "markdown", |
|
320 | "cell_type": "markdown", | |
321 | "metadata": {}, |
|
321 | "metadata": {}, | |
322 | "source": [ |
|
322 | "source": [ | |
323 | "The following is also valid:" |
|
323 | "The following is also valid:" | |
324 | ] |
|
324 | ] | |
325 | }, |
|
325 | }, | |
326 | { |
|
326 | { | |
327 | "cell_type": "code", |
|
327 | "cell_type": "code", | |
328 | "execution_count": null, |
|
328 | "execution_count": null, | |
329 | "metadata": { |
|
329 | "metadata": { | |
330 | "collapsed": false |
|
330 | "collapsed": false | |
331 | }, |
|
331 | }, | |
332 | "outputs": [], |
|
332 | "outputs": [], | |
333 | "source": [ |
|
333 | "source": [ | |
334 | "w = widgets.Dropdown(\n", |
|
334 | "w = widgets.Dropdown(\n", | |
335 |
" |
|
335 | " options={'One': 1, 'Two': 2, 'Three': 3},\n", | |
336 | " value=2,\n", |
|
336 | " value=2,\n", | |
337 | " description='Number:',\n", |
|
337 | " description='Number:',\n", | |
338 | ")\n", |
|
338 | ")\n", | |
339 | "display(w)" |
|
339 | "display(w)" | |
340 | ] |
|
340 | ] | |
341 | }, |
|
341 | }, | |
342 | { |
|
342 | { | |
343 | "cell_type": "code", |
|
343 | "cell_type": "code", | |
344 | "execution_count": null, |
|
344 | "execution_count": null, | |
345 | "metadata": { |
|
345 | "metadata": { | |
346 | "collapsed": false |
|
346 | "collapsed": false | |
347 | }, |
|
347 | }, | |
348 | "outputs": [], |
|
348 | "outputs": [], | |
349 | "source": [ |
|
349 | "source": [ | |
350 | "w.value" |
|
350 | "w.value" | |
351 | ] |
|
351 | ] | |
352 | }, |
|
352 | }, | |
353 | { |
|
353 | { | |
354 | "cell_type": "markdown", |
|
354 | "cell_type": "markdown", | |
355 | "metadata": { |
|
355 | "metadata": { | |
356 | "slideshow": { |
|
356 | "slideshow": { | |
357 | "slide_type": "slide" |
|
357 | "slide_type": "slide" | |
358 | } |
|
358 | } | |
359 | }, |
|
359 | }, | |
360 | "source": [ |
|
360 | "source": [ | |
361 | "### RadioButtons" |
|
361 | "### RadioButtons" | |
362 | ] |
|
362 | ] | |
363 | }, |
|
363 | }, | |
364 | { |
|
364 | { | |
365 | "cell_type": "code", |
|
365 | "cell_type": "code", | |
366 | "execution_count": null, |
|
366 | "execution_count": null, | |
367 | "metadata": { |
|
367 | "metadata": { | |
368 | "collapsed": false |
|
368 | "collapsed": false | |
369 | }, |
|
369 | }, | |
370 | "outputs": [], |
|
370 | "outputs": [], | |
371 | "source": [ |
|
371 | "source": [ | |
372 | "widgets.RadioButtons(\n", |
|
372 | "widgets.RadioButtons(\n", | |
373 | " description='Pizza topping:',\n", |
|
373 | " description='Pizza topping:',\n", | |
374 |
" |
|
374 | " options=['pepperoni', 'pineapple', 'anchovies'],\n", | |
375 | ")" |
|
375 | ")" | |
376 | ] |
|
376 | ] | |
377 | }, |
|
377 | }, | |
378 | { |
|
378 | { | |
379 | "cell_type": "markdown", |
|
379 | "cell_type": "markdown", | |
380 | "metadata": { |
|
380 | "metadata": { | |
381 | "slideshow": { |
|
381 | "slideshow": { | |
382 | "slide_type": "slide" |
|
382 | "slide_type": "slide" | |
383 | } |
|
383 | } | |
384 | }, |
|
384 | }, | |
385 | "source": [ |
|
385 | "source": [ | |
386 | "### Select" |
|
386 | "### Select" | |
387 | ] |
|
387 | ] | |
388 | }, |
|
388 | }, | |
389 | { |
|
389 | { | |
390 | "cell_type": "code", |
|
390 | "cell_type": "code", | |
391 | "execution_count": null, |
|
391 | "execution_count": null, | |
392 | "metadata": { |
|
392 | "metadata": { | |
393 | "collapsed": false |
|
393 | "collapsed": false | |
394 | }, |
|
394 | }, | |
395 | "outputs": [], |
|
395 | "outputs": [], | |
396 | "source": [ |
|
396 | "source": [ | |
397 | "widgets.Select(\n", |
|
397 | "widgets.Select(\n", | |
398 | " description='OS:',\n", |
|
398 | " description='OS:',\n", | |
399 |
" |
|
399 | " options=['Linux', 'Windows', 'OSX'],\n", | |
400 | ")" |
|
400 | ")" | |
401 | ] |
|
401 | ] | |
402 | }, |
|
402 | }, | |
403 | { |
|
403 | { | |
404 | "cell_type": "markdown", |
|
404 | "cell_type": "markdown", | |
405 | "metadata": { |
|
405 | "metadata": { | |
406 | "slideshow": { |
|
406 | "slideshow": { | |
407 | "slide_type": "slide" |
|
407 | "slide_type": "slide" | |
408 | } |
|
408 | } | |
409 | }, |
|
409 | }, | |
410 | "source": [ |
|
410 | "source": [ | |
411 | "### ToggleButtons" |
|
411 | "### ToggleButtons" | |
412 | ] |
|
412 | ] | |
413 | }, |
|
413 | }, | |
414 | { |
|
414 | { | |
415 | "cell_type": "code", |
|
415 | "cell_type": "code", | |
416 | "execution_count": null, |
|
416 | "execution_count": null, | |
417 | "metadata": { |
|
417 | "metadata": { | |
418 | "collapsed": false |
|
418 | "collapsed": false | |
419 | }, |
|
419 | }, | |
420 | "outputs": [], |
|
420 | "outputs": [], | |
421 | "source": [ |
|
421 | "source": [ | |
422 | "widgets.ToggleButtons(\n", |
|
422 | "widgets.ToggleButtons(\n", | |
423 | " description='Speed:',\n", |
|
423 | " description='Speed:',\n", | |
424 |
" |
|
424 | " options=['Slow', 'Regular', 'Fast'],\n", | |
425 | ")" |
|
425 | ")" | |
426 | ] |
|
426 | ] | |
427 | }, |
|
427 | }, | |
428 | { |
|
428 | { | |
429 | "cell_type": "markdown", |
|
429 | "cell_type": "markdown", | |
|
430 | "metadata": {}, | |||
|
431 | "source": [ | |||
|
432 | "### SelectMultiple\n", | |||
|
433 | "Multiple values can be selected with <kbd>shift</kbd> and <kbd>ctrl</kbd> pressed and mouse clicks or arrow keys." | |||
|
434 | ] | |||
|
435 | }, | |||
|
436 | { | |||
|
437 | "cell_type": "code", | |||
|
438 | "execution_count": null, | |||
|
439 | "metadata": { | |||
|
440 | "collapsed": true | |||
|
441 | }, | |||
|
442 | "outputs": [], | |||
|
443 | "source": [ | |||
|
444 | "w = widgets.SelectMultiple(\n", | |||
|
445 | " description=\"Fruits\",\n", | |||
|
446 | " options=['Apples', 'Oranges', 'Pears']\n", | |||
|
447 | ")\n", | |||
|
448 | "display(w)" | |||
|
449 | ] | |||
|
450 | }, | |||
|
451 | { | |||
|
452 | "cell_type": "code", | |||
|
453 | "execution_count": null, | |||
|
454 | "metadata": { | |||
|
455 | "collapsed": false | |||
|
456 | }, | |||
|
457 | "outputs": [], | |||
|
458 | "source": [ | |||
|
459 | "w.value" | |||
|
460 | ] | |||
|
461 | }, | |||
|
462 | { | |||
|
463 | "cell_type": "markdown", | |||
430 | "metadata": { |
|
464 | "metadata": { | |
431 | "slideshow": { |
|
465 | "slideshow": { | |
432 | "slide_type": "slide" |
|
466 | "slide_type": "slide" | |
433 | } |
|
467 | } | |
434 | }, |
|
468 | }, | |
435 | "source": [ |
|
469 | "source": [ | |
436 | "## String widgets" |
|
470 | "## String widgets" | |
437 | ] |
|
471 | ] | |
438 | }, |
|
472 | }, | |
439 | { |
|
473 | { | |
440 | "cell_type": "markdown", |
|
474 | "cell_type": "markdown", | |
441 | "metadata": {}, |
|
475 | "metadata": {}, | |
442 | "source": [ |
|
476 | "source": [ | |
443 | "There are 4 widgets that can be used to display a string value. Of those, the **`Text` and `Textarea` widgets accept input**. The **`Latex` and `HTML` widgets display the string** as either Latex or HTML respectively, but **do not accept input**." |
|
477 | "There are 4 widgets that can be used to display a string value. Of those, the **`Text` and `Textarea` widgets accept input**. The **`Latex` and `HTML` widgets display the string** as either Latex or HTML respectively, but **do not accept input**." | |
444 | ] |
|
478 | ] | |
445 | }, |
|
479 | }, | |
446 | { |
|
480 | { | |
447 | "cell_type": "markdown", |
|
481 | "cell_type": "markdown", | |
448 | "metadata": { |
|
482 | "metadata": { | |
449 | "slideshow": { |
|
483 | "slideshow": { | |
450 | "slide_type": "slide" |
|
484 | "slide_type": "slide" | |
451 | } |
|
485 | } | |
452 | }, |
|
486 | }, | |
453 | "source": [ |
|
487 | "source": [ | |
454 | "### Text" |
|
488 | "### Text" | |
455 | ] |
|
489 | ] | |
456 | }, |
|
490 | }, | |
457 | { |
|
491 | { | |
458 | "cell_type": "code", |
|
492 | "cell_type": "code", | |
459 | "execution_count": null, |
|
493 | "execution_count": null, | |
460 | "metadata": { |
|
494 | "metadata": { | |
461 | "collapsed": false |
|
495 | "collapsed": false | |
462 | }, |
|
496 | }, | |
463 | "outputs": [], |
|
497 | "outputs": [], | |
464 | "source": [ |
|
498 | "source": [ | |
465 | "widgets.Text(\n", |
|
499 | "widgets.Text(\n", | |
466 | " description='String:',\n", |
|
500 | " description='String:',\n", | |
467 | " value='Hello World',\n", |
|
501 | " value='Hello World',\n", | |
468 | ")" |
|
502 | ")" | |
469 | ] |
|
503 | ] | |
470 | }, |
|
504 | }, | |
471 | { |
|
505 | { | |
472 | "cell_type": "markdown", |
|
506 | "cell_type": "markdown", | |
473 | "metadata": {}, |
|
507 | "metadata": {}, | |
474 | "source": [ |
|
508 | "source": [ | |
475 | "### Textarea" |
|
509 | "### Textarea" | |
476 | ] |
|
510 | ] | |
477 | }, |
|
511 | }, | |
478 | { |
|
512 | { | |
479 | "cell_type": "code", |
|
513 | "cell_type": "code", | |
480 | "execution_count": null, |
|
514 | "execution_count": null, | |
481 | "metadata": { |
|
515 | "metadata": { | |
482 | "collapsed": false |
|
516 | "collapsed": false | |
483 | }, |
|
517 | }, | |
484 | "outputs": [], |
|
518 | "outputs": [], | |
485 | "source": [ |
|
519 | "source": [ | |
486 | "widgets.Textarea(\n", |
|
520 | "widgets.Textarea(\n", | |
487 | " description='String:',\n", |
|
521 | " description='String:',\n", | |
488 | " value='Hello World',\n", |
|
522 | " value='Hello World',\n", | |
489 | ")" |
|
523 | ")" | |
490 | ] |
|
524 | ] | |
491 | }, |
|
525 | }, | |
492 | { |
|
526 | { | |
493 | "cell_type": "markdown", |
|
527 | "cell_type": "markdown", | |
494 | "metadata": { |
|
528 | "metadata": { | |
495 | "slideshow": { |
|
529 | "slideshow": { | |
496 | "slide_type": "slide" |
|
530 | "slide_type": "slide" | |
497 | } |
|
531 | } | |
498 | }, |
|
532 | }, | |
499 | "source": [ |
|
533 | "source": [ | |
500 | "### Latex" |
|
534 | "### Latex" | |
501 | ] |
|
535 | ] | |
502 | }, |
|
536 | }, | |
503 | { |
|
537 | { | |
504 | "cell_type": "code", |
|
538 | "cell_type": "code", | |
505 | "execution_count": null, |
|
539 | "execution_count": null, | |
506 | "metadata": { |
|
540 | "metadata": { | |
507 | "collapsed": false |
|
541 | "collapsed": false | |
508 | }, |
|
542 | }, | |
509 | "outputs": [], |
|
543 | "outputs": [], | |
510 | "source": [ |
|
544 | "source": [ | |
511 | "widgets.Latex(\n", |
|
545 | "widgets.Latex(\n", | |
512 | " value=\"$$\\\\frac{n!}{k!(n-k)!} = \\\\binom{n}{k}$$\",\n", |
|
546 | " value=\"$$\\\\frac{n!}{k!(n-k)!} = \\\\binom{n}{k}$$\",\n", | |
513 | ")" |
|
547 | ")" | |
514 | ] |
|
548 | ] | |
515 | }, |
|
549 | }, | |
516 | { |
|
550 | { | |
517 | "cell_type": "markdown", |
|
551 | "cell_type": "markdown", | |
518 | "metadata": {}, |
|
552 | "metadata": {}, | |
519 | "source": [ |
|
553 | "source": [ | |
520 | "### HTML" |
|
554 | "### HTML" | |
521 | ] |
|
555 | ] | |
522 | }, |
|
556 | }, | |
523 | { |
|
557 | { | |
524 | "cell_type": "code", |
|
558 | "cell_type": "code", | |
525 | "execution_count": null, |
|
559 | "execution_count": null, | |
526 | "metadata": { |
|
560 | "metadata": { | |
527 | "collapsed": false |
|
561 | "collapsed": false | |
528 | }, |
|
562 | }, | |
529 | "outputs": [], |
|
563 | "outputs": [], | |
530 | "source": [ |
|
564 | "source": [ | |
531 | "widgets.HTML(\n", |
|
565 | "widgets.HTML(\n", | |
532 | " value=\"Hello <b>World</b>\"\n", |
|
566 | " value=\"Hello <b>World</b>\"\n", | |
533 | ")" |
|
567 | ")" | |
534 | ] |
|
568 | ] | |
535 | }, |
|
569 | }, | |
536 | { |
|
570 | { | |
537 | "cell_type": "markdown", |
|
571 | "cell_type": "markdown", | |
538 | "metadata": { |
|
572 | "metadata": { | |
539 | "slideshow": { |
|
573 | "slideshow": { | |
540 | "slide_type": "slide" |
|
574 | "slide_type": "slide" | |
541 | } |
|
575 | } | |
542 | }, |
|
576 | }, | |
543 | "source": [ |
|
577 | "source": [ | |
544 | "## Button" |
|
578 | "## Button" | |
545 | ] |
|
579 | ] | |
546 | }, |
|
580 | }, | |
547 | { |
|
581 | { | |
548 | "cell_type": "code", |
|
582 | "cell_type": "code", | |
549 | "execution_count": null, |
|
583 | "execution_count": null, | |
550 | "metadata": { |
|
584 | "metadata": { | |
551 | "collapsed": false |
|
585 | "collapsed": false | |
552 | }, |
|
586 | }, | |
553 | "outputs": [], |
|
587 | "outputs": [], | |
554 | "source": [ |
|
588 | "source": [ | |
555 | "widgets.Button(description='Click me')" |
|
589 | "widgets.Button(description='Click me')" | |
556 | ] |
|
590 | ] | |
557 | }, |
|
591 | }, | |
558 | { |
|
592 | { | |
559 | "cell_type": "markdown", |
|
593 | "cell_type": "markdown", | |
560 | "metadata": {}, |
|
594 | "metadata": {}, | |
561 | "source": [ |
|
595 | "source": [ | |
562 | "[Index](Index.ipynb) - [Back](Widget Basics.ipynb) - [Next](Widget Events.ipynb)" |
|
596 | "[Index](Index.ipynb) - [Back](Widget Basics.ipynb) - [Next](Widget Events.ipynb)" | |
563 | ] |
|
597 | ] | |
564 | } |
|
598 | } | |
565 | ], |
|
599 | ], | |
566 | "metadata": { |
|
600 | "metadata": { | |
567 | "kernelspec": { |
|
601 | "kernelspec": { | |
568 | "display_name": "Python 3", |
|
602 | "display_name": "Python 3", | |
569 | "language": "python", |
|
603 | "language": "python", | |
570 | "name": "python3" |
|
604 | "name": "python3" | |
571 | }, |
|
605 | }, | |
572 | "language_info": { |
|
606 | "language_info": { | |
573 | "codemirror_mode": { |
|
607 | "codemirror_mode": { | |
574 | "name": "ipython", |
|
608 | "name": "ipython", | |
575 | "version": 3 |
|
609 | "version": 3 | |
576 | }, |
|
610 | }, | |
577 | "file_extension": ".py", |
|
611 | "file_extension": ".py", | |
578 | "mimetype": "text/x-python", |
|
612 | "mimetype": "text/x-python", | |
579 | "name": "python", |
|
613 | "name": "python", | |
580 | "nbconvert_exporter": "python", |
|
614 | "nbconvert_exporter": "python", | |
581 | "pygments_lexer": "ipython3", |
|
615 | "pygments_lexer": "ipython3", | |
582 | "version": "3.4.2" |
|
616 | "version": "3.4.2" | |
583 | } |
|
617 | } | |
584 | }, |
|
618 | }, | |
585 | "nbformat": 4, |
|
619 | "nbformat": 4, | |
586 | "nbformat_minor": 0 |
|
620 | "nbformat_minor": 0 | |
587 | } |
|
621 | } |
@@ -1,585 +1,585 b'' | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "markdown", |
|
4 | "cell_type": "markdown", | |
5 | "metadata": {}, |
|
5 | "metadata": {}, | |
6 | "source": [ |
|
6 | "source": [ | |
7 | "[Index](Index.ipynb) - [Back](Widget Events.ipynb) - [Next](Custom Widget - Hello World.ipynb)" |
|
7 | "[Index](Index.ipynb) - [Back](Widget Events.ipynb) - [Next](Custom Widget - Hello World.ipynb)" | |
8 | ] |
|
8 | ] | |
9 | }, |
|
9 | }, | |
10 | { |
|
10 | { | |
11 | "cell_type": "code", |
|
11 | "cell_type": "code", | |
12 | "execution_count": null, |
|
12 | "execution_count": null, | |
13 | "metadata": { |
|
13 | "metadata": { | |
14 | "collapsed": false |
|
14 | "collapsed": false | |
15 | }, |
|
15 | }, | |
16 | "outputs": [], |
|
16 | "outputs": [], | |
17 | "source": [ |
|
17 | "source": [ | |
18 | "%%html\n", |
|
18 | "%%html\n", | |
19 | "<style>\n", |
|
19 | "<style>\n", | |
20 | ".example-container { background: #999999; padding: 2px; min-height: 100px; }\n", |
|
20 | ".example-container { background: #999999; padding: 2px; min-height: 100px; }\n", | |
21 | ".example-container.sm { min-height: 50px; }\n", |
|
21 | ".example-container.sm { min-height: 50px; }\n", | |
22 | ".example-box { background: #9999FF; width: 50px; height: 50px; text-align: center; vertical-align: middle; color: white; font-weight: bold; margin: 2px;}\n", |
|
22 | ".example-box { background: #9999FF; width: 50px; height: 50px; text-align: center; vertical-align: middle; color: white; font-weight: bold; margin: 2px;}\n", | |
23 | ".example-box.med { width: 65px; height: 65px; } \n", |
|
23 | ".example-box.med { width: 65px; height: 65px; } \n", | |
24 | ".example-box.lrg { width: 80px; height: 80px; } \n", |
|
24 | ".example-box.lrg { width: 80px; height: 80px; } \n", | |
25 | "</style>" |
|
25 | "</style>" | |
26 | ] |
|
26 | ] | |
27 | }, |
|
27 | }, | |
28 | { |
|
28 | { | |
29 | "cell_type": "code", |
|
29 | "cell_type": "code", | |
30 | "execution_count": null, |
|
30 | "execution_count": null, | |
31 | "metadata": { |
|
31 | "metadata": { | |
32 | "collapsed": false |
|
32 | "collapsed": false | |
33 | }, |
|
33 | }, | |
34 | "outputs": [], |
|
34 | "outputs": [], | |
35 | "source": [ |
|
35 | "source": [ | |
36 | "from IPython.html import widgets\n", |
|
36 | "from IPython.html import widgets\n", | |
37 | "from IPython.display import display" |
|
37 | "from IPython.display import display" | |
38 | ] |
|
38 | ] | |
39 | }, |
|
39 | }, | |
40 | { |
|
40 | { | |
41 | "cell_type": "markdown", |
|
41 | "cell_type": "markdown", | |
42 | "metadata": { |
|
42 | "metadata": { | |
43 | "slideshow": { |
|
43 | "slideshow": { | |
44 | "slide_type": "slide" |
|
44 | "slide_type": "slide" | |
45 | } |
|
45 | } | |
46 | }, |
|
46 | }, | |
47 | "source": [ |
|
47 | "source": [ | |
48 | "# Widget Styling" |
|
48 | "# Widget Styling" | |
49 | ] |
|
49 | ] | |
50 | }, |
|
50 | }, | |
51 | { |
|
51 | { | |
52 | "cell_type": "markdown", |
|
52 | "cell_type": "markdown", | |
53 | "metadata": {}, |
|
53 | "metadata": {}, | |
54 | "source": [ |
|
54 | "source": [ | |
55 | "## Basic styling" |
|
55 | "## Basic styling" | |
56 | ] |
|
56 | ] | |
57 | }, |
|
57 | }, | |
58 | { |
|
58 | { | |
59 | "cell_type": "markdown", |
|
59 | "cell_type": "markdown", | |
60 | "metadata": {}, |
|
60 | "metadata": {}, | |
61 | "source": [ |
|
61 | "source": [ | |
62 | "The widgets distributed with IPython can be styled by setting the following traits:\n", |
|
62 | "The widgets distributed with IPython can be styled by setting the following traits:\n", | |
63 | "\n", |
|
63 | "\n", | |
64 | "- width \n", |
|
64 | "- width \n", | |
65 | "- height \n", |
|
65 | "- height \n", | |
66 | "- fore_color \n", |
|
66 | "- fore_color \n", | |
67 | "- back_color \n", |
|
67 | "- back_color \n", | |
68 | "- border_color \n", |
|
68 | "- border_color \n", | |
69 | "- border_width \n", |
|
69 | "- border_width \n", | |
70 | "- border_style \n", |
|
70 | "- border_style \n", | |
71 | "- font_style \n", |
|
71 | "- font_style \n", | |
72 | "- font_weight \n", |
|
72 | "- font_weight \n", | |
73 | "- font_size \n", |
|
73 | "- font_size \n", | |
74 | "- font_family \n", |
|
74 | "- font_family \n", | |
75 | "\n", |
|
75 | "\n", | |
76 | "The example below shows how a `Button` widget can be styled:" |
|
76 | "The example below shows how a `Button` widget can be styled:" | |
77 | ] |
|
77 | ] | |
78 | }, |
|
78 | }, | |
79 | { |
|
79 | { | |
80 | "cell_type": "code", |
|
80 | "cell_type": "code", | |
81 | "execution_count": null, |
|
81 | "execution_count": null, | |
82 | "metadata": { |
|
82 | "metadata": { | |
83 | "collapsed": false |
|
83 | "collapsed": false | |
84 | }, |
|
84 | }, | |
85 | "outputs": [], |
|
85 | "outputs": [], | |
86 | "source": [ |
|
86 | "source": [ | |
87 | "button = widgets.Button(\n", |
|
87 | "button = widgets.Button(\n", | |
88 | " description='Hello World!',\n", |
|
88 | " description='Hello World!',\n", | |
89 | " width=100, # Integers are interpreted as pixel measurements.\n", |
|
89 | " width=100, # Integers are interpreted as pixel measurements.\n", | |
90 | " height='2em', # em is valid HTML unit of measurement.\n", |
|
90 | " height='2em', # em is valid HTML unit of measurement.\n", | |
91 | " color='lime', # Colors can be set by name,\n", |
|
91 | " color='lime', # Colors can be set by name,\n", | |
92 | " background_color='#0022FF', # and also by color code.\n", |
|
92 | " background_color='#0022FF', # and also by color code.\n", | |
93 | " border_color='red')\n", |
|
93 | " border_color='red')\n", | |
94 | "display(button)" |
|
94 | "display(button)" | |
95 | ] |
|
95 | ] | |
96 | }, |
|
96 | }, | |
97 | { |
|
97 | { | |
98 | "cell_type": "markdown", |
|
98 | "cell_type": "markdown", | |
99 | "metadata": { |
|
99 | "metadata": { | |
100 | "slideshow": { |
|
100 | "slideshow": { | |
101 | "slide_type": "slide" |
|
101 | "slide_type": "slide" | |
102 | } |
|
102 | } | |
103 | }, |
|
103 | }, | |
104 | "source": [ |
|
104 | "source": [ | |
105 | "## Parent/child relationships" |
|
105 | "## Parent/child relationships" | |
106 | ] |
|
106 | ] | |
107 | }, |
|
107 | }, | |
108 | { |
|
108 | { | |
109 | "cell_type": "markdown", |
|
109 | "cell_type": "markdown", | |
110 | "metadata": {}, |
|
110 | "metadata": {}, | |
111 | "source": [ |
|
111 | "source": [ | |
112 | "To display widget A inside widget B, widget A must be a child of widget B. Widgets that can contain other widgets have a **`children` attribute**. This attribute can be **set via a keyword argument** in the widget's constructor **or after construction**. Calling display on an **object with children automatically displays those children**, too." |
|
112 | "To display widget A inside widget B, widget A must be a child of widget B. Widgets that can contain other widgets have a **`children` attribute**. This attribute can be **set via a keyword argument** in the widget's constructor **or after construction**. Calling display on an **object with children automatically displays those children**, too." | |
113 | ] |
|
113 | ] | |
114 | }, |
|
114 | }, | |
115 | { |
|
115 | { | |
116 | "cell_type": "code", |
|
116 | "cell_type": "code", | |
117 | "execution_count": null, |
|
117 | "execution_count": null, | |
118 | "metadata": { |
|
118 | "metadata": { | |
119 | "collapsed": false |
|
119 | "collapsed": false | |
120 | }, |
|
120 | }, | |
121 | "outputs": [], |
|
121 | "outputs": [], | |
122 | "source": [ |
|
122 | "source": [ | |
123 | "from IPython.display import display\n", |
|
123 | "from IPython.display import display\n", | |
124 | "\n", |
|
124 | "\n", | |
125 | "float_range = widgets.FloatSlider()\n", |
|
125 | "float_range = widgets.FloatSlider()\n", | |
126 | "string = widgets.Text(value='hi')\n", |
|
126 | "string = widgets.Text(value='hi')\n", | |
127 | "container = widgets.Box(children=[float_range, string])\n", |
|
127 | "container = widgets.Box(children=[float_range, string])\n", | |
128 | "\n", |
|
128 | "\n", | |
129 | "container.border_color = 'red'\n", |
|
129 | "container.border_color = 'red'\n", | |
130 | "container.border_style = 'dotted'\n", |
|
130 | "container.border_style = 'dotted'\n", | |
131 | "container.border_width = 3\n", |
|
131 | "container.border_width = 3\n", | |
132 | "display(container) # Displays the `container` and all of it's children." |
|
132 | "display(container) # Displays the `container` and all of it's children." | |
133 | ] |
|
133 | ] | |
134 | }, |
|
134 | }, | |
135 | { |
|
135 | { | |
136 | "cell_type": "markdown", |
|
136 | "cell_type": "markdown", | |
137 | "metadata": {}, |
|
137 | "metadata": {}, | |
138 | "source": [ |
|
138 | "source": [ | |
139 | "### After the parent is displayed" |
|
139 | "### After the parent is displayed" | |
140 | ] |
|
140 | ] | |
141 | }, |
|
141 | }, | |
142 | { |
|
142 | { | |
143 | "cell_type": "markdown", |
|
143 | "cell_type": "markdown", | |
144 | "metadata": { |
|
144 | "metadata": { | |
145 | "slideshow": { |
|
145 | "slideshow": { | |
146 | "slide_type": "slide" |
|
146 | "slide_type": "slide" | |
147 | } |
|
147 | } | |
148 | }, |
|
148 | }, | |
149 | "source": [ |
|
149 | "source": [ | |
150 | "Children **can be added to parents** after the parent has been displayed. The **parent is responsible for rendering its children**." |
|
150 | "Children **can be added to parents** after the parent has been displayed. The **parent is responsible for rendering its children**." | |
151 | ] |
|
151 | ] | |
152 | }, |
|
152 | }, | |
153 | { |
|
153 | { | |
154 | "cell_type": "code", |
|
154 | "cell_type": "code", | |
155 | "execution_count": null, |
|
155 | "execution_count": null, | |
156 | "metadata": { |
|
156 | "metadata": { | |
157 | "collapsed": false |
|
157 | "collapsed": false | |
158 | }, |
|
158 | }, | |
159 | "outputs": [], |
|
159 | "outputs": [], | |
160 | "source": [ |
|
160 | "source": [ | |
161 | "container = widgets.Box()\n", |
|
161 | "container = widgets.Box()\n", | |
162 | "container.border_color = 'red'\n", |
|
162 | "container.border_color = 'red'\n", | |
163 | "container.border_style = 'dotted'\n", |
|
163 | "container.border_style = 'dotted'\n", | |
164 | "container.border_width = 3\n", |
|
164 | "container.border_width = 3\n", | |
165 | "display(container)\n", |
|
165 | "display(container)\n", | |
166 | "\n", |
|
166 | "\n", | |
167 | "int_range = widgets.IntSlider()\n", |
|
167 | "int_range = widgets.IntSlider()\n", | |
168 | "container.children=[int_range]" |
|
168 | "container.children=[int_range]" | |
169 | ] |
|
169 | ] | |
170 | }, |
|
170 | }, | |
171 | { |
|
171 | { | |
172 | "cell_type": "markdown", |
|
172 | "cell_type": "markdown", | |
173 | "metadata": { |
|
173 | "metadata": { | |
174 | "slideshow": { |
|
174 | "slideshow": { | |
175 | "slide_type": "slide" |
|
175 | "slide_type": "slide" | |
176 | } |
|
176 | } | |
177 | }, |
|
177 | }, | |
178 | "source": [ |
|
178 | "source": [ | |
179 | "## Fancy boxes" |
|
179 | "## Fancy boxes" | |
180 | ] |
|
180 | ] | |
181 | }, |
|
181 | }, | |
182 | { |
|
182 | { | |
183 | "cell_type": "markdown", |
|
183 | "cell_type": "markdown", | |
184 | "metadata": {}, |
|
184 | "metadata": {}, | |
185 | "source": [ |
|
185 | "source": [ | |
186 | "If you need to display a more complicated set of widgets, there are **specialized containers** that you can use. To display **multiple sets of widgets**, you can use an **`Accordion` or a `Tab` in combination with one `Box` per set of widgets** (as seen below). The \"pages\" of these widgets are their children. To set the titles of the pages, one can **call `set_title`**." |
|
186 | "If you need to display a more complicated set of widgets, there are **specialized containers** that you can use. To display **multiple sets of widgets**, you can use an **`Accordion` or a `Tab` in combination with one `Box` per set of widgets** (as seen below). The \"pages\" of these widgets are their children. To set the titles of the pages, one can **call `set_title`**." | |
187 | ] |
|
187 | ] | |
188 | }, |
|
188 | }, | |
189 | { |
|
189 | { | |
190 | "cell_type": "markdown", |
|
190 | "cell_type": "markdown", | |
191 | "metadata": {}, |
|
191 | "metadata": {}, | |
192 | "source": [ |
|
192 | "source": [ | |
193 | "### Accordion" |
|
193 | "### Accordion" | |
194 | ] |
|
194 | ] | |
195 | }, |
|
195 | }, | |
196 | { |
|
196 | { | |
197 | "cell_type": "code", |
|
197 | "cell_type": "code", | |
198 | "execution_count": null, |
|
198 | "execution_count": null, | |
199 | "metadata": { |
|
199 | "metadata": { | |
200 | "collapsed": false |
|
200 | "collapsed": false | |
201 | }, |
|
201 | }, | |
202 | "outputs": [], |
|
202 | "outputs": [], | |
203 | "source": [ |
|
203 | "source": [ | |
204 | "name1 = widgets.Text(description='Location:')\n", |
|
204 | "name1 = widgets.Text(description='Location:')\n", | |
205 | "zip1 = widgets.BoundedIntText(description='Zip:', min=0, max=99999)\n", |
|
205 | "zip1 = widgets.BoundedIntText(description='Zip:', min=0, max=99999)\n", | |
206 | "page1 = widgets.Box(children=[name1, zip1])\n", |
|
206 | "page1 = widgets.Box(children=[name1, zip1])\n", | |
207 | "\n", |
|
207 | "\n", | |
208 | "name2 = widgets.Text(description='Location:')\n", |
|
208 | "name2 = widgets.Text(description='Location:')\n", | |
209 | "zip2 = widgets.BoundedIntText(description='Zip:', min=0, max=99999)\n", |
|
209 | "zip2 = widgets.BoundedIntText(description='Zip:', min=0, max=99999)\n", | |
210 | "page2 = widgets.Box(children=[name2, zip2])\n", |
|
210 | "page2 = widgets.Box(children=[name2, zip2])\n", | |
211 | "\n", |
|
211 | "\n", | |
212 | "accord = widgets.Accordion(children=[page1, page2])\n", |
|
212 | "accord = widgets.Accordion(children=[page1, page2])\n", | |
213 | "display(accord)\n", |
|
213 | "display(accord)\n", | |
214 | "\n", |
|
214 | "\n", | |
215 | "accord.set_title(0, 'From')\n", |
|
215 | "accord.set_title(0, 'From')\n", | |
216 | "accord.set_title(1, 'To')" |
|
216 | "accord.set_title(1, 'To')" | |
217 | ] |
|
217 | ] | |
218 | }, |
|
218 | }, | |
219 | { |
|
219 | { | |
220 | "cell_type": "markdown", |
|
220 | "cell_type": "markdown", | |
221 | "metadata": { |
|
221 | "metadata": { | |
222 | "slideshow": { |
|
222 | "slideshow": { | |
223 | "slide_type": "slide" |
|
223 | "slide_type": "slide" | |
224 | } |
|
224 | } | |
225 | }, |
|
225 | }, | |
226 | "source": [ |
|
226 | "source": [ | |
227 | "### TabWidget" |
|
227 | "### TabWidget" | |
228 | ] |
|
228 | ] | |
229 | }, |
|
229 | }, | |
230 | { |
|
230 | { | |
231 | "cell_type": "code", |
|
231 | "cell_type": "code", | |
232 | "execution_count": null, |
|
232 | "execution_count": null, | |
233 | "metadata": { |
|
233 | "metadata": { | |
234 | "collapsed": false |
|
234 | "collapsed": false | |
235 | }, |
|
235 | }, | |
236 | "outputs": [], |
|
236 | "outputs": [], | |
237 | "source": [ |
|
237 | "source": [ | |
238 | "name = widgets.Text(description='Name:')\n", |
|
238 | "name = widgets.Text(description='Name:')\n", | |
239 |
"color = widgets.Dropdown(description='Color:', |
|
239 | "color = widgets.Dropdown(description='Color:', options=['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'])\n", | |
240 | "page1 = widgets.Box(children=[name, color])\n", |
|
240 | "page1 = widgets.Box(children=[name, color])\n", | |
241 | "\n", |
|
241 | "\n", | |
242 | "age = widgets.IntSlider(description='Age:', min=0, max=120, value=50)\n", |
|
242 | "age = widgets.IntSlider(description='Age:', min=0, max=120, value=50)\n", | |
243 |
"gender = widgets.RadioButtons(description='Gender:', |
|
243 | "gender = widgets.RadioButtons(description='Gender:', options=['male', 'female'])\n", | |
244 | "page2 = widgets.Box(children=[age, gender])\n", |
|
244 | "page2 = widgets.Box(children=[age, gender])\n", | |
245 | "\n", |
|
245 | "\n", | |
246 | "tabs = widgets.Tab(children=[page1, page2])\n", |
|
246 | "tabs = widgets.Tab(children=[page1, page2])\n", | |
247 | "display(tabs)\n", |
|
247 | "display(tabs)\n", | |
248 | "\n", |
|
248 | "\n", | |
249 | "tabs.set_title(0, 'Name')\n", |
|
249 | "tabs.set_title(0, 'Name')\n", | |
250 | "tabs.set_title(1, 'Details')" |
|
250 | "tabs.set_title(1, 'Details')" | |
251 | ] |
|
251 | ] | |
252 | }, |
|
252 | }, | |
253 | { |
|
253 | { | |
254 | "cell_type": "markdown", |
|
254 | "cell_type": "markdown", | |
255 | "metadata": { |
|
255 | "metadata": { | |
256 | "slideshow": { |
|
256 | "slideshow": { | |
257 | "slide_type": "slide" |
|
257 | "slide_type": "slide" | |
258 | } |
|
258 | } | |
259 | }, |
|
259 | }, | |
260 | "source": [ |
|
260 | "source": [ | |
261 | "# Alignment" |
|
261 | "# Alignment" | |
262 | ] |
|
262 | ] | |
263 | }, |
|
263 | }, | |
264 | { |
|
264 | { | |
265 | "cell_type": "markdown", |
|
265 | "cell_type": "markdown", | |
266 | "metadata": {}, |
|
266 | "metadata": {}, | |
267 | "source": [ |
|
267 | "source": [ | |
268 | "Most widgets have a **`description` attribute**, which allows a label for the widget to be defined.\n", |
|
268 | "Most widgets have a **`description` attribute**, which allows a label for the widget to be defined.\n", | |
269 | "The label of the widget **has a fixed minimum width**.\n", |
|
269 | "The label of the widget **has a fixed minimum width**.\n", | |
270 | "The text of the label is **always right aligned and the widget is left aligned**:" |
|
270 | "The text of the label is **always right aligned and the widget is left aligned**:" | |
271 | ] |
|
271 | ] | |
272 | }, |
|
272 | }, | |
273 | { |
|
273 | { | |
274 | "cell_type": "code", |
|
274 | "cell_type": "code", | |
275 | "execution_count": null, |
|
275 | "execution_count": null, | |
276 | "metadata": { |
|
276 | "metadata": { | |
277 | "collapsed": false |
|
277 | "collapsed": false | |
278 | }, |
|
278 | }, | |
279 | "outputs": [], |
|
279 | "outputs": [], | |
280 | "source": [ |
|
280 | "source": [ | |
281 | "display(widgets.Text(description=\"a:\"))\n", |
|
281 | "display(widgets.Text(description=\"a:\"))\n", | |
282 | "display(widgets.Text(description=\"aa:\"))\n", |
|
282 | "display(widgets.Text(description=\"aa:\"))\n", | |
283 | "display(widgets.Text(description=\"aaa:\"))" |
|
283 | "display(widgets.Text(description=\"aaa:\"))" | |
284 | ] |
|
284 | ] | |
285 | }, |
|
285 | }, | |
286 | { |
|
286 | { | |
287 | "cell_type": "markdown", |
|
287 | "cell_type": "markdown", | |
288 | "metadata": { |
|
288 | "metadata": { | |
289 | "slideshow": { |
|
289 | "slideshow": { | |
290 | "slide_type": "slide" |
|
290 | "slide_type": "slide" | |
291 | } |
|
291 | } | |
292 | }, |
|
292 | }, | |
293 | "source": [ |
|
293 | "source": [ | |
294 | "If a **label is longer** than the minimum width, the **widget is shifted to the right**:" |
|
294 | "If a **label is longer** than the minimum width, the **widget is shifted to the right**:" | |
295 | ] |
|
295 | ] | |
296 | }, |
|
296 | }, | |
297 | { |
|
297 | { | |
298 | "cell_type": "code", |
|
298 | "cell_type": "code", | |
299 | "execution_count": null, |
|
299 | "execution_count": null, | |
300 | "metadata": { |
|
300 | "metadata": { | |
301 | "collapsed": false |
|
301 | "collapsed": false | |
302 | }, |
|
302 | }, | |
303 | "outputs": [], |
|
303 | "outputs": [], | |
304 | "source": [ |
|
304 | "source": [ | |
305 | "display(widgets.Text(description=\"a:\"))\n", |
|
305 | "display(widgets.Text(description=\"a:\"))\n", | |
306 | "display(widgets.Text(description=\"aa:\"))\n", |
|
306 | "display(widgets.Text(description=\"aa:\"))\n", | |
307 | "display(widgets.Text(description=\"aaa:\"))\n", |
|
307 | "display(widgets.Text(description=\"aaa:\"))\n", | |
308 | "display(widgets.Text(description=\"aaaaaaaaaaaaaaaaaa:\"))" |
|
308 | "display(widgets.Text(description=\"aaaaaaaaaaaaaaaaaa:\"))" | |
309 | ] |
|
309 | ] | |
310 | }, |
|
310 | }, | |
311 | { |
|
311 | { | |
312 | "cell_type": "markdown", |
|
312 | "cell_type": "markdown", | |
313 | "metadata": { |
|
313 | "metadata": { | |
314 | "slideshow": { |
|
314 | "slideshow": { | |
315 | "slide_type": "slide" |
|
315 | "slide_type": "slide" | |
316 | } |
|
316 | } | |
317 | }, |
|
317 | }, | |
318 | "source": [ |
|
318 | "source": [ | |
319 | "If a `description` is **not set** for the widget, the **label is not displayed**:" |
|
319 | "If a `description` is **not set** for the widget, the **label is not displayed**:" | |
320 | ] |
|
320 | ] | |
321 | }, |
|
321 | }, | |
322 | { |
|
322 | { | |
323 | "cell_type": "code", |
|
323 | "cell_type": "code", | |
324 | "execution_count": null, |
|
324 | "execution_count": null, | |
325 | "metadata": { |
|
325 | "metadata": { | |
326 | "collapsed": false |
|
326 | "collapsed": false | |
327 | }, |
|
327 | }, | |
328 | "outputs": [], |
|
328 | "outputs": [], | |
329 | "source": [ |
|
329 | "source": [ | |
330 | "display(widgets.Text(description=\"a:\"))\n", |
|
330 | "display(widgets.Text(description=\"a:\"))\n", | |
331 | "display(widgets.Text(description=\"aa:\"))\n", |
|
331 | "display(widgets.Text(description=\"aa:\"))\n", | |
332 | "display(widgets.Text(description=\"aaa:\"))\n", |
|
332 | "display(widgets.Text(description=\"aaa:\"))\n", | |
333 | "display(widgets.Text())" |
|
333 | "display(widgets.Text())" | |
334 | ] |
|
334 | ] | |
335 | }, |
|
335 | }, | |
336 | { |
|
336 | { | |
337 | "cell_type": "markdown", |
|
337 | "cell_type": "markdown", | |
338 | "metadata": { |
|
338 | "metadata": { | |
339 | "slideshow": { |
|
339 | "slideshow": { | |
340 | "slide_type": "slide" |
|
340 | "slide_type": "slide" | |
341 | } |
|
341 | } | |
342 | }, |
|
342 | }, | |
343 | "source": [ |
|
343 | "source": [ | |
344 | "## Flex boxes" |
|
344 | "## Flex boxes" | |
345 | ] |
|
345 | ] | |
346 | }, |
|
346 | }, | |
347 | { |
|
347 | { | |
348 | "cell_type": "markdown", |
|
348 | "cell_type": "markdown", | |
349 | "metadata": {}, |
|
349 | "metadata": {}, | |
350 | "source": [ |
|
350 | "source": [ | |
351 | "Widgets can be aligned using the `FlexBox`, `HBox`, and `VBox` widgets." |
|
351 | "Widgets can be aligned using the `FlexBox`, `HBox`, and `VBox` widgets." | |
352 | ] |
|
352 | ] | |
353 | }, |
|
353 | }, | |
354 | { |
|
354 | { | |
355 | "cell_type": "markdown", |
|
355 | "cell_type": "markdown", | |
356 | "metadata": { |
|
356 | "metadata": { | |
357 | "slideshow": { |
|
357 | "slideshow": { | |
358 | "slide_type": "slide" |
|
358 | "slide_type": "slide" | |
359 | } |
|
359 | } | |
360 | }, |
|
360 | }, | |
361 | "source": [ |
|
361 | "source": [ | |
362 | "### Application to widgets" |
|
362 | "### Application to widgets" | |
363 | ] |
|
363 | ] | |
364 | }, |
|
364 | }, | |
365 | { |
|
365 | { | |
366 | "cell_type": "markdown", |
|
366 | "cell_type": "markdown", | |
367 | "metadata": {}, |
|
367 | "metadata": {}, | |
368 | "source": [ |
|
368 | "source": [ | |
369 | "Widgets display vertically by default:" |
|
369 | "Widgets display vertically by default:" | |
370 | ] |
|
370 | ] | |
371 | }, |
|
371 | }, | |
372 | { |
|
372 | { | |
373 | "cell_type": "code", |
|
373 | "cell_type": "code", | |
374 | "execution_count": null, |
|
374 | "execution_count": null, | |
375 | "metadata": { |
|
375 | "metadata": { | |
376 | "collapsed": false |
|
376 | "collapsed": false | |
377 | }, |
|
377 | }, | |
378 | "outputs": [], |
|
378 | "outputs": [], | |
379 | "source": [ |
|
379 | "source": [ | |
380 | "buttons = [widgets.Button(description=str(i)) for i in range(3)]\n", |
|
380 | "buttons = [widgets.Button(description=str(i)) for i in range(3)]\n", | |
381 | "display(*buttons)" |
|
381 | "display(*buttons)" | |
382 | ] |
|
382 | ] | |
383 | }, |
|
383 | }, | |
384 | { |
|
384 | { | |
385 | "cell_type": "markdown", |
|
385 | "cell_type": "markdown", | |
386 | "metadata": { |
|
386 | "metadata": { | |
387 | "slideshow": { |
|
387 | "slideshow": { | |
388 | "slide_type": "slide" |
|
388 | "slide_type": "slide" | |
389 | } |
|
389 | } | |
390 | }, |
|
390 | }, | |
391 | "source": [ |
|
391 | "source": [ | |
392 | "### Using hbox" |
|
392 | "### Using hbox" | |
393 | ] |
|
393 | ] | |
394 | }, |
|
394 | }, | |
395 | { |
|
395 | { | |
396 | "cell_type": "markdown", |
|
396 | "cell_type": "markdown", | |
397 | "metadata": {}, |
|
397 | "metadata": {}, | |
398 | "source": [ |
|
398 | "source": [ | |
399 | "To make widgets display horizontally, you need to **child them to a `HBox` widget**." |
|
399 | "To make widgets display horizontally, you need to **child them to a `HBox` widget**." | |
400 | ] |
|
400 | ] | |
401 | }, |
|
401 | }, | |
402 | { |
|
402 | { | |
403 | "cell_type": "code", |
|
403 | "cell_type": "code", | |
404 | "execution_count": null, |
|
404 | "execution_count": null, | |
405 | "metadata": { |
|
405 | "metadata": { | |
406 | "collapsed": false |
|
406 | "collapsed": false | |
407 | }, |
|
407 | }, | |
408 | "outputs": [], |
|
408 | "outputs": [], | |
409 | "source": [ |
|
409 | "source": [ | |
410 | "container = widgets.HBox(children=buttons)\n", |
|
410 | "container = widgets.HBox(children=buttons)\n", | |
411 | "display(container)" |
|
411 | "display(container)" | |
412 | ] |
|
412 | ] | |
413 | }, |
|
413 | }, | |
414 | { |
|
414 | { | |
415 | "cell_type": "markdown", |
|
415 | "cell_type": "markdown", | |
416 | "metadata": {}, |
|
416 | "metadata": {}, | |
417 | "source": [ |
|
417 | "source": [ | |
418 | "By setting the width of the container to 100% and its `pack` to `center`, you can center the buttons." |
|
418 | "By setting the width of the container to 100% and its `pack` to `center`, you can center the buttons." | |
419 | ] |
|
419 | ] | |
420 | }, |
|
420 | }, | |
421 | { |
|
421 | { | |
422 | "cell_type": "code", |
|
422 | "cell_type": "code", | |
423 | "execution_count": null, |
|
423 | "execution_count": null, | |
424 | "metadata": { |
|
424 | "metadata": { | |
425 | "collapsed": false |
|
425 | "collapsed": false | |
426 | }, |
|
426 | }, | |
427 | "outputs": [], |
|
427 | "outputs": [], | |
428 | "source": [ |
|
428 | "source": [ | |
429 | "container.width = '100%'\n", |
|
429 | "container.width = '100%'\n", | |
430 | "container.pack = 'center'" |
|
430 | "container.pack = 'center'" | |
431 | ] |
|
431 | ] | |
432 | }, |
|
432 | }, | |
433 | { |
|
433 | { | |
434 | "cell_type": "markdown", |
|
434 | "cell_type": "markdown", | |
435 | "metadata": { |
|
435 | "metadata": { | |
436 | "slideshow": { |
|
436 | "slideshow": { | |
437 | "slide_type": "slide" |
|
437 | "slide_type": "slide" | |
438 | } |
|
438 | } | |
439 | }, |
|
439 | }, | |
440 | "source": [ |
|
440 | "source": [ | |
441 | "## Visibility" |
|
441 | "## Visibility" | |
442 | ] |
|
442 | ] | |
443 | }, |
|
443 | }, | |
444 | { |
|
444 | { | |
445 | "cell_type": "markdown", |
|
445 | "cell_type": "markdown", | |
446 | "metadata": {}, |
|
446 | "metadata": {}, | |
447 | "source": [ |
|
447 | "source": [ | |
448 | "Sometimes it is necessary to **hide or show widgets** in place, **without having to re-display** the widget.\n", |
|
448 | "Sometimes it is necessary to **hide or show widgets** in place, **without having to re-display** the widget.\n", | |
449 | "The `visible` property of widgets can be used to hide or show **widgets that have already been displayed** (as seen below). The `visible` property can be:\n", |
|
449 | "The `visible` property of widgets can be used to hide or show **widgets that have already been displayed** (as seen below). The `visible` property can be:\n", | |
450 | "* `True` - the widget is displayed\n", |
|
450 | "* `True` - the widget is displayed\n", | |
451 | "* `False` - the widget is hidden, and the empty space where the widget would be is collapsed\n", |
|
451 | "* `False` - the widget is hidden, and the empty space where the widget would be is collapsed\n", | |
452 | "* `None` - the widget is hidden, and the empty space where the widget would be is shown" |
|
452 | "* `None` - the widget is hidden, and the empty space where the widget would be is shown" | |
453 | ] |
|
453 | ] | |
454 | }, |
|
454 | }, | |
455 | { |
|
455 | { | |
456 | "cell_type": "code", |
|
456 | "cell_type": "code", | |
457 | "execution_count": null, |
|
457 | "execution_count": null, | |
458 | "metadata": { |
|
458 | "metadata": { | |
459 | "collapsed": false |
|
459 | "collapsed": false | |
460 | }, |
|
460 | }, | |
461 | "outputs": [], |
|
461 | "outputs": [], | |
462 | "source": [ |
|
462 | "source": [ | |
463 | "w1 = widgets.Latex(value=\"First line\")\n", |
|
463 | "w1 = widgets.Latex(value=\"First line\")\n", | |
464 | "w2 = widgets.Latex(value=\"Second line\")\n", |
|
464 | "w2 = widgets.Latex(value=\"Second line\")\n", | |
465 | "w3 = widgets.Latex(value=\"Third line\")\n", |
|
465 | "w3 = widgets.Latex(value=\"Third line\")\n", | |
466 | "display(w1, w2, w3)" |
|
466 | "display(w1, w2, w3)" | |
467 | ] |
|
467 | ] | |
468 | }, |
|
468 | }, | |
469 | { |
|
469 | { | |
470 | "cell_type": "code", |
|
470 | "cell_type": "code", | |
471 | "execution_count": null, |
|
471 | "execution_count": null, | |
472 | "metadata": { |
|
472 | "metadata": { | |
473 | "collapsed": true |
|
473 | "collapsed": true | |
474 | }, |
|
474 | }, | |
475 | "outputs": [], |
|
475 | "outputs": [], | |
476 | "source": [ |
|
476 | "source": [ | |
477 | "w2.visible=None" |
|
477 | "w2.visible=None" | |
478 | ] |
|
478 | ] | |
479 | }, |
|
479 | }, | |
480 | { |
|
480 | { | |
481 | "cell_type": "code", |
|
481 | "cell_type": "code", | |
482 | "execution_count": null, |
|
482 | "execution_count": null, | |
483 | "metadata": { |
|
483 | "metadata": { | |
484 | "collapsed": false |
|
484 | "collapsed": false | |
485 | }, |
|
485 | }, | |
486 | "outputs": [], |
|
486 | "outputs": [], | |
487 | "source": [ |
|
487 | "source": [ | |
488 | "w2.visible=False" |
|
488 | "w2.visible=False" | |
489 | ] |
|
489 | ] | |
490 | }, |
|
490 | }, | |
491 | { |
|
491 | { | |
492 | "cell_type": "code", |
|
492 | "cell_type": "code", | |
493 | "execution_count": null, |
|
493 | "execution_count": null, | |
494 | "metadata": { |
|
494 | "metadata": { | |
495 | "collapsed": false |
|
495 | "collapsed": false | |
496 | }, |
|
496 | }, | |
497 | "outputs": [], |
|
497 | "outputs": [], | |
498 | "source": [ |
|
498 | "source": [ | |
499 | "w2.visible=True" |
|
499 | "w2.visible=True" | |
500 | ] |
|
500 | ] | |
501 | }, |
|
501 | }, | |
502 | { |
|
502 | { | |
503 | "cell_type": "markdown", |
|
503 | "cell_type": "markdown", | |
504 | "metadata": { |
|
504 | "metadata": { | |
505 | "slideshow": { |
|
505 | "slideshow": { | |
506 | "slide_type": "slide" |
|
506 | "slide_type": "slide" | |
507 | } |
|
507 | } | |
508 | }, |
|
508 | }, | |
509 | "source": [ |
|
509 | "source": [ | |
510 | "### Another example" |
|
510 | "### Another example" | |
511 | ] |
|
511 | ] | |
512 | }, |
|
512 | }, | |
513 | { |
|
513 | { | |
514 | "cell_type": "markdown", |
|
514 | "cell_type": "markdown", | |
515 | "metadata": {}, |
|
515 | "metadata": {}, | |
516 | "source": [ |
|
516 | "source": [ | |
517 | "In the example below, a form is rendered, which conditionally displays widgets depending on the state of other widgets. Try toggling the student checkbox." |
|
517 | "In the example below, a form is rendered, which conditionally displays widgets depending on the state of other widgets. Try toggling the student checkbox." | |
518 | ] |
|
518 | ] | |
519 | }, |
|
519 | }, | |
520 | { |
|
520 | { | |
521 | "cell_type": "code", |
|
521 | "cell_type": "code", | |
522 | "execution_count": null, |
|
522 | "execution_count": null, | |
523 | "metadata": { |
|
523 | "metadata": { | |
524 | "collapsed": false |
|
524 | "collapsed": false | |
525 | }, |
|
525 | }, | |
526 | "outputs": [], |
|
526 | "outputs": [], | |
527 | "source": [ |
|
527 | "source": [ | |
528 | "form = widgets.VBox()\n", |
|
528 | "form = widgets.VBox()\n", | |
529 | "first = widgets.Text(description=\"First Name:\")\n", |
|
529 | "first = widgets.Text(description=\"First Name:\")\n", | |
530 | "last = widgets.Text(description=\"Last Name:\")\n", |
|
530 | "last = widgets.Text(description=\"Last Name:\")\n", | |
531 | "\n", |
|
531 | "\n", | |
532 | "student = widgets.Checkbox(description=\"Student:\", value=False)\n", |
|
532 | "student = widgets.Checkbox(description=\"Student:\", value=False)\n", | |
533 | "school_info = widgets.VBox(visible=False, children=[\n", |
|
533 | "school_info = widgets.VBox(visible=False, children=[\n", | |
534 | " widgets.Text(description=\"School:\"),\n", |
|
534 | " widgets.Text(description=\"School:\"),\n", | |
535 | " widgets.IntText(description=\"Grade:\", min=0, max=12)\n", |
|
535 | " widgets.IntText(description=\"Grade:\", min=0, max=12)\n", | |
536 | " ])\n", |
|
536 | " ])\n", | |
537 | "\n", |
|
537 | "\n", | |
538 | "pet = widgets.Text(description=\"Pet's Name:\")\n", |
|
538 | "pet = widgets.Text(description=\"Pet's Name:\")\n", | |
539 | "form.children = [first, last, student, school_info, pet]\n", |
|
539 | "form.children = [first, last, student, school_info, pet]\n", | |
540 | "display(form)\n", |
|
540 | "display(form)\n", | |
541 | "\n", |
|
541 | "\n", | |
542 | "def on_student_toggle(name, value):\n", |
|
542 | "def on_student_toggle(name, value):\n", | |
543 | " if value:\n", |
|
543 | " if value:\n", | |
544 | " school_info.visible = True\n", |
|
544 | " school_info.visible = True\n", | |
545 | " else:\n", |
|
545 | " else:\n", | |
546 | " school_info.visible = False\n", |
|
546 | " school_info.visible = False\n", | |
547 | "student.on_trait_change(on_student_toggle, 'value')\n" |
|
547 | "student.on_trait_change(on_student_toggle, 'value')\n" | |
548 | ] |
|
548 | ] | |
549 | }, |
|
549 | }, | |
550 | { |
|
550 | { | |
551 | "cell_type": "markdown", |
|
551 | "cell_type": "markdown", | |
552 | "metadata": {}, |
|
552 | "metadata": {}, | |
553 | "source": [ |
|
553 | "source": [ | |
554 | "[Index](Index.ipynb) - [Back](Widget Events.ipynb) - [Next](Custom Widget - Hello World.ipynb)" |
|
554 | "[Index](Index.ipynb) - [Back](Widget Events.ipynb) - [Next](Custom Widget - Hello World.ipynb)" | |
555 | ] |
|
555 | ] | |
556 | } |
|
556 | } | |
557 | ], |
|
557 | ], | |
558 | "metadata": { |
|
558 | "metadata": { | |
559 | "cell_tags": [ |
|
559 | "cell_tags": [ | |
560 | [ |
|
560 | [ | |
561 | "<None>", |
|
561 | "<None>", | |
562 | null |
|
562 | null | |
563 | ] |
|
563 | ] | |
564 | ], |
|
564 | ], | |
565 | "kernelspec": { |
|
565 | "kernelspec": { | |
566 | "display_name": "Python 3", |
|
566 | "display_name": "Python 3", | |
567 | "language": "python", |
|
567 | "language": "python", | |
568 | "name": "python3" |
|
568 | "name": "python3" | |
569 | }, |
|
569 | }, | |
570 | "language_info": { |
|
570 | "language_info": { | |
571 | "codemirror_mode": { |
|
571 | "codemirror_mode": { | |
572 | "name": "ipython", |
|
572 | "name": "ipython", | |
573 | "version": 3 |
|
573 | "version": 3 | |
574 | }, |
|
574 | }, | |
575 | "file_extension": ".py", |
|
575 | "file_extension": ".py", | |
576 | "mimetype": "text/x-python", |
|
576 | "mimetype": "text/x-python", | |
577 | "name": "python", |
|
577 | "name": "python", | |
578 | "nbconvert_exporter": "python", |
|
578 | "nbconvert_exporter": "python", | |
579 | "pygments_lexer": "ipython3", |
|
579 | "pygments_lexer": "ipython3", | |
580 | "version": "3.4.2" |
|
580 | "version": "3.4.2" | |
581 | } |
|
581 | } | |
582 | }, |
|
582 | }, | |
583 | "nbformat": 4, |
|
583 | "nbformat": 4, | |
584 | "nbformat_minor": 0 |
|
584 | "nbformat_minor": 0 | |
585 | } |
|
585 | } |
General Comments 0
You need to be logged in to leave comments.
Login now