##// END OF EJS Templates
Widget styling updates for pydata2014
Jonathan Frederic -
Show More
This diff has been collapsed as it changes many lines, (1056 lines changed) Show them Hide them
@@ -7,7 +7,7 b''
7 ]
7 ]
8 ],
8 ],
9 "name": "",
9 "name": "",
10 "signature": "sha256:cd7d3d42126bdbf20c087014460779dfbdb0a63dcb8f489ba7ebfc230a685edd"
10 "signature": "sha256:55ee4a4661f0939c40550752218a4c127b985536811190a2b7e581d7fe25cec7"
11 },
11 },
12 "nbformat": 3,
12 "nbformat": 3,
13 "nbformat_minor": 0,
13 "nbformat_minor": 0,
@@ -18,243 +18,865 b''
18 "cell_type": "code",
18 "cell_type": "code",
19 "collapsed": false,
19 "collapsed": false,
20 "input": [
20 "input": [
21 "from IPython.html import widgets # Widget definitions\n",
21 "%%html\n",
22 "from IPython.display import display # Used to display widgets in the notebook"
22 "<style>\n",
23 ".example-container { background: #999999; padding: 2px; min-height: 100px; }\n",
24 ".example-container.sm { min-height: 50px; }\n",
25 ".example-box { background: #9999FF; width: 50px; height: 50px; text-align: center; vertical-align: middle; color: white; font-weight: bold; margin: 2px;}\n",
26 ".example-box.med { width: 65px; height: 65px; } \n",
27 ".example-box.lrg { width: 80px; height: 80px; } \n",
28 "</style>"
29 ],
30 "language": "python",
31 "metadata": {},
32 "outputs": [
33 {
34 "html": [
35 "<style>\n",
36 ".example-container { background: #999999; padding: 2px; min-height: 100px; }\n",
37 ".example-container.sm { min-height: 50px; }\n",
38 ".example-box { background: #9999FF; width: 50px; height: 50px; text-align: center; vertical-align: middle; color: white; font-weight: bold; margin: 2px;}\n",
39 ".example-box.med { width: 65px; height: 65px; } \n",
40 ".example-box.lrg { width: 80px; height: 80px; } \n",
41 "</style>"
42 ],
43 "metadata": {},
44 "output_type": "display_data",
45 "text": [
46 "<IPython.core.display.HTML object>"
47 ]
48 }
49 ],
50 "prompt_number": 145
51 },
52 {
53 "cell_type": "heading",
54 "level": 1,
55 "metadata": {},
56 "source": [
57 "CSS"
58 ]
59 },
60 {
61 "cell_type": "markdown",
62 "metadata": {},
63 "source": [
64 "Since the representation of the widget you see is a browser element, Cascading Style Sheets (CSS) are used for styling. Widgets have a `set_css` method that allows you to add and remove CSS properties from your elements. The following example shows had `set_css` can be used to set the background color of a `TextWidget`."
65 ]
66 },
67 {
68 "cell_type": "code",
69 "collapsed": false,
70 "input": [
71 "from IPython.html import widgets\n",
72 "text = widgets.TextWidget()\n",
73 "text.set_css('background', 'lime')\n",
74 "text "
75 ],
76 "language": "python",
77 "metadata": {},
78 "outputs": [],
79 "prompt_number": 146
80 },
81 {
82 "cell_type": "markdown",
83 "metadata": {},
84 "source": [
85 "In the example above, the color `lime` is specified by name. CSS also supports specifying colors by a 3 byte hexadecimal string. The first byte is red, second green, and third blue. The following example sets the `TextWidget`'s background to blue."
86 ]
87 },
88 {
89 "cell_type": "code",
90 "collapsed": false,
91 "input": [
92 "text.set_css('background', '#0000FF')"
93 ],
94 "language": "python",
95 "metadata": {},
96 "outputs": [],
97 "prompt_number": 147
98 },
99 {
100 "cell_type": "markdown",
101 "metadata": {},
102 "source": [
103 "Font color is just `color`."
104 ]
105 },
106 {
107 "cell_type": "code",
108 "collapsed": false,
109 "input": [
110 "text.set_css('color', '#FFFFFF')"
111 ],
112 "language": "python",
113 "metadata": {},
114 "outputs": [],
115 "prompt_number": 148
116 },
117 {
118 "cell_type": "markdown",
119 "metadata": {},
120 "source": [
121 "To remove the styling, you can call `set_css` again, but use an empty string instead of a color value."
122 ]
123 },
124 {
125 "cell_type": "code",
126 "collapsed": false,
127 "input": [
128 "text.set_css('background', '')"
129 ],
130 "language": "python",
131 "metadata": {},
132 "outputs": [],
133 "prompt_number": 149
134 },
135 {
136 "cell_type": "markdown",
137 "metadata": {},
138 "source": [
139 "CSS is also used to set the height and width of controls. The `set_css` method also can accept a single dictionary with multiple CSS properties (as seen below)."
140 ]
141 },
142 {
143 "cell_type": "code",
144 "collapsed": false,
145 "input": [
146 "btn = widgets.ButtonWidget()\n",
147 "btn.set_css({\n",
148 " 'width': '100px',\n",
149 " 'height': '100px',\n",
150 "})\n",
151 "btn"
152 ],
153 "language": "python",
154 "metadata": {},
155 "outputs": [],
156 "prompt_number": 150
157 },
158 {
159 "cell_type": "markdown",
160 "metadata": {},
161 "source": [
162 "For more information about what can be done with CSS, please refer to the [Mozilla Developer Network's series on it](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started).\n"
163 ]
164 },
165 {
166 "cell_type": "heading",
167 "level": 1,
168 "metadata": {},
169 "source": [
170 "Parent/Child Relationships"
171 ]
172 },
173 {
174 "cell_type": "markdown",
175 "metadata": {},
176 "source": [
177 "To display widget A inside widget B, widget A must be a child of widget B. Only one instance of any particular widget can be child of another. In other words, *widget A* cannot have *widget B* listed twice in it's list of children.\n",
178 "\n",
179 "Widgets that can contain other widgets have a `children` attribute. This attribute can be set via a kwarg in the widget's constructor or after construction. Calling display on an object with children automatically displays those children, too."
180 ]
181 },
182 {
183 "cell_type": "code",
184 "collapsed": false,
185 "input": [
186 "\n",
187 "from IPython.display import display\n",
188 "\n",
189 "float_range = widgets.FloatSliderWidget()\n",
190 "string = widgets.TextWidget(value='hi')\n",
191 "container = widgets.ContainerWidget(children=[float_range, string])\n",
192 "\n",
193 "container.set_css('border', '3px dotted red')\n",
194 "display(container) # Displays the `container` and all of it's children."
195 ],
196 "language": "python",
197 "metadata": {},
198 "outputs": [],
199 "prompt_number": 151
200 },
201 {
202 "cell_type": "markdown",
203 "metadata": {},
204 "source": [
205 "Children can also be added to parents after the parent has been displayed. The parent is responsible for rendering its children."
206 ]
207 },
208 {
209 "cell_type": "code",
210 "collapsed": false,
211 "input": [
212 "container = widgets.ContainerWidget()\n",
213 "container.set_css('border', '3px dotted red')\n",
214 "display(container)\n",
215 "\n",
216 "int_range = widgets.IntSliderWidget()\n",
217 "container.children=[int_range]"
218 ],
219 "language": "python",
220 "metadata": {},
221 "outputs": [],
222 "prompt_number": 152
223 },
224 {
225 "cell_type": "heading",
226 "level": 2,
227 "metadata": {},
228 "source": [
229 "Fancy containers"
230 ]
231 },
232 {
233 "cell_type": "markdown",
234 "metadata": {},
235 "source": [
236 "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 `AccordionWidget` or a `TabWidget` in combination with one `ContainerWidget` per set of widgets (as seen below). The \"pages\" of these widgets are their children. To set the titles of the pages, one must call `set_title` after the widget has been displayed."
237 ]
238 },
239 {
240 "cell_type": "heading",
241 "level": 3,
242 "metadata": {},
243 "source": [
244 "AccordionWidget"
245 ]
246 },
247 {
248 "cell_type": "code",
249 "collapsed": false,
250 "input": [
251 "name1 = widgets.TextWidget(description='Location:')\n",
252 "zip1 = widgets.BoundedIntTextWidget(description='Zip:', min=0, max=99999)\n",
253 "page1 = widgets.ContainerWidget(children=[name1, zip1])\n",
254 "\n",
255 "name2 = widgets.TextWidget(description='Location:')\n",
256 "zip2 = widgets.BoundedIntTextWidget(description='Zip:', min=0, max=99999)\n",
257 "page2 = widgets.ContainerWidget(children=[name2, zip2])\n",
258 "\n",
259 "accord = widgets.AccordionWidget(children=[page1, page2])\n",
260 "display(accord)\n",
261 "\n",
262 "accord.set_title(0, 'From')\n",
263 "accord.set_title(1, 'To')"
264 ],
265 "language": "python",
266 "metadata": {},
267 "outputs": [],
268 "prompt_number": 153
269 },
270 {
271 "cell_type": "heading",
272 "level": 3,
273 "metadata": {},
274 "source": [
275 "TabWidget"
276 ]
277 },
278 {
279 "cell_type": "code",
280 "collapsed": false,
281 "input": [
282 "name = widgets.TextWidget(description='Name:')\n",
283 "color = widgets.DropdownWidget(description='Color:', values=['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'])\n",
284 "page1 = widgets.ContainerWidget(children=[name, color])\n",
285 "\n",
286 "age = widgets.IntSliderWidget(description='Age:', min=0, max=120, value=50)\n",
287 "gender = widgets.RadioButtonsWidget(description='Gender:', values=['male', 'female'])\n",
288 "page2 = widgets.ContainerWidget(children=[age, gender])\n",
289 "\n",
290 "tabs = widgets.TabWidget(children=[page1, page2])\n",
291 "display(tabs)\n",
292 "\n",
293 "tabs.set_title(0, 'Name')\n",
294 "tabs.set_title(1, 'Details')"
295 ],
296 "language": "python",
297 "metadata": {},
298 "outputs": [],
299 "prompt_number": 154
300 },
301 {
302 "cell_type": "heading",
303 "level": 3,
304 "metadata": {},
305 "source": [
306 "PopupWidget"
307 ]
308 },
309 {
310 "cell_type": "markdown",
311 "metadata": {},
312 "source": [
313 "Unlike the other two special containers, the `PopupWidget` is only designed to display one set of widgets. The `PopupWidget` can be used to display widgets outside of the widget area. "
314 ]
315 },
316 {
317 "cell_type": "code",
318 "collapsed": false,
319 "input": [
320 "counter = widgets.IntTextWidget(description='Counter:')\n",
321 "popup = widgets.PopupWidget(children=[counter], description='Popup Demo', button_text='Popup Button')\n",
322 "display(popup)"
323 ],
324 "language": "python",
325 "metadata": {},
326 "outputs": [],
327 "prompt_number": 155
328 },
329 {
330 "cell_type": "code",
331 "collapsed": false,
332 "input": [
333 "counter.value += 1"
334 ],
335 "language": "python",
336 "metadata": {},
337 "outputs": [],
338 "prompt_number": 156
339 },
340 {
341 "cell_type": "code",
342 "collapsed": false,
343 "input": [],
344 "language": "python",
345 "metadata": {},
346 "outputs": [],
347 "prompt_number": 156
348 },
349 {
350 "cell_type": "code",
351 "collapsed": false,
352 "input": [],
353 "language": "python",
354 "metadata": {},
355 "outputs": [],
356 "prompt_number": 156
357 },
358 {
359 "cell_type": "code",
360 "collapsed": false,
361 "input": [],
362 "language": "python",
363 "metadata": {},
364 "outputs": [],
365 "prompt_number": 156
366 },
367 {
368 "cell_type": "code",
369 "collapsed": false,
370 "input": [],
371 "language": "python",
372 "metadata": {},
373 "outputs": [],
374 "prompt_number": 156
375 },
376 {
377 "cell_type": "code",
378 "collapsed": false,
379 "input": [],
380 "language": "python",
381 "metadata": {},
382 "outputs": [],
383 "prompt_number": 156
384 },
385 {
386 "cell_type": "code",
387 "collapsed": false,
388 "input": [],
389 "language": "python",
390 "metadata": {},
391 "outputs": [],
392 "prompt_number": 156
393 },
394 {
395 "cell_type": "code",
396 "collapsed": false,
397 "input": [],
398 "language": "python",
399 "metadata": {},
400 "outputs": [],
401 "prompt_number": 156
402 },
403 {
404 "cell_type": "code",
405 "collapsed": false,
406 "input": [],
407 "language": "python",
408 "metadata": {},
409 "outputs": [],
410 "prompt_number": 156
411 },
412 {
413 "cell_type": "code",
414 "collapsed": false,
415 "input": [],
416 "language": "python",
417 "metadata": {},
418 "outputs": [],
419 "prompt_number": 156
420 },
421 {
422 "cell_type": "code",
423 "collapsed": false,
424 "input": [],
425 "language": "python",
426 "metadata": {},
427 "outputs": [],
428 "prompt_number": 156
429 },
430 {
431 "cell_type": "code",
432 "collapsed": false,
433 "input": [],
434 "language": "python",
435 "metadata": {},
436 "outputs": [],
437 "prompt_number": 156
438 },
439 {
440 "cell_type": "code",
441 "collapsed": false,
442 "input": [],
443 "language": "python",
444 "metadata": {},
445 "outputs": [],
446 "prompt_number": 156
447 },
448 {
449 "cell_type": "code",
450 "collapsed": false,
451 "input": [],
452 "language": "python",
453 "metadata": {},
454 "outputs": [],
455 "prompt_number": 156
456 },
457 {
458 "cell_type": "code",
459 "collapsed": false,
460 "input": [],
461 "language": "python",
462 "metadata": {},
463 "outputs": [],
464 "prompt_number": 156
465 },
466 {
467 "cell_type": "code",
468 "collapsed": false,
469 "input": [
470 "counter.value += 1"
471 ],
472 "language": "python",
473 "metadata": {},
474 "outputs": [],
475 "prompt_number": 157
476 },
477 {
478 "cell_type": "code",
479 "collapsed": false,
480 "input": [
481 "popup.close()"
23 ],
482 ],
24 "language": "python",
483 "language": "python",
25 "metadata": {},
484 "metadata": {},
26 "outputs": [],
485 "outputs": [],
27 "prompt_number": 1
486 "prompt_number": 158
28 },
487 },
29 {
488 {
30 "cell_type": "heading",
489 "cell_type": "heading",
31 "level": 1,
490 "level": 1,
32 "metadata": {},
491 "metadata": {},
33 "source": [
492 "source": [
34 "CSS"
493 "Alignment"
35 ]
494 ]
36 },
495 },
37 {
496 {
38 "cell_type": "markdown",
497 "cell_type": "markdown",
39 "metadata": {},
498 "metadata": {},
40 "source": [
499 "source": [
41 "When trying to design an attractive widget GUI, styling becomes important.\n",
500 "Most widgets have a `description` attribute, which allows a label for the widget to be defined.\n",
42 "Most widget views are DOM (document object model) elements that can be controlled with CSS.\n",
501 "The label of the widget has a fixed minimum width.\n",
43 "There are two helper methods that allow the manipulation of the widget's CSS.\n",
502 "The text of the label is always right aligned and the widget is left aligned:"
44 "The first is the `Widget.set_css` method.\n",
45 "This method allows one or more CSS attributes to be set at once. "
46 ]
503 ]
47 },
504 },
48 {
505 {
49 "cell_type": "code",
506 "cell_type": "code",
50 "collapsed": false,
507 "collapsed": false,
51 "input": [
508 "input": [
52 "print(widgets.DOMWidget.set_css.__doc__)"
509 "display(widgets.TextWidget(description=\"a:\"))\n",
510 "display(widgets.TextWidget(description=\"aa:\"))\n",
511 "display(widgets.TextWidget(description=\"aaa:\"))"
53 ],
512 ],
54 "language": "python",
513 "language": "python",
55 "metadata": {},
514 "metadata": {},
56 "outputs": [
515 "outputs": [],
57 {
516 "prompt_number": 159
58 "output_type": "stream",
59 "stream": "stdout",
60 "text": [
61 "Set one or more CSS properties of the widget.\n",
62 "\n",
63 " This function has two signatures:\n",
64 " - set_css(css_dict, selector='')\n",
65 " - set_css(key, value, selector='')\n",
66 "\n",
67 " Parameters\n",
68 " ----------\n",
69 " css_dict : dict\n",
70 " CSS key/value pairs to apply\n",
71 " key: unicode\n",
72 " CSS key\n",
73 " value:\n",
74 " CSS value\n",
75 " selector: unicode (optional, kwarg only)\n",
76 " JQuery selector to use to apply the CSS key/value. If no selector \n",
77 " is provided, an empty selector is used. An empty selector makes the \n",
78 " front-end try to apply the css to a default element. The default\n",
79 " element is an attribute unique to each view, which is a DOM element\n",
80 " of the view that should be styled with common CSS (see \n",
81 " `$el_to_style` in the Javascript code).\n",
82 " \n"
83 ]
84 }
85 ],
86 "prompt_number": 2
87 },
517 },
88 {
518 {
89 "cell_type": "markdown",
519 "cell_type": "markdown",
90 "metadata": {},
520 "metadata": {},
91 "source": [
521 "source": [
92 "The second is `get_css` which allows CSS attributesto be read.\n",
522 "If a label is longer than the minimum width, the widget is shifted to the right:"
93 "Note that this method will only read CSS attributes that have been set using the `set_css` method."
94 ]
523 ]
95 },
524 },
96 {
525 {
97 "cell_type": "code",
526 "cell_type": "code",
98 "collapsed": false,
527 "collapsed": false,
99 "input": [
528 "input": [
100 "print(widgets.DOMWidget.get_css.__doc__)"
529 "display(widgets.TextWidget(description=\"a:\"))\n",
530 "display(widgets.TextWidget(description=\"aa:\"))\n",
531 "display(widgets.TextWidget(description=\"aaa:\"))\n",
532 "display(widgets.TextWidget(description=\"aaaaaaaaaaaaaaaaaa:\"))"
101 ],
533 ],
102 "language": "python",
534 "language": "python",
103 "metadata": {},
535 "metadata": {},
104 "outputs": [
536 "outputs": [],
105 {
537 "prompt_number": 160
106 "output_type": "stream",
107 "stream": "stdout",
108 "text": [
109 "Get a CSS property of the widget.\n",
110 "\n",
111 " Note: This function does not actually request the CSS from the \n",
112 " front-end; Only properties that have been set with set_css can be read.\n",
113 "\n",
114 " Parameters\n",
115 " ----------\n",
116 " key: unicode\n",
117 " CSS key\n",
118 " selector: unicode (optional)\n",
119 " JQuery selector used when the CSS key/value was set.\n",
120 " \n"
121 ]
122 }
123 ],
124 "prompt_number": 3
125 },
538 },
126 {
539 {
127 "cell_type": "markdown",
540 "cell_type": "markdown",
128 "metadata": {},
541 "metadata": {},
129 "source": [
542 "source": [
130 "Below is an example that applies CSS attributes to a container to emphasize text."
543 "If a `description` is not set for the widget, the label is not displayed:"
131 ]
544 ]
132 },
545 },
133 {
546 {
134 "cell_type": "code",
547 "cell_type": "code",
135 "collapsed": false,
548 "collapsed": false,
136 "input": [
549 "input": [
137 "label = widgets.LatexWidget()\n",
550 "display(widgets.TextWidget(description=\"a:\"))\n",
138 "label.value = \"$\\\\textbf{ALERT:} Hello World!$\"\n",
551 "display(widgets.TextWidget(description=\"aa:\"))\n",
139 "container = widgets.ContainerWidget(children=[label])\n",
552 "display(widgets.TextWidget(description=\"aaa:\"))\n",
140 "\n",
553 "display(widgets.TextWidget())"
141 "# set_css used to set a single CSS attribute.\n",
142 "container.set_css('border', '3px solid black') # Border the container\n",
143 "\n",
144 "# set_css used to set multiple CSS attributes.\n",
145 "container.set_css({'padding': '6px', # Add padding to the container\n",
146 " 'background': 'yellow'}) # Fill the container yellow\n",
147 "\n",
148 "display(container)"
149 ],
554 ],
150 "language": "python",
555 "language": "python",
151 "metadata": {},
556 "metadata": {},
152 "outputs": [],
557 "outputs": [],
153 "prompt_number": 4
558 "prompt_number": 161
154 },
559 },
155 {
560 {
156 "cell_type": "heading",
561 "cell_type": "heading",
157 "level": 1,
562 "level": 1,
158 "metadata": {},
563 "metadata": {},
159 "source": [
564 "source": [
160 "CSS Classes"
565 "DOM Classes"
566 ]
567 },
568 {
569 "cell_type": "markdown",
570 "metadata": {},
571 "source": [
572 "IPython defines a large number of DOM (document object model) classes that you can apply to your widgets. Applying a DOM class causes all of the CSS associated with that class to be applied to the element. Classes can be applied and removed using the `add_class` and `remove_class` methods after a widget has been displayed. The majority of DOM classes defined by IPython are actually Bootstrap classes. For more information on Bootstrap classes and CSS, please refer to [Bootstrap's website](http://getbootstrap.com/2.3.2/)."
573 ]
574 },
575 {
576 "cell_type": "heading",
577 "level": 2,
578 "metadata": {},
579 "source": [
580 "Path dependent"
161 ]
581 ]
162 },
582 },
163 {
583 {
164 "cell_type": "markdown",
584 "cell_type": "markdown",
165 "metadata": {},
585 "metadata": {},
166 "source": [
586 "source": [
167 "In some cases, it is necessary to apply CSS classes to your widgets.\n",
587 "Both `add_class` and `remove_class` allow you to use CSS selectors to pick which sub elements of your widget get styled. Because of this, the `add_class` and `remove_class` methods are path dependent (order specific). The following example shows the same three calls made in three different orders and the resulting output. All three differ."
168 "CSS classes allow DOM elements to be indentified in Javascript and CSS.\n",
169 "The notebook defines its own set of classes to stylize its elements.\n",
170 "The `add_class` widget method allows you to add CSS classes to your widget."
171 ]
588 ]
172 },
589 },
173 {
590 {
174 "cell_type": "code",
591 "cell_type": "code",
175 "collapsed": false,
592 "collapsed": false,
176 "input": [
593 "input": [
177 "print(widgets.DOMWidget.add_class.__doc__)"
594 "%%html\n",
595 "<style>\n",
596 " div.cube { display: inline; padding: 5px; }\n",
597 " div.red { background: red; }\n",
598 " div.blue { background: blue; }\n",
599 "</style>"
178 ],
600 ],
179 "language": "python",
601 "language": "python",
180 "metadata": {},
602 "metadata": {},
181 "outputs": [
603 "outputs": [
182 {
604 {
183 "output_type": "stream",
605 "html": [
184 "stream": "stdout",
606 "<style>\n",
607 " div.cube { display: inline; padding: 5px; }\n",
608 " div.red { background: red; }\n",
609 " div.blue { background: blue; }\n",
610 "</style>"
611 ],
612 "metadata": {},
613 "output_type": "display_data",
185 "text": [
614 "text": [
186 "Add class[es] to a DOM element.\n",
615 "<IPython.core.display.HTML object>"
187 "\n",
188 " Parameters\n",
189 " ----------\n",
190 " class_names: unicode or list\n",
191 " Class name(s) to add to the DOM element(s).\n",
192 " selector: unicode (optional)\n",
193 " JQuery selector to select the DOM element(s) that the class(es) will\n",
194 " be added to.\n",
195 " \n"
196 ]
616 ]
197 }
617 }
198 ],
618 ],
199 "prompt_number": 5
619 "prompt_number": 162
620 },
621 {
622 "cell_type": "code",
623 "collapsed": false,
624 "input": [
625 "from IPython.html import widgets\n",
626 "from IPython.display import display\n",
627 "html = '<br />'.join([''.join(['<div class=\"cube\">x</div>' for i in range(8)]) for j in range(8)])\n",
628 "widget = [widgets.HTMLWidget(value=html) for i in range(3)]\n",
629 "\n",
630 "display(widget[0])\n",
631 "widget[0].add_class('red', 'div.cube:nth-child(even)')\n",
632 "widget[0].remove_class('red', 'div.red:nth-child(7n+1)')\n",
633 "widget[0].add_class('blue', 'div.red:nth-child(3n+1)')"
634 ],
635 "language": "python",
636 "metadata": {},
637 "outputs": [],
638 "prompt_number": 163
639 },
640 {
641 "cell_type": "code",
642 "collapsed": false,
643 "input": [
644 "display(widget[1])\n",
645 "widget[1].remove_class('red', 'div.red:nth-child(7n+1)')\n",
646 "widget[1].add_class('blue', 'div.red:nth-child(3n+1)')\n",
647 "widget[1].add_class('red', 'div.cube:nth-child(even)')"
648 ],
649 "language": "python",
650 "metadata": {},
651 "outputs": [],
652 "prompt_number": 164
653 },
654 {
655 "cell_type": "code",
656 "collapsed": false,
657 "input": [
658 "display(widget[2])\n",
659 "widget[2].add_class('red', 'div.cube:nth-child(even)')\n",
660 "widget[2].add_class('blue', 'div.red:nth-child(3n+1)')\n",
661 "widget[2].remove_class('red', 'div.red:nth-child(7n+1)')"
662 ],
663 "language": "python",
664 "metadata": {},
665 "outputs": [],
666 "prompt_number": 165
667 },
668 {
669 "cell_type": "heading",
670 "level": 2,
671 "metadata": {},
672 "source": [
673 "Alignment classes"
674 ]
675 },
676 {
677 "cell_type": "markdown",
678 "metadata": {},
679 "source": [
680 "Widgets can be aligned using IPython specific alignment classes. These classes should work with most widgets, but were designed to be applied to `ContainerWidget`s. Examples of these classes follow:\n",
681 "\n",
682 "### Orientation classes\n",
683 "#### \"vbox\"\n",
684 "Widget containers default to this orientation.\n",
685 "<div class=\"example-container vbox\">\n",
686 "<div class=\"example-box\">A</div>\n",
687 "<div class=\"example-box med\">B</div>\n",
688 "<div class=\"example-box lrg\">C</div>\n",
689 "</div>\n",
690 "\n",
691 "#### \"hbox\"\n",
692 "<div class=\"example-container hbox\">\n",
693 "<div class=\"example-box\">A</div>\n",
694 "<div class=\"example-box med\">B</div>\n",
695 "<div class=\"example-box lrg\">C</div>\n",
696 "</div>\n",
697 "\n",
698 "### Packing classes\n",
699 "These examples use the hbox layout to show packing. Packing is the alignment of the widgets along the the axis that they are displayed on.\n",
700 "#### \"start\"\n",
701 "<div class=\"example-container hbox start\">\n",
702 "<div class=\"example-box\">A</div>\n",
703 "<div class=\"example-box med\">B</div>\n",
704 "<div class=\"example-box lrg\">C</div>\n",
705 "</div>\n",
706 "\n",
707 "#### \"center\"\n",
708 "<div class=\"example-container hbox center\">\n",
709 "<div class=\"example-box\">A</div>\n",
710 "<div class=\"example-box med\">B</div>\n",
711 "<div class=\"example-box lrg\">C</div>\n",
712 "</div>\n",
713 "\n",
714 "#### \"end\"\n",
715 "<div class=\"example-container hbox end\">\n",
716 "<div class=\"example-box\">A</div>\n",
717 "<div class=\"example-box med\">B</div>\n",
718 "<div class=\"example-box lrg\">C</div>\n",
719 "</div>\n",
720 "\n",
721 "### Aligning classes\n",
722 "These examples use the hbox layout to show alignment. Packing is the alignment of the widgets along the the axis perpindicular to the one that they are displayed on.\n",
723 "#### \"align-start\"\n",
724 "<div class=\"example-container hbox align-start\">\n",
725 "<div class=\"example-box\">A</div>\n",
726 "<div class=\"example-box med\">B</div>\n",
727 "<div class=\"example-box lrg\">C</div>\n",
728 "</div>\n",
729 "\n",
730 "#### \"align-center\"\n",
731 "<div class=\"example-container hbox align-center\">\n",
732 "<div class=\"example-box\">A</div>\n",
733 "<div class=\"example-box med\">B</div>\n",
734 "<div class=\"example-box lrg\">C</div>\n",
735 "</div>\n",
736 "\n",
737 "#### \"align-end\"\n",
738 "<div class=\"example-container hbox align-end\">\n",
739 "<div class=\"example-box\">A</div>\n",
740 "<div class=\"example-box med\">B</div>\n",
741 "<div class=\"example-box lrg\">C</div>\n",
742 "</div>\n",
743 "\n",
744 "### Flex classes\n",
745 "To specify how \"greedy\" a container is when filling in the remaining space of its parent, the `box-flexN` properties are used (where N is 0, 1, or 2). The higher the value of N, the more greedy the child is. `box-flex0` is the default behavior, which is to not fill the parent.\n",
746 "\n",
747 "#### Example 1\n",
748 "<div class=\"example-container sm hbox center\">\n",
749 "<div class=\"example-box box-flex0\">box-flex0</div>\n",
750 "<div class=\"example-box box-flex0\">box-flex0</div>\n",
751 "<div class=\"example-box box-flex0\">box-flex0</div>\n",
752 "</div>\n",
753 "\n",
754 "#### Example 2\n",
755 "<div class=\"example-container sm hbox center\">\n",
756 "<div class=\"example-box box-flex0\">box-flex0</div>\n",
757 "<div class=\"example-box box-flex1\">box-flex1</div>\n",
758 "<div class=\"example-box box-flex0\">box-flex0</div>\n",
759 "</div>\n",
760 "\n",
761 "#### Example 3\n",
762 "<div class=\"example-container sm hbox center\">\n",
763 "<div class=\"example-box box-flex0\">box-flex0</div>\n",
764 "<div class=\"example-box box-flex1\">box-flex1</div>\n",
765 "<div class=\"example-box box-flex1\">box-flex1</div>\n",
766 "</div>\n",
767 "\n",
768 "#### Example 4\n",
769 "<div class=\"example-container sm hbox center\">\n",
770 "<div class=\"example-box box-flex1\">box-flex1</div>\n",
771 "<div class=\"example-box box-flex1\">box-flex1</div>\n",
772 "<div class=\"example-box box-flex1\">box-flex1</div>\n",
773 "</div>\n",
774 "\n",
775 "#### Example 5\n",
776 "<div class=\"example-container sm hbox center\">\n",
777 "<div class=\"example-box box-flex2\">box-flex2</div>\n",
778 "<div class=\"example-box box-flex1\">box-flex1</div>\n",
779 "<div class=\"example-box box-flex1\">box-flex1</div>\n",
780 "</div>\n",
781 "\n",
782 "#### Example 6\n",
783 "<div class=\"example-container sm hbox center\">\n",
784 "<div class=\"example-box box-flex0\">box-flex0</div>\n",
785 "<div class=\"example-box box-flex1\">box-flex1</div>\n",
786 "<div class=\"example-box box-flex2\">box-flex2</div>\n",
787 "</div>\n"
788 ]
789 },
790 {
791 "cell_type": "heading",
792 "level": 3,
793 "metadata": {},
794 "source": [
795 "Application to widgets"
796 ]
200 },
797 },
201 {
798 {
202 "cell_type": "markdown",
799 "cell_type": "markdown",
203 "metadata": {},
800 "metadata": {},
204 "source": [
801 "source": [
205 "Since `add_class` is a DOM operation, **it will only affect widgets that have already been displayed**.\n",
802 "Widget containers default as vertical boxes."
206 "`add_class` must be called after the widget has been displayed.\n",
207 "Extending the example above, the corners of the container can be rounded by adding the `corner-all` CSS class to the container."
208 ]
803 ]
209 },
804 },
210 {
805 {
211 "cell_type": "code",
806 "cell_type": "code",
212 "collapsed": false,
807 "collapsed": false,
213 "input": [
808 "input": [
214 "container = widgets.ContainerWidget()\n",
809 "buttons = [widgets.ButtonWidget(description=str(i)) for i in range(3)]\n",
215 "container.set_css({'border': '3px solid black',\n",
216 " 'padding': '6px', \n",
217 " 'background': 'yellow'}) \n",
218 "\n",
810 "\n",
219 "label = widgets.LatexWidget()\n",
811 "container = widgets.ContainerWidget(children=buttons)\n",
220 "label.value = \"$\\\\textbf{ALERT:} Hello World!$\"\n",
812 "display(container)"
221 "container.children = [label]\n",
813 ],
814 "language": "python",
815 "metadata": {},
816 "outputs": [],
817 "prompt_number": 166
818 },
819 {
820 "cell_type": "markdown",
821 "metadata": {},
822 "source": [
823 "To make a widget container display its widgets horizontally, you need to remove the `vbox` class from the container and add the `hbox` class in its place."
824 ]
825 },
826 {
827 "cell_type": "code",
828 "collapsed": false,
829 "input": [
830 "container = widgets.ContainerWidget(children=buttons)\n",
222 "display(container)\n",
831 "display(container)\n",
223 "container.add_class('corner-all') # Must be called AFTER display"
832 "container.remove_class('vbox')\n",
833 "container.add_class('hbox')"
224 ],
834 ],
225 "language": "python",
835 "language": "python",
226 "metadata": {},
836 "metadata": {},
227 "outputs": [],
837 "outputs": [],
228 "prompt_number": 6
838 "prompt_number": 167
229 },
839 },
230 {
840 {
231 "cell_type": "markdown",
841 "cell_type": "markdown",
232 "metadata": {},
842 "metadata": {},
233 "source": [
843 "source": [
234 "The IPython notebook uses [bootstrap](http://getbootstrap.com/\u200e) for styling.\n",
844 "By setting the width of the container to 100% and adding the `center` class to it, you can center the buttons."
235 "The example above can be simplified by using a bootstrap class:"
236 ]
845 ]
237 },
846 },
238 {
847 {
239 "cell_type": "code",
848 "cell_type": "code",
240 "collapsed": false,
849 "collapsed": false,
241 "input": [
850 "input": [
242 "label = widgets.LatexWidget(value = \"$\\\\textbf{ALERT:} Hello World!$\")\n",
851 "container.set_css('width', '100%')\n",
243 "display(label)\n",
852 "container.add_class('center')"
244 "\n",
245 "# Apply twitter bootstrap alert class to the label.\n",
246 "label.add_class(\"alert\")"
247 ],
853 ],
248 "language": "python",
854 "language": "python",
249 "metadata": {},
855 "metadata": {},
250 "outputs": [],
856 "outputs": [],
251 "prompt_number": 7
857 "prompt_number": 168
858 },
859 {
860 "cell_type": "heading",
861 "level": 2,
862 "metadata": {},
863 "source": [
864 "Style classes"
865 ]
252 },
866 },
253 {
867 {
254 "cell_type": "markdown",
868 "cell_type": "markdown",
255 "metadata": {},
869 "metadata": {},
256 "source": [
870 "source": [
257 "The example below shows how bootstrap classes can be used to change button apearance."
871 "In addition to alignment classes, the classes defined by Bootstrap can also be used. This tutorial will only cover a few of the most common classes. For a full list of Bootstrap classes, please refer to [Bootstrap's website](http://getbootstrap.com/2.3.2/)."
872 ]
873 },
874 {
875 "cell_type": "heading",
876 "level": 3,
877 "metadata": {},
878 "source": [
879 "ButtonWidgets"
258 ]
880 ]
259 },
881 },
260 {
882 {
@@ -262,91 +884,189 b''
262 "collapsed": false,
884 "collapsed": false,
263 "input": [
885 "input": [
264 "# List of the bootstrap button styles\n",
886 "# List of the bootstrap button styles\n",
265 "button_classes = ['Default', 'btn-primary', 'btn-info', 'btn-success', \n",
887 "classes = [\n",
266 " 'btn-warning', 'btn-danger', 'btn-inverse', 'btn-link']\n",
888 " 'btn', \n",
889 " 'btn-primary', \n",
890 " 'btn-info', \n",
891 " 'btn-success', \n",
892 " 'btn-warning', \n",
893 " 'btn-danger', \n",
894 " 'btn-inverse', \n",
895 " 'btn-link'\n",
896 "]\n",
897 "\n",
898 "# Display the buttons in a hbox\n",
899 "container = widgets.ContainerWidget(children=[widgets.ButtonWidget(description=c) for c in classes])\n",
900 "display(container)\n",
901 "\n",
902 "# Apply classes after display\n",
903 "container.remove_class('vbox')\n",
904 "container.add_class('hbox')\n",
905 "ret = [container.children[i].add_class(c) for i, c in enumerate(classes)]"
906 ],
907 "language": "python",
908 "metadata": {},
909 "outputs": [],
910 "prompt_number": 180
911 },
912 {
913 "cell_type": "heading",
914 "level": 3,
915 "metadata": {},
916 "source": [
917 "ContainerWidgets"
918 ]
919 },
920 {
921 "cell_type": "code",
922 "collapsed": false,
923 "input": [
924 "def create_label(cls):\n",
925 " class_name = widgets.HTMLWidget(value=cls)\n",
926 " container = widgets.ContainerWidget(children=[class_name])\n",
927 " display(container)\n",
928 " container.add_class(cls)\n",
267 "\n",
929 "\n",
268 "# Create each button and apply the style. Also add margin to the buttons so they space\n",
930 "ret = [create_label(c) for c in [\n",
269 "# themselves nicely.\n",
931 " 'alert', \n",
270 "for i in range(8):\n",
932 " 'alert alert-error', \n",
271 " button = widgets.ButtonWidget(description=button_classes[i])\n",
933 " 'alert alert-success', \n",
272 " button.set_css(\"margin\", \"5px\")\n",
934 " 'alert alert-info'\n",
273 " display(button)\n",
935 "]]"
274 " if i > 0: # Don't add a class the first button.\n",
936 ],
275 " button.add_class(button_classes[i])\n",
937 "language": "python",
276 " "
938 "metadata": {},
939 "outputs": [],
940 "prompt_number": 181
941 },
942 {
943 "cell_type": "heading",
944 "level": 3,
945 "metadata": {},
946 "source": [
947 "*ProgressWidgets"
948 ]
949 },
950 {
951 "cell_type": "code",
952 "collapsed": false,
953 "input": [
954 "classes = [\n",
955 " 'progress-info', \n",
956 " 'progress-success', \n",
957 " 'progress-warning', \n",
958 " 'progress-danger',\n",
959 " 'progress-striped progress-info', \n",
960 " 'progress-striped progress-success', \n",
961 " 'progress-striped progress-warning', \n",
962 " 'progress-striped progress-danger',\n",
963 " 'active progress-striped progress-info', \n",
964 " 'active progress-striped progress-success', \n",
965 " 'active progress-striped progress-warning', \n",
966 " 'active progress-striped progress-danger',\n",
967 "]\n",
968 "ws = [widgets.IntProgressWidget(value=50, description=c) for c in classes]\n",
969 "ret = [display(w) for w in ws]\n",
970 "ret = [ws[i].add_class(c) for i, c in enumerate(classes)]"
277 ],
971 ],
278 "language": "python",
972 "language": "python",
279 "metadata": {},
973 "metadata": {},
280 "outputs": [],
974 "outputs": [],
281 "prompt_number": 8
975 "prompt_number": 182
976 },
977 {
978 "cell_type": "heading",
979 "level": 1,
980 "metadata": {},
981 "source": [
982 "Visibility"
983 ]
282 },
984 },
283 {
985 {
284 "cell_type": "markdown",
986 "cell_type": "markdown",
285 "metadata": {},
987 "metadata": {},
286 "source": [
988 "source": [
287 "It is also useful to be able to remove CSS classes from widgets.\n",
989 "Sometimes it is necessary to hide or show widgets in place, without having to redisplay the widget.\n",
288 "The `remove_class` method allows you to remove classes from widgets that have been displayed.\n",
990 "The `visibility` property of widgets can be used to hide or show widgets that have already been displayed (as seen below)."
289 "Like `add_class`, it must be called after the widget has been displayed."
290 ]
991 ]
291 },
992 },
292 {
993 {
293 "cell_type": "code",
994 "cell_type": "code",
294 "collapsed": false,
995 "collapsed": false,
295 "input": [
996 "input": [
296 "print(widgets.DOMWidget.remove_class.__doc__)"
997 "string = widgets.LatexWidget(value=\"Hello World!\")\n",
998 "display(string) "
297 ],
999 ],
298 "language": "python",
1000 "language": "python",
299 "metadata": {},
1001 "metadata": {},
300 "outputs": [
1002 "outputs": [],
301 {
1003 "prompt_number": 183
302 "output_type": "stream",
1004 },
303 "stream": "stdout",
1005 {
304 "text": [
1006 "cell_type": "code",
305 "Remove class[es] from a DOM element.\n",
1007 "collapsed": false,
306 "\n",
1008 "input": [
307 " Parameters\n",
1009 "string.visible=False"
308 " ----------\n",
1010 ],
309 " class_names: unicode or list\n",
1011 "language": "python",
310 " Class name(s) to remove from the DOM element(s).\n",
1012 "metadata": {},
311 " selector: unicode (optional)\n",
1013 "outputs": [],
312 " JQuery selector to select the DOM element(s) that the class(es) will\n",
1014 "prompt_number": 184
313 " be removed from.\n",
1015 },
314 " \n"
1016 {
315 ]
1017 "cell_type": "code",
316 }
1018 "collapsed": false,
1019 "input": [
1020 "string.visible=True"
317 ],
1021 ],
318 "prompt_number": 9
1022 "language": "python",
1023 "metadata": {},
1024 "outputs": [],
1025 "prompt_number": 185
319 },
1026 },
320 {
1027 {
321 "cell_type": "markdown",
1028 "cell_type": "markdown",
322 "metadata": {},
1029 "metadata": {},
323 "source": [
1030 "source": [
324 "The example below animates an alert using different bootstrap styles."
1031 "In the example below, a form is rendered, which conditionally displays widgets depending on the state of other widgets. Try toggling the student checkbox."
325 ]
1032 ]
326 },
1033 },
327 {
1034 {
328 "cell_type": "code",
1035 "cell_type": "code",
329 "collapsed": false,
1036 "collapsed": false,
330 "input": [
1037 "input": [
331 "import time\n",
1038 "form = widgets.ContainerWidget()\n",
332 "label = widgets.LatexWidget(value = \"$\\\\textbf{ALERT:} Hello World!$\")\n",
1039 "first = widgets.TextWidget(description=\"First Name:\")\n",
333 "display(label)\n",
1040 "last = widgets.TextWidget(description=\"Last Name:\")\n",
1041 "\n",
1042 "student = widgets.CheckboxWidget(description=\"Student:\", value=False)\n",
1043 "school_info = widgets.ContainerWidget(visible=False, children=[\n",
1044 " widgets.TextWidget(description=\"School:\"),\n",
1045 " widgets.IntTextWidget(description=\"Grade:\", min=0, max=12)\n",
1046 " ])\n",
334 "\n",
1047 "\n",
335 "# Apply twitter bootstrap alert class to the label.\n",
1048 "pet = widgets.TextWidget(description=\"Pet's Name:\")\n",
336 "label.add_class(\"alert\")\n",
1049 "form.children = [first, last, student, school_info, pet]\n",
1050 "display(form)\n",
337 "\n",
1051 "\n",
338 "# Animate through additional bootstrap label styles 3 times\n",
1052 "def on_student_toggle(name, value):\n",
339 "additional_alert_styles = ['alert-error', 'alert-info', 'alert-success']\n",
1053 " if value:\n",
340 "for i in range(3 * len(additional_alert_styles)):\n",
1054 " school_info.visible = True\n",
341 " label.add_class(additional_alert_styles[i % 3])\n",
1055 " else:\n",
342 " label.remove_class(additional_alert_styles[(i-1) % 3])\n",
1056 " school_info.visible = False\n",
343 " time.sleep(1)\n",
1057 "student.on_trait_change(on_student_toggle, 'value')\n"
344 " "
345 ],
1058 ],
346 "language": "python",
1059 "language": "python",
347 "metadata": {},
1060 "metadata": {},
348 "outputs": [],
1061 "outputs": [],
349 "prompt_number": 10
1062 "prompt_number": 186
1063 },
1064 {
1065 "cell_type": "markdown",
1066 "metadata": {},
1067 "source": [
1068 "[Next](Custom Widget - Hello World.ipynb)"
1069 ]
350 }
1070 }
351 ],
1071 ],
352 "metadata": {}
1072 "metadata": {}
General Comments 0
You need to be logged in to leave comments. Login now