diff --git a/examples/Interactive Widgets/Widget Styling.ipynb b/examples/Interactive Widgets/Widget Styling.ipynb index 136ae87..c9fce87 100644 --- a/examples/Interactive Widgets/Widget Styling.ipynb +++ b/examples/Interactive Widgets/Widget Styling.ipynb @@ -7,7 +7,7 @@ ] ], "name": "", - "signature": "sha256:cd7d3d42126bdbf20c087014460779dfbdb0a63dcb8f489ba7ebfc230a685edd" + "signature": "sha256:55ee4a4661f0939c40550752218a4c127b985536811190a2b7e581d7fe25cec7" }, "nbformat": 3, "nbformat_minor": 0, @@ -18,243 +18,865 @@ "cell_type": "code", "collapsed": false, "input": [ - "from IPython.html import widgets # Widget definitions\n", - "from IPython.display import display # Used to display widgets in the notebook" + "%%html\n", + "" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "html": [ + "" + ], + "metadata": {}, + "output_type": "display_data", + "text": [ + "" + ] + } + ], + "prompt_number": 145 + }, + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "CSS" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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`." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from IPython.html import widgets\n", + "text = widgets.TextWidget()\n", + "text.set_css('background', 'lime')\n", + "text " + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 146 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "text.set_css('background', '#0000FF')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 147 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Font color is just `color`." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "text.set_css('color', '#FFFFFF')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 148 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To remove the styling, you can call `set_css` again, but use an empty string instead of a color value." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "text.set_css('background', '')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 149 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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)." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "btn = widgets.ButtonWidget()\n", + "btn.set_css({\n", + " 'width': '100px',\n", + " 'height': '100px',\n", + "})\n", + "btn" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 150 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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" + ] + }, + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "Parent/Child Relationships" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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", + "\n", + "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." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "\n", + "from IPython.display import display\n", + "\n", + "float_range = widgets.FloatSliderWidget()\n", + "string = widgets.TextWidget(value='hi')\n", + "container = widgets.ContainerWidget(children=[float_range, string])\n", + "\n", + "container.set_css('border', '3px dotted red')\n", + "display(container) # Displays the `container` and all of it's children." + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 151 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Children can also be added to parents after the parent has been displayed. The parent is responsible for rendering its children." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "container = widgets.ContainerWidget()\n", + "container.set_css('border', '3px dotted red')\n", + "display(container)\n", + "\n", + "int_range = widgets.IntSliderWidget()\n", + "container.children=[int_range]" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 152 + }, + { + "cell_type": "heading", + "level": 2, + "metadata": {}, + "source": [ + "Fancy containers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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." + ] + }, + { + "cell_type": "heading", + "level": 3, + "metadata": {}, + "source": [ + "AccordionWidget" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "name1 = widgets.TextWidget(description='Location:')\n", + "zip1 = widgets.BoundedIntTextWidget(description='Zip:', min=0, max=99999)\n", + "page1 = widgets.ContainerWidget(children=[name1, zip1])\n", + "\n", + "name2 = widgets.TextWidget(description='Location:')\n", + "zip2 = widgets.BoundedIntTextWidget(description='Zip:', min=0, max=99999)\n", + "page2 = widgets.ContainerWidget(children=[name2, zip2])\n", + "\n", + "accord = widgets.AccordionWidget(children=[page1, page2])\n", + "display(accord)\n", + "\n", + "accord.set_title(0, 'From')\n", + "accord.set_title(1, 'To')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 153 + }, + { + "cell_type": "heading", + "level": 3, + "metadata": {}, + "source": [ + "TabWidget" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "name = widgets.TextWidget(description='Name:')\n", + "color = widgets.DropdownWidget(description='Color:', values=['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'])\n", + "page1 = widgets.ContainerWidget(children=[name, color])\n", + "\n", + "age = widgets.IntSliderWidget(description='Age:', min=0, max=120, value=50)\n", + "gender = widgets.RadioButtonsWidget(description='Gender:', values=['male', 'female'])\n", + "page2 = widgets.ContainerWidget(children=[age, gender])\n", + "\n", + "tabs = widgets.TabWidget(children=[page1, page2])\n", + "display(tabs)\n", + "\n", + "tabs.set_title(0, 'Name')\n", + "tabs.set_title(1, 'Details')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 154 + }, + { + "cell_type": "heading", + "level": 3, + "metadata": {}, + "source": [ + "PopupWidget" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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. " + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "counter = widgets.IntTextWidget(description='Counter:')\n", + "popup = widgets.PopupWidget(children=[counter], description='Popup Demo', button_text='Popup Button')\n", + "display(popup)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 155 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "counter.value += 1" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 156 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "counter.value += 1" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 157 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "popup.close()" ], "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 1 + "prompt_number": 158 }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ - "CSS" + "Alignment" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "When trying to design an attractive widget GUI, styling becomes important.\n", - "Most widget views are DOM (document object model) elements that can be controlled with CSS.\n", - "There are two helper methods that allow the manipulation of the widget's CSS.\n", - "The first is the `Widget.set_css` method.\n", - "This method allows one or more CSS attributes to be set at once. " + "Most widgets have a `description` attribute, which allows a label for the widget to be defined.\n", + "The label of the widget has a fixed minimum width.\n", + "The text of the label is always right aligned and the widget is left aligned:" ] }, { "cell_type": "code", "collapsed": false, "input": [ - "print(widgets.DOMWidget.set_css.__doc__)" + "display(widgets.TextWidget(description=\"a:\"))\n", + "display(widgets.TextWidget(description=\"aa:\"))\n", + "display(widgets.TextWidget(description=\"aaa:\"))" ], "language": "python", "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Set one or more CSS properties of the widget.\n", - "\n", - " This function has two signatures:\n", - " - set_css(css_dict, selector='')\n", - " - set_css(key, value, selector='')\n", - "\n", - " Parameters\n", - " ----------\n", - " css_dict : dict\n", - " CSS key/value pairs to apply\n", - " key: unicode\n", - " CSS key\n", - " value:\n", - " CSS value\n", - " selector: unicode (optional, kwarg only)\n", - " JQuery selector to use to apply the CSS key/value. If no selector \n", - " is provided, an empty selector is used. An empty selector makes the \n", - " front-end try to apply the css to a default element. The default\n", - " element is an attribute unique to each view, which is a DOM element\n", - " of the view that should be styled with common CSS (see \n", - " `$el_to_style` in the Javascript code).\n", - " \n" - ] - } - ], - "prompt_number": 2 + "outputs": [], + "prompt_number": 159 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The second is `get_css` which allows CSS attributesto be read.\n", - "Note that this method will only read CSS attributes that have been set using the `set_css` method." + "If a label is longer than the minimum width, the widget is shifted to the right:" ] }, { "cell_type": "code", "collapsed": false, "input": [ - "print(widgets.DOMWidget.get_css.__doc__)" + "display(widgets.TextWidget(description=\"a:\"))\n", + "display(widgets.TextWidget(description=\"aa:\"))\n", + "display(widgets.TextWidget(description=\"aaa:\"))\n", + "display(widgets.TextWidget(description=\"aaaaaaaaaaaaaaaaaa:\"))" ], "language": "python", "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Get a CSS property of the widget.\n", - "\n", - " Note: This function does not actually request the CSS from the \n", - " front-end; Only properties that have been set with set_css can be read.\n", - "\n", - " Parameters\n", - " ----------\n", - " key: unicode\n", - " CSS key\n", - " selector: unicode (optional)\n", - " JQuery selector used when the CSS key/value was set.\n", - " \n" - ] - } - ], - "prompt_number": 3 + "outputs": [], + "prompt_number": 160 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Below is an example that applies CSS attributes to a container to emphasize text." + "If a `description` is not set for the widget, the label is not displayed:" ] }, { "cell_type": "code", "collapsed": false, "input": [ - "label = widgets.LatexWidget()\n", - "label.value = \"$\\\\textbf{ALERT:} Hello World!$\"\n", - "container = widgets.ContainerWidget(children=[label])\n", - "\n", - "# set_css used to set a single CSS attribute.\n", - "container.set_css('border', '3px solid black') # Border the container\n", - "\n", - "# set_css used to set multiple CSS attributes.\n", - "container.set_css({'padding': '6px', # Add padding to the container\n", - " 'background': 'yellow'}) # Fill the container yellow\n", - "\n", - "display(container)" + "display(widgets.TextWidget(description=\"a:\"))\n", + "display(widgets.TextWidget(description=\"aa:\"))\n", + "display(widgets.TextWidget(description=\"aaa:\"))\n", + "display(widgets.TextWidget())" ], "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 4 + "prompt_number": 161 }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ - "CSS Classes" + "DOM Classes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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/)." + ] + }, + { + "cell_type": "heading", + "level": 2, + "metadata": {}, + "source": [ + "Path dependent" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "In some cases, it is necessary to apply CSS classes to your widgets.\n", - "CSS classes allow DOM elements to be indentified in Javascript and CSS.\n", - "The notebook defines its own set of classes to stylize its elements.\n", - "The `add_class` widget method allows you to add CSS classes to your widget." + "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." ] }, { "cell_type": "code", "collapsed": false, "input": [ - "print(widgets.DOMWidget.add_class.__doc__)" + "%%html\n", + "" ], "language": "python", "metadata": {}, "outputs": [ { - "output_type": "stream", - "stream": "stdout", + "html": [ + "" + ], + "metadata": {}, + "output_type": "display_data", "text": [ - "Add class[es] to a DOM element.\n", - "\n", - " Parameters\n", - " ----------\n", - " class_names: unicode or list\n", - " Class name(s) to add to the DOM element(s).\n", - " selector: unicode (optional)\n", - " JQuery selector to select the DOM element(s) that the class(es) will\n", - " be added to.\n", - " \n" + "" ] } ], - "prompt_number": 5 + "prompt_number": 162 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from IPython.html import widgets\n", + "from IPython.display import display\n", + "html = '
'.join([''.join(['
x
' for i in range(8)]) for j in range(8)])\n", + "widget = [widgets.HTMLWidget(value=html) for i in range(3)]\n", + "\n", + "display(widget[0])\n", + "widget[0].add_class('red', 'div.cube:nth-child(even)')\n", + "widget[0].remove_class('red', 'div.red:nth-child(7n+1)')\n", + "widget[0].add_class('blue', 'div.red:nth-child(3n+1)')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 163 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "display(widget[1])\n", + "widget[1].remove_class('red', 'div.red:nth-child(7n+1)')\n", + "widget[1].add_class('blue', 'div.red:nth-child(3n+1)')\n", + "widget[1].add_class('red', 'div.cube:nth-child(even)')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 164 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "display(widget[2])\n", + "widget[2].add_class('red', 'div.cube:nth-child(even)')\n", + "widget[2].add_class('blue', 'div.red:nth-child(3n+1)')\n", + "widget[2].remove_class('red', 'div.red:nth-child(7n+1)')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 165 + }, + { + "cell_type": "heading", + "level": 2, + "metadata": {}, + "source": [ + "Alignment classes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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", + "\n", + "### Orientation classes\n", + "#### \"vbox\"\n", + "Widget containers default to this orientation.\n", + "
\n", + "
A
\n", + "
B
\n", + "
C
\n", + "
\n", + "\n", + "#### \"hbox\"\n", + "
\n", + "
A
\n", + "
B
\n", + "
C
\n", + "
\n", + "\n", + "### Packing classes\n", + "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", + "#### \"start\"\n", + "
\n", + "
A
\n", + "
B
\n", + "
C
\n", + "
\n", + "\n", + "#### \"center\"\n", + "
\n", + "
A
\n", + "
B
\n", + "
C
\n", + "
\n", + "\n", + "#### \"end\"\n", + "
\n", + "
A
\n", + "
B
\n", + "
C
\n", + "
\n", + "\n", + "### Aligning classes\n", + "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", + "#### \"align-start\"\n", + "
\n", + "
A
\n", + "
B
\n", + "
C
\n", + "
\n", + "\n", + "#### \"align-center\"\n", + "
\n", + "
A
\n", + "
B
\n", + "
C
\n", + "
\n", + "\n", + "#### \"align-end\"\n", + "
\n", + "
A
\n", + "
B
\n", + "
C
\n", + "
\n", + "\n", + "### Flex classes\n", + "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", + "\n", + "#### Example 1\n", + "
\n", + "
box-flex0
\n", + "
box-flex0
\n", + "
box-flex0
\n", + "
\n", + "\n", + "#### Example 2\n", + "
\n", + "
box-flex0
\n", + "
box-flex1
\n", + "
box-flex0
\n", + "
\n", + "\n", + "#### Example 3\n", + "
\n", + "
box-flex0
\n", + "
box-flex1
\n", + "
box-flex1
\n", + "
\n", + "\n", + "#### Example 4\n", + "
\n", + "
box-flex1
\n", + "
box-flex1
\n", + "
box-flex1
\n", + "
\n", + "\n", + "#### Example 5\n", + "
\n", + "
box-flex2
\n", + "
box-flex1
\n", + "
box-flex1
\n", + "
\n", + "\n", + "#### Example 6\n", + "
\n", + "
box-flex0
\n", + "
box-flex1
\n", + "
box-flex2
\n", + "
\n" + ] + }, + { + "cell_type": "heading", + "level": 3, + "metadata": {}, + "source": [ + "Application to widgets" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Since `add_class` is a DOM operation, **it will only affect widgets that have already been displayed**.\n", - "`add_class` must be called after the widget has been displayed.\n", - "Extending the example above, the corners of the container can be rounded by adding the `corner-all` CSS class to the container." + "Widget containers default as vertical boxes." ] }, { "cell_type": "code", "collapsed": false, "input": [ - "container = widgets.ContainerWidget()\n", - "container.set_css({'border': '3px solid black',\n", - " 'padding': '6px', \n", - " 'background': 'yellow'}) \n", + "buttons = [widgets.ButtonWidget(description=str(i)) for i in range(3)]\n", "\n", - "label = widgets.LatexWidget()\n", - "label.value = \"$\\\\textbf{ALERT:} Hello World!$\"\n", - "container.children = [label]\n", + "container = widgets.ContainerWidget(children=buttons)\n", + "display(container)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 166 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "container = widgets.ContainerWidget(children=buttons)\n", "display(container)\n", - "container.add_class('corner-all') # Must be called AFTER display" + "container.remove_class('vbox')\n", + "container.add_class('hbox')" ], "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 6 + "prompt_number": 167 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The IPython notebook uses [bootstrap](http://getbootstrap.com/\u200e) for styling.\n", - "The example above can be simplified by using a bootstrap class:" + "By setting the width of the container to 100% and adding the `center` class to it, you can center the buttons." ] }, { "cell_type": "code", "collapsed": false, "input": [ - "label = widgets.LatexWidget(value = \"$\\\\textbf{ALERT:} Hello World!$\")\n", - "display(label)\n", - "\n", - "# Apply twitter bootstrap alert class to the label.\n", - "label.add_class(\"alert\")" + "container.set_css('width', '100%')\n", + "container.add_class('center')" ], "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 7 + "prompt_number": 168 + }, + { + "cell_type": "heading", + "level": 2, + "metadata": {}, + "source": [ + "Style classes" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The example below shows how bootstrap classes can be used to change button apearance." + "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/)." + ] + }, + { + "cell_type": "heading", + "level": 3, + "metadata": {}, + "source": [ + "ButtonWidgets" ] }, { @@ -262,91 +884,189 @@ "collapsed": false, "input": [ "# List of the bootstrap button styles\n", - "button_classes = ['Default', 'btn-primary', 'btn-info', 'btn-success', \n", - " 'btn-warning', 'btn-danger', 'btn-inverse', 'btn-link']\n", + "classes = [\n", + " 'btn', \n", + " 'btn-primary', \n", + " 'btn-info', \n", + " 'btn-success', \n", + " 'btn-warning', \n", + " 'btn-danger', \n", + " 'btn-inverse', \n", + " 'btn-link'\n", + "]\n", + "\n", + "# Display the buttons in a hbox\n", + "container = widgets.ContainerWidget(children=[widgets.ButtonWidget(description=c) for c in classes])\n", + "display(container)\n", + "\n", + "# Apply classes after display\n", + "container.remove_class('vbox')\n", + "container.add_class('hbox')\n", + "ret = [container.children[i].add_class(c) for i, c in enumerate(classes)]" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 180 + }, + { + "cell_type": "heading", + "level": 3, + "metadata": {}, + "source": [ + "ContainerWidgets" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "def create_label(cls):\n", + " class_name = widgets.HTMLWidget(value=cls)\n", + " container = widgets.ContainerWidget(children=[class_name])\n", + " display(container)\n", + " container.add_class(cls)\n", "\n", - "# Create each button and apply the style. Also add margin to the buttons so they space\n", - "# themselves nicely.\n", - "for i in range(8):\n", - " button = widgets.ButtonWidget(description=button_classes[i])\n", - " button.set_css(\"margin\", \"5px\")\n", - " display(button)\n", - " if i > 0: # Don't add a class the first button.\n", - " button.add_class(button_classes[i])\n", - " " + "ret = [create_label(c) for c in [\n", + " 'alert', \n", + " 'alert alert-error', \n", + " 'alert alert-success', \n", + " 'alert alert-info'\n", + "]]" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 181 + }, + { + "cell_type": "heading", + "level": 3, + "metadata": {}, + "source": [ + "*ProgressWidgets" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "classes = [\n", + " 'progress-info', \n", + " 'progress-success', \n", + " 'progress-warning', \n", + " 'progress-danger',\n", + " 'progress-striped progress-info', \n", + " 'progress-striped progress-success', \n", + " 'progress-striped progress-warning', \n", + " 'progress-striped progress-danger',\n", + " 'active progress-striped progress-info', \n", + " 'active progress-striped progress-success', \n", + " 'active progress-striped progress-warning', \n", + " 'active progress-striped progress-danger',\n", + "]\n", + "ws = [widgets.IntProgressWidget(value=50, description=c) for c in classes]\n", + "ret = [display(w) for w in ws]\n", + "ret = [ws[i].add_class(c) for i, c in enumerate(classes)]" ], "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 8 + "prompt_number": 182 + }, + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "Visibility" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "It is also useful to be able to remove CSS classes from widgets.\n", - "The `remove_class` method allows you to remove classes from widgets that have been displayed.\n", - "Like `add_class`, it must be called after the widget has been displayed." + "Sometimes it is necessary to hide or show widgets in place, without having to redisplay the widget.\n", + "The `visibility` property of widgets can be used to hide or show widgets that have already been displayed (as seen below)." ] }, { "cell_type": "code", "collapsed": false, "input": [ - "print(widgets.DOMWidget.remove_class.__doc__)" + "string = widgets.LatexWidget(value=\"Hello World!\")\n", + "display(string) " ], "language": "python", "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Remove class[es] from a DOM element.\n", - "\n", - " Parameters\n", - " ----------\n", - " class_names: unicode or list\n", - " Class name(s) to remove from the DOM element(s).\n", - " selector: unicode (optional)\n", - " JQuery selector to select the DOM element(s) that the class(es) will\n", - " be removed from.\n", - " \n" - ] - } + "outputs": [], + "prompt_number": 183 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "string.visible=False" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 184 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "string.visible=True" ], - "prompt_number": 9 + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 185 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The example below animates an alert using different bootstrap styles." + "In the example below, a form is rendered, which conditionally displays widgets depending on the state of other widgets. Try toggling the student checkbox." ] }, { "cell_type": "code", "collapsed": false, "input": [ - "import time\n", - "label = widgets.LatexWidget(value = \"$\\\\textbf{ALERT:} Hello World!$\")\n", - "display(label)\n", + "form = widgets.ContainerWidget()\n", + "first = widgets.TextWidget(description=\"First Name:\")\n", + "last = widgets.TextWidget(description=\"Last Name:\")\n", + "\n", + "student = widgets.CheckboxWidget(description=\"Student:\", value=False)\n", + "school_info = widgets.ContainerWidget(visible=False, children=[\n", + " widgets.TextWidget(description=\"School:\"),\n", + " widgets.IntTextWidget(description=\"Grade:\", min=0, max=12)\n", + " ])\n", "\n", - "# Apply twitter bootstrap alert class to the label.\n", - "label.add_class(\"alert\")\n", + "pet = widgets.TextWidget(description=\"Pet's Name:\")\n", + "form.children = [first, last, student, school_info, pet]\n", + "display(form)\n", "\n", - "# Animate through additional bootstrap label styles 3 times\n", - "additional_alert_styles = ['alert-error', 'alert-info', 'alert-success']\n", - "for i in range(3 * len(additional_alert_styles)):\n", - " label.add_class(additional_alert_styles[i % 3])\n", - " label.remove_class(additional_alert_styles[(i-1) % 3])\n", - " time.sleep(1)\n", - " " + "def on_student_toggle(name, value):\n", + " if value:\n", + " school_info.visible = True\n", + " else:\n", + " school_info.visible = False\n", + "student.on_trait_change(on_student_toggle, 'value')\n" ], "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 10 + "prompt_number": 186 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[Next](Custom Widget - Hello World.ipynb)" + ] } ], "metadata": {}