##// END OF EJS Templates
Widget styling updates for pydata2014
Jonathan Frederic -
Show More
This diff has been collapsed as it changes many lines, (1032 lines changed) Show them Hide them
@@ -1,355 +1,1075
1 1 {
2 2 "metadata": {
3 3 "cell_tags": [
4 4 [
5 5 "<None>",
6 6 null
7 7 ]
8 8 ],
9 9 "name": "",
10 "signature": "sha256:cd7d3d42126bdbf20c087014460779dfbdb0a63dcb8f489ba7ebfc230a685edd"
10 "signature": "sha256:55ee4a4661f0939c40550752218a4c127b985536811190a2b7e581d7fe25cec7"
11 11 },
12 12 "nbformat": 3,
13 13 "nbformat_minor": 0,
14 14 "worksheets": [
15 15 {
16 16 "cells": [
17 17 {
18 18 "cell_type": "code",
19 19 "collapsed": false,
20 20 "input": [
21 "from IPython.html import widgets # Widget definitions\n",
22 "from IPython.display import display # Used to display widgets in the notebook"
21 "%%html\n",
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>"
23 29 ],
24 30 "language": "python",
25 31 "metadata": {},
26 "outputs": [],
27 "prompt_number": 1
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
28 51 },
29 52 {
30 53 "cell_type": "heading",
31 54 "level": 1,
32 55 "metadata": {},
33 56 "source": [
34 57 "CSS"
35 58 ]
36 59 },
37 60 {
38 61 "cell_type": "markdown",
39 62 "metadata": {},
40 63 "source": [
41 "When trying to design an attractive widget GUI, styling becomes important.\n",
42 "Most widget views are DOM (document object model) elements that can be controlled with CSS.\n",
43 "There are two helper methods that allow the manipulation of the widget's CSS.\n",
44 "The first is the `Widget.set_css` method.\n",
45 "This method allows one or more CSS attributes to be set at once. "
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`."
46 65 ]
47 66 },
48 67 {
49 68 "cell_type": "code",
50 69 "collapsed": false,
51 70 "input": [
52 "print(widgets.DOMWidget.set_css.__doc__)"
71 "from IPython.html import widgets\n",
72 "text = widgets.TextWidget()\n",
73 "text.set_css('background', 'lime')\n",
74 "text "
53 75 ],
54 76 "language": "python",
55 77 "metadata": {},
56 "outputs": [
78 "outputs": [],
79 "prompt_number": 146
80 },
57 81 {
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"
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."
83 86 ]
84 }
87 },
88 {
89 "cell_type": "code",
90 "collapsed": false,
91 "input": [
92 "text.set_css('background', '#0000FF')"
85 93 ],
86 "prompt_number": 2
94 "language": "python",
95 "metadata": {},
96 "outputs": [],
97 "prompt_number": 147
87 98 },
88 99 {
89 100 "cell_type": "markdown",
90 101 "metadata": {},
91 102 "source": [
92 "The second is `get_css` which allows CSS attributesto be read.\n",
93 "Note that this method will only read CSS attributes that have been set using the `set_css` method."
103 "Font color is just `color`."
94 104 ]
95 105 },
96 106 {
97 107 "cell_type": "code",
98 108 "collapsed": false,
99 109 "input": [
100 "print(widgets.DOMWidget.get_css.__doc__)"
110 "text.set_css('color', '#FFFFFF')"
101 111 ],
102 112 "language": "python",
103 113 "metadata": {},
104 "outputs": [
114 "outputs": [],
115 "prompt_number": 148
116 },
105 117 {
106 "output_type": "stream",
107 "stream": "stdout",
108 "text": [
109 "Get a CSS property of the widget.\n",
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": [
110 186 "\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",
187 "from IPython.display import display\n",
113 188 "\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"
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."
121 206 ]
122 }
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]"
123 218 ],
124 "prompt_number": 3
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 ]
125 231 },
126 232 {
127 233 "cell_type": "markdown",
128 234 "metadata": {},
129 235 "source": [
130 "Below is an example that applies CSS attributes to a container to emphasize text."
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"
131 245 ]
132 246 },
133 247 {
134 248 "cell_type": "code",
135 249 "collapsed": false,
136 250 "input": [
137 "label = widgets.LatexWidget()\n",
138 "label.value = \"$\\\\textbf{ALERT:} Hello World!$\"\n",
139 "container = widgets.ContainerWidget(children=[label])\n",
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",
140 254 "\n",
141 "# set_css used to set a single CSS attribute.\n",
142 "container.set_css('border', '3px solid black') # Border the container\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",
143 258 "\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",
259 "accord = widgets.AccordionWidget(children=[page1, page2])\n",
260 "display(accord)\n",
147 261 "\n",
148 "display(container)"
262 "accord.set_title(0, 'From')\n",
263 "accord.set_title(1, 'To')"
149 264 ],
150 265 "language": "python",
151 266 "metadata": {},
152 267 "outputs": [],
153 "prompt_number": 4
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()"
482 ],
483 "language": "python",
484 "metadata": {},
485 "outputs": [],
486 "prompt_number": 158
154 487 },
155 488 {
156 489 "cell_type": "heading",
157 490 "level": 1,
158 491 "metadata": {},
159 492 "source": [
160 "CSS Classes"
493 "Alignment"
494 ]
495 },
496 {
497 "cell_type": "markdown",
498 "metadata": {},
499 "source": [
500 "Most widgets have a `description` attribute, which allows a label for the widget to be defined.\n",
501 "The label of the widget has a fixed minimum width.\n",
502 "The text of the label is always right aligned and the widget is left aligned:"
161 503 ]
162 504 },
163 505 {
506 "cell_type": "code",
507 "collapsed": false,
508 "input": [
509 "display(widgets.TextWidget(description=\"a:\"))\n",
510 "display(widgets.TextWidget(description=\"aa:\"))\n",
511 "display(widgets.TextWidget(description=\"aaa:\"))"
512 ],
513 "language": "python",
514 "metadata": {},
515 "outputs": [],
516 "prompt_number": 159
517 },
518 {
519 "cell_type": "markdown",
520 "metadata": {},
521 "source": [
522 "If a label is longer than the minimum width, the widget is shifted to the right:"
523 ]
524 },
525 {
526 "cell_type": "code",
527 "collapsed": false,
528 "input": [
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:\"))"
533 ],
534 "language": "python",
535 "metadata": {},
536 "outputs": [],
537 "prompt_number": 160
538 },
539 {
164 540 "cell_type": "markdown",
165 541 "metadata": {},
166 542 "source": [
167 "In some cases, it is necessary to apply CSS classes to your widgets.\n",
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."
543 "If a `description` is not set for the widget, the label is not displayed:"
171 544 ]
172 545 },
173 546 {
174 547 "cell_type": "code",
175 548 "collapsed": false,
176 549 "input": [
177 "print(widgets.DOMWidget.add_class.__doc__)"
550 "display(widgets.TextWidget(description=\"a:\"))\n",
551 "display(widgets.TextWidget(description=\"aa:\"))\n",
552 "display(widgets.TextWidget(description=\"aaa:\"))\n",
553 "display(widgets.TextWidget())"
554 ],
555 "language": "python",
556 "metadata": {},
557 "outputs": [],
558 "prompt_number": 161
559 },
560 {
561 "cell_type": "heading",
562 "level": 1,
563 "metadata": {},
564 "source": [
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"
581 ]
582 },
583 {
584 "cell_type": "markdown",
585 "metadata": {},
586 "source": [
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."
588 ]
589 },
590 {
591 "cell_type": "code",
592 "collapsed": false,
593 "input": [
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 601 "language": "python",
180 602 "metadata": {},
181 603 "outputs": [
182 604 {
183 "output_type": "stream",
184 "stream": "stdout",
605 "html": [
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 614 "text": [
186 "Add class[es] to a DOM element.\n",
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"
615 "<IPython.core.display.HTML object>"
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 ]
200 675 },
201 676 {
202 677 "cell_type": "markdown",
203 678 "metadata": {},
204 679 "source": [
205 "Since `add_class` is a DOM operation, **it will only affect widgets that have already been displayed**.\n",
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."
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 ]
797 },
798 {
799 "cell_type": "markdown",
800 "metadata": {},
801 "source": [
802 "Widget containers default as vertical boxes."
208 803 ]
209 804 },
210 805 {
211 806 "cell_type": "code",
212 807 "collapsed": false,
213 808 "input": [
214 "container = widgets.ContainerWidget()\n",
215 "container.set_css({'border': '3px solid black',\n",
216 " 'padding': '6px', \n",
217 " 'background': 'yellow'}) \n",
809 "buttons = [widgets.ButtonWidget(description=str(i)) for i in range(3)]\n",
218 810 "\n",
219 "label = widgets.LatexWidget()\n",
220 "label.value = \"$\\\\textbf{ALERT:} Hello World!$\"\n",
221 "container.children = [label]\n",
811 "container = widgets.ContainerWidget(children=buttons)\n",
812 "display(container)"
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 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 835 "language": "python",
226 836 "metadata": {},
227 837 "outputs": [],
228 "prompt_number": 6
838 "prompt_number": 167
229 839 },
230 840 {
231 841 "cell_type": "markdown",
232 842 "metadata": {},
233 843 "source": [
234 "The IPython notebook uses [bootstrap](http://getbootstrap.com/\u200e) for styling.\n",
235 "The example above can be simplified by using a bootstrap class:"
844 "By setting the width of the container to 100% and adding the `center` class to it, you can center the buttons."
236 845 ]
237 846 },
238 847 {
239 848 "cell_type": "code",
240 849 "collapsed": false,
241 850 "input": [
242 "label = widgets.LatexWidget(value = \"$\\\\textbf{ALERT:} Hello World!$\")\n",
243 "display(label)\n",
244 "\n",
245 "# Apply twitter bootstrap alert class to the label.\n",
246 "label.add_class(\"alert\")"
851 "container.set_css('width', '100%')\n",
852 "container.add_class('center')"
247 853 ],
248 854 "language": "python",
249 855 "metadata": {},
250 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 868 "cell_type": "markdown",
255 869 "metadata": {},
256 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 {
261 883 "cell_type": "code",
262 884 "collapsed": false,
263 885 "input": [
264 886 "# List of the bootstrap button styles\n",
265 "button_classes = ['Default', 'btn-primary', 'btn-info', 'btn-success', \n",
266 " 'btn-warning', 'btn-danger', 'btn-inverse', 'btn-link']\n",
887 "classes = [\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",
267 901 "\n",
268 "# Create each button and apply the style. Also add margin to the buttons so they space\n",
269 "# themselves nicely.\n",
270 "for i in range(8):\n",
271 " button = widgets.ButtonWidget(description=button_classes[i])\n",
272 " button.set_css(\"margin\", \"5px\")\n",
273 " display(button)\n",
274 " if i > 0: # Don't add a class the first button.\n",
275 " button.add_class(button_classes[i])\n",
276 " "
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)]"
277 906 ],
278 907 "language": "python",
279 908 "metadata": {},
280 909 "outputs": [],
281 "prompt_number": 8
910 "prompt_number": 180
282 911 },
283 912 {
284 "cell_type": "markdown",
913 "cell_type": "heading",
914 "level": 3,
285 915 "metadata": {},
286 916 "source": [
287 "It is also useful to be able to remove CSS classes from widgets.\n",
288 "The `remove_class` method allows you to remove classes from widgets that have been displayed.\n",
289 "Like `add_class`, it must be called after the widget has been displayed."
917 "ContainerWidgets"
290 918 ]
291 919 },
292 920 {
293 921 "cell_type": "code",
294 922 "collapsed": false,
295 923 "input": [
296 "print(widgets.DOMWidget.remove_class.__doc__)"
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",
929 "\n",
930 "ret = [create_label(c) for c in [\n",
931 " 'alert', \n",
932 " 'alert alert-error', \n",
933 " 'alert alert-success', \n",
934 " 'alert alert-info'\n",
935 "]]"
297 936 ],
298 937 "language": "python",
299 938 "metadata": {},
300 "outputs": [
939 "outputs": [],
940 "prompt_number": 181
941 },
301 942 {
302 "output_type": "stream",
303 "stream": "stdout",
304 "text": [
305 "Remove class[es] from a DOM element.\n",
306 "\n",
307 " Parameters\n",
308 " ----------\n",
309 " class_names: unicode or list\n",
310 " Class name(s) to remove from the DOM element(s).\n",
311 " selector: unicode (optional)\n",
312 " JQuery selector to select the DOM element(s) that the class(es) will\n",
313 " be removed from.\n",
314 " \n"
943 "cell_type": "heading",
944 "level": 3,
945 "metadata": {},
946 "source": [
947 "*ProgressWidgets"
315 948 ]
316 }
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)]"
317 971 ],
318 "prompt_number": 9
972 "language": "python",
973 "metadata": {},
974 "outputs": [],
975 "prompt_number": 182
976 },
977 {
978 "cell_type": "heading",
979 "level": 1,
980 "metadata": {},
981 "source": [
982 "Visibility"
983 ]
319 984 },
320 985 {
321 986 "cell_type": "markdown",
322 987 "metadata": {},
323 988 "source": [
324 "The example below animates an alert using different bootstrap styles."
989 "Sometimes it is necessary to hide or show widgets in place, without having to redisplay the widget.\n",
990 "The `visibility` property of widgets can be used to hide or show widgets that have already been displayed (as seen below)."
325 991 ]
326 992 },
327 993 {
328 994 "cell_type": "code",
329 995 "collapsed": false,
330 996 "input": [
331 "import time\n",
332 "label = widgets.LatexWidget(value = \"$\\\\textbf{ALERT:} Hello World!$\")\n",
333 "display(label)\n",
997 "string = widgets.LatexWidget(value=\"Hello World!\")\n",
998 "display(string) "
999 ],
1000 "language": "python",
1001 "metadata": {},
1002 "outputs": [],
1003 "prompt_number": 183
1004 },
1005 {
1006 "cell_type": "code",
1007 "collapsed": false,
1008 "input": [
1009 "string.visible=False"
1010 ],
1011 "language": "python",
1012 "metadata": {},
1013 "outputs": [],
1014 "prompt_number": 184
1015 },
1016 {
1017 "cell_type": "code",
1018 "collapsed": false,
1019 "input": [
1020 "string.visible=True"
1021 ],
1022 "language": "python",
1023 "metadata": {},
1024 "outputs": [],
1025 "prompt_number": 185
1026 },
1027 {
1028 "cell_type": "markdown",
1029 "metadata": {},
1030 "source": [
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."
1032 ]
1033 },
1034 {
1035 "cell_type": "code",
1036 "collapsed": false,
1037 "input": [
1038 "form = widgets.ContainerWidget()\n",
1039 "first = widgets.TextWidget(description=\"First Name:\")\n",
1040 "last = widgets.TextWidget(description=\"Last Name:\")\n",
334 1041 "\n",
335 "# Apply twitter bootstrap alert class to the label.\n",
336 "label.add_class(\"alert\")\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",
337 1047 "\n",
338 "# Animate through additional bootstrap label styles 3 times\n",
339 "additional_alert_styles = ['alert-error', 'alert-info', 'alert-success']\n",
340 "for i in range(3 * len(additional_alert_styles)):\n",
341 " label.add_class(additional_alert_styles[i % 3])\n",
342 " label.remove_class(additional_alert_styles[(i-1) % 3])\n",
343 " time.sleep(1)\n",
344 " "
1048 "pet = widgets.TextWidget(description=\"Pet's Name:\")\n",
1049 "form.children = [first, last, student, school_info, pet]\n",
1050 "display(form)\n",
1051 "\n",
1052 "def on_student_toggle(name, value):\n",
1053 " if value:\n",
1054 " school_info.visible = True\n",
1055 " else:\n",
1056 " school_info.visible = False\n",
1057 "student.on_trait_change(on_student_toggle, 'value')\n"
345 1058 ],
346 1059 "language": "python",
347 1060 "metadata": {},
348 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 1072 "metadata": {}
353 1073 }
354 1074 ]
355 1075 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now