From c01a6f3082f360f7adef339d92b27e3923830578 2014-08-20 18:15:22 From: Brian E. Granger Date: 2014-08-20 18:15:22 Subject: [PATCH] Merge pull request #6125 from jdfreder/flex Embrace the flexible box model in the widgets --- diff --git a/IPython/html/static/base/less/flexbox.less b/IPython/html/static/base/less/flexbox.less index 4623833..62eaad2 100644 --- a/IPython/html/static/base/less/flexbox.less +++ b/IPython/html/static/base/less/flexbox.less @@ -184,6 +184,30 @@ Browsers not listed, including Safari, are supported via the styling under the justify-content: center; } +.hbox.baseline, +.vbox.baseline, +.baseline { + /* Old browsers */ + -webkit-box-pack: baseline; + -moz-box-pack: baseline; + box-pack: baseline; + + /* Modern browsers */ + justify-content: baseline; +} + +.hbox.stretch, +.vbox.stretch, +.stretch { + /* Old browsers */ + -webkit-box-pack: stretch; + -moz-box-pack: stretch; + box-pack: stretch; + + /* Modern browsers */ + justify-content: stretch; +} + .hbox.align-start, .vbox.align-start, .align-start { @@ -219,3 +243,27 @@ Browsers not listed, including Safari, are supported via the styling under the /* Modern browsers */ align-items: center; } + +.hbox.align-baseline, +.vbox.align-baseline, +.align-baseline { + /* Old browsers */ + -webkit-box-align: baseline; + -moz-box-align: baseline; + box-align: baseline; + + /* Modern browsers */ + align-items: baseline; +} + +.hbox.align-stretch, +.vbox.align-stretch, +.align-stretch { + /* Old browsers */ + -webkit-box-align: stretch; + -moz-box-align: stretch; + box-align: stretch; + + /* Modern browsers */ + align-items: stretch; +} diff --git a/IPython/html/static/style/ipython.min.css b/IPython/html/static/style/ipython.min.css index add3cd0..367bf10 100644 --- a/IPython/html/static/style/ipython.min.css +++ b/IPython/html/static/style/ipython.min.css @@ -1493,7 +1493,7 @@ div.cell.text_cell.rendered { box-pack: start; /* Modern browsers */ justify-content: flex-start; - /* ContainerWidget */ + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -1524,7 +1524,7 @@ div.cell.text_cell.rendered { box-pack: start; /* Modern browsers */ justify-content: flex-start; - /* ContainerWidget */ + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -1576,7 +1576,7 @@ div.cell.text_cell.rendered { box-pack: start; /* Modern browsers */ justify-content: flex-start; - /* ContainerWidget */ + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -1631,7 +1631,7 @@ div.cell.text_cell.rendered { box-pack: start; /* Modern browsers */ justify-content: flex-start; - /* ContainerWidget */ + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -1683,7 +1683,7 @@ div.cell.text_cell.rendered { box-pack: start; /* Modern browsers */ justify-content: flex-start; - /* ContainerWidget */ + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -1716,7 +1716,7 @@ div.cell.text_cell.rendered { width: 30px; } .widget-modal { - /* ContainerWidget - ModalView */ + /* Box - ModalView */ overflow: hidden; position: absolute !important; top: 0px; @@ -1724,11 +1724,11 @@ div.cell.text_cell.rendered { margin-left: 0px !important; } .widget-modal-body { - /* ContainerWidget - ModalView Body */ + /* Box - ModalView Body */ max-height: none !important; } -.widget-container { - /* ContainerWidget */ +.widget-box { + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; diff --git a/IPython/html/static/style/style.min.css b/IPython/html/static/style/style.min.css index 9fe1651..78642f3 100644 --- a/IPython/html/static/style/style.min.css +++ b/IPython/html/static/style/style.min.css @@ -9265,7 +9265,7 @@ div.cell.text_cell.rendered { box-pack: start; /* Modern browsers */ justify-content: flex-start; - /* ContainerWidget */ + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -9296,7 +9296,7 @@ div.cell.text_cell.rendered { box-pack: start; /* Modern browsers */ justify-content: flex-start; - /* ContainerWidget */ + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -9348,7 +9348,7 @@ div.cell.text_cell.rendered { box-pack: start; /* Modern browsers */ justify-content: flex-start; - /* ContainerWidget */ + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -9403,7 +9403,7 @@ div.cell.text_cell.rendered { box-pack: start; /* Modern browsers */ justify-content: flex-start; - /* ContainerWidget */ + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -9455,7 +9455,7 @@ div.cell.text_cell.rendered { box-pack: start; /* Modern browsers */ justify-content: flex-start; - /* ContainerWidget */ + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -9488,7 +9488,7 @@ div.cell.text_cell.rendered { width: 30px; } .widget-modal { - /* ContainerWidget - ModalView */ + /* Box - ModalView */ overflow: hidden; position: absolute !important; top: 0px; @@ -9496,11 +9496,11 @@ div.cell.text_cell.rendered { margin-left: 0px !important; } .widget-modal-body { - /* ContainerWidget - ModalView Body */ + /* Box - ModalView Body */ max-height: none !important; } -.widget-container { - /* ContainerWidget */ +.widget-box { + /* Box */ box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; diff --git a/IPython/html/static/widgets/js/init.js b/IPython/html/static/widgets/js/init.js index 1d92668..cfbd134 100644 --- a/IPython/html/static/widgets/js/init.js +++ b/IPython/html/static/widgets/js/init.js @@ -5,7 +5,7 @@ define([ "widgets/js/manager", "widgets/js/widget_bool", "widgets/js/widget_button", - "widgets/js/widget_container", + "widgets/js/widget_box", "widgets/js/widget_float", "widgets/js/widget_image", "widgets/js/widget_int", diff --git a/IPython/html/static/widgets/js/widget_container.js b/IPython/html/static/widgets/js/widget_box.js similarity index 76% rename from IPython/html/static/widgets/js/widget_container.js rename to IPython/html/static/widgets/js/widget_box.js index e568733..a1e97fe 100644 --- a/IPython/html/static/widgets/js/widget_container.js +++ b/IPython/html/static/widgets/js/widget_box.js @@ -7,11 +7,10 @@ define([ "bootstrap", ], function(widget, $){ - var ContainerView = widget.DOMWidgetView.extend({ + var BoxView = widget.DOMWidgetView.extend({ initialize: function(){ // Public constructor - ContainerView.__super__.initialize.apply(this, arguments); - this.update_children([], this.model.get('children')); + BoxView.__super__.initialize.apply(this, arguments); this.model.on('change:children', function(model, value) { this.update_children(model.previous('children'), value); }, this); @@ -19,7 +18,9 @@ define([ render: function(){ // Called when view is rendered. - this.$el.addClass('widget-container').addClass('vbox'); + this.$box = this.$el; + this.$box.addClass('widget-box'); + this.update_children([], this.model.get('children')); }, update_children: function(old_list, new_list) { @@ -37,7 +38,7 @@ define([ add_child_model: function(model) { // Called when a model is added to the children list. var view = this.create_child_view(model); - this.$el.append(view.$el); + this.$box.append(view.$el); // Trigger the displayed event of the child view. this.after_displayed(function() { @@ -45,9 +46,54 @@ define([ }); }, }); - - var PopupView = widget.DOMWidgetView.extend({ + + var FlexBoxView = BoxView.extend({ + render: function(){ + FlexBoxView.__super__.render.apply(this); + this.model.on('change:orientation', this.update_orientation, this); + this.model.on('change:flex', this._flex_changed, this); + this.model.on('change:pack', this._pack_changed, this); + this.model.on('change:align', this._align_changed, this); + this._flex_changed(); + this._pack_changed(); + this._align_changed(); + this.update_orientation(); + }, + + update_orientation: function(){ + var orientation = this.model.get("orientation"); + if (orientation == "vertical") { + this.$box.removeClass("hbox").addClass("vbox"); + } else { + this.$box.removeClass("vbox").addClass("hbox"); + } + }, + + _flex_changed: function(){ + if (this.model.previous('flex')) { + this.$box.removeClass('box-flex' + this.model.previous('flex')); + } + this.$box.addClass('box-flex' + this.model.get('flex')); + }, + + _pack_changed: function(){ + if (this.model.previous('pack')) { + this.$box.removeClass(this.model.previous('pack')); + } + this.$box.addClass(this.model.get('pack')); + }, + + _align_changed: function(){ + if (this.model.previous('align')) { + this.$box.removeClass('align-' + this.model.previous('align')); + } + this.$box.addClass('align-' + this.model.get('align')); + }, + }); + + var PopupView = BoxView.extend({ + render: function(){ // Called when view is rendered. var that = this; @@ -130,11 +176,11 @@ define([ this.$title = $('
') .addClass('widget-modal-title') .html(" ") - .appendTo(this.$title_bar); - this.$body = $('
') + .appendTo(this.$title_bar); + this.$box = $('
') .addClass('modal-body') .addClass('widget-modal-body') - .addClass('widget-container') + .addClass('widget-box') .addClass('vbox') .appendTo(this.$window); @@ -149,7 +195,7 @@ define([ this.$window.draggable({handle: '.popover-title', snap: '#notebook, .modal', snapMode: 'both'}); this.$window.resizable(); this.$window.on('resize', function(){ - that.$body.outerHeight(that.$window.innerHeight() - that.$title_bar.outerHeight()); + that.$box.outerHeight(that.$window.innerHeight() - that.$title_bar.outerHeight()); }); this._shown_once = false; @@ -203,29 +249,6 @@ define([ this.$window.css('z-index', max_zindex); }, - update_children: function(old_list, new_list) { - // Called when the children list is modified. - this.do_diff(old_list, new_list, - $.proxy(this.remove_child_model, this), - $.proxy(this.add_child_model, this)); - }, - - remove_child_model: function(model) { - // Called when a child is removed from children list. - this.pop_child_view(model).remove(); - }, - - add_child_model: function(model) { - // Called when a child is added to children list. - var view = this.create_child_view(model); - this.$body.append(view.$el); - - // Trigger the displayed event of the child view. - this.after_displayed(function() { - view.trigger('displayed'); - }); - }, - update: function(){ // Update the contents of this view // @@ -277,7 +300,8 @@ define([ }); return { - 'ContainerView': ContainerView, + 'BoxView': BoxView, 'PopupView': PopupView, + 'FlexBoxView': FlexBoxView, }; }); diff --git a/IPython/html/static/widgets/less/widgets.less b/IPython/html/static/widgets/less/widgets.less index 4eed2e2..12f8cf9 100644 --- a/IPython/html/static/widgets/less/widgets.less +++ b/IPython/html/static/widgets/less/widgets.less @@ -216,7 +216,7 @@ margin : 5px; .start(); - .widget-container(); + .widget-box(); } .widget-hbox { @@ -248,7 +248,7 @@ } .widget-modal { - /* ContainerWidget - ModalView */ + /* Box - ModalView */ overflow : hidden; position : absolute !important; top : 0px; @@ -257,12 +257,12 @@ } .widget-modal-body { - /* ContainerWidget - ModalView Body */ + /* Box - ModalView Body */ max-height: none !important; } -.widget-container { - /* ContainerWidget */ +.widget-box { + /* Box */ .border-box-sizing(); .align-start(); } diff --git a/IPython/html/tests/widgets/widget.js b/IPython/html/tests/widgets/widget.js index 787b0f2..005d75e 100644 --- a/IPython/html/tests/widgets/widget.js +++ b/IPython/html/tests/widgets/widget.js @@ -147,7 +147,7 @@ casper.notebook_test(function () { var textbox = {}; throttle_index = this.append_cell( 'import time\n' + - 'textbox = widgets.TextWidget()\n' + + 'textbox = widgets.Text()\n' + 'display(textbox)\n' + 'textbox.add_class("my-throttle-textbox", selector="input")\n' + 'def handle_change(name, old, new):\n' + diff --git a/IPython/html/tests/widgets/widget_bool.js b/IPython/html/tests/widgets/widget_bool.js index 4fd1007..0fe80b9 100644 --- a/IPython/html/tests/widgets/widget_bool.js +++ b/IPython/html/tests/widgets/widget_bool.js @@ -7,8 +7,8 @@ casper.notebook_test(function () { this.execute_cell_then(index); var bool_index = this.append_cell( - 'bool_widgets = [widgets.CheckboxWidget(description="Title", value=True),\n' + - ' widgets.ToggleButtonWidget(description="Title", value=True)]\n' + + 'bool_widgets = [widgets.Checkbox(description="Title", value=True),\n' + + ' widgets.ToggleButton(description="Title", value=True)]\n' + 'display(bool_widgets[0])\n' + 'display(bool_widgets[1])\n' + 'print("Success")'); diff --git a/IPython/html/tests/widgets/widget_container.js b/IPython/html/tests/widgets/widget_box.js similarity index 93% rename from IPython/html/tests/widgets/widget_container.js rename to IPython/html/tests/widgets/widget_box.js index e3faa75..c1b422a 100644 --- a/IPython/html/tests/widgets/widget_container.js +++ b/IPython/html/tests/widgets/widget_box.js @@ -7,8 +7,8 @@ casper.notebook_test(function () { this.execute_cell_then(index); var container_index = this.append_cell( - 'container = widgets.ContainerWidget()\n' + - 'button = widgets.ButtonWidget()\n'+ + 'container = widgets.Box()\n' + + 'button = widgets.Button()\n'+ 'container.children = [button]\n'+ 'display(container)\n'+ 'container.add_class("my-test-class")\n'+ @@ -23,7 +23,7 @@ casper.notebook_test(function () { 'Widget subarea exists.'); this.test.assert(this.cell_element_exists(index, - '.widget-area .widget-subarea .widget-container'), + '.widget-area .widget-subarea .widget-box'), 'Widget container exists.'); this.test.assert(this.cell_element_exists(index, @@ -70,7 +70,7 @@ casper.notebook_test(function () { 'Display container child executed with correct output.'); this.test.assert(! this.cell_element_exists(index, - '.widget-area .widget-subarea .widget-container'), + '.widget-area .widget-subarea .widget-box'), 'Parent container not displayed.'); this.test.assert(this.cell_element_exists(index, diff --git a/IPython/html/tests/widgets/widget_button.js b/IPython/html/tests/widgets/widget_button.js index ae0aec6..304f64d 100644 --- a/IPython/html/tests/widgets/widget_button.js +++ b/IPython/html/tests/widgets/widget_button.js @@ -7,7 +7,7 @@ casper.notebook_test(function () { this.execute_cell_then(index); var button_index = this.append_cell( - 'button = widgets.ButtonWidget(description="Title")\n' + + 'button = widgets.Button(description="Title")\n' + 'display(button)\n' + 'print("Success")\n' + 'def handle_click(sender):\n' + diff --git a/IPython/html/tests/widgets/widget_float.js b/IPython/html/tests/widgets/widget_float.js index a26c42d..a2f4e74 100644 --- a/IPython/html/tests/widgets/widget_float.js +++ b/IPython/html/tests/widgets/widget_float.js @@ -9,7 +9,7 @@ casper.notebook_test(function () { var float_text = {}; float_text.query = '.widget-area .widget-subarea .widget-hbox-single .my-second-float-text'; float_text.index = this.append_cell( - 'float_widget = widgets.FloatTextWidget()\n' + + 'float_widget = widgets.FloatText()\n' + 'display(float_widget)\n' + 'float_widget.add_class("my-second-float-text", selector="input")\n' + 'print(float_widget.model_id)\n'); @@ -59,8 +59,8 @@ casper.notebook_test(function () { var slider = {}; slider.query = '.widget-area .widget-subarea .widget-hbox-single .slider'; slider.index = this.append_cell( - 'floatrange = [widgets.BoundedFloatTextWidget(), \n' + - ' widgets.FloatSliderWidget()]\n' + + 'floatrange = [widgets.BoundedFloatText(), \n' + + ' widgets.FloatSlider()]\n' + '[display(floatrange[i]) for i in range(2)]\n' + 'print("Success")\n'); this.execute_cell_then(slider.index, function(index){ diff --git a/IPython/html/tests/widgets/widget_image.js b/IPython/html/tests/widgets/widget_image.js index 04b1451..c858c68 100644 --- a/IPython/html/tests/widgets/widget_image.js +++ b/IPython/html/tests/widgets/widget_image.js @@ -18,7 +18,7 @@ casper.notebook_test(function () { var image_index = this.append_cell( 'import base64\n' + 'data = base64.b64decode("' + test_jpg + '")\n' + - 'image = widgets.ImageWidget()\n' + + 'image = widgets.Image()\n' + 'image.format = "jpeg"\n' + 'image.value = data\n' + 'image.width = "50px"\n' + diff --git a/IPython/html/tests/widgets/widget_int.js b/IPython/html/tests/widgets/widget_int.js index 4393664..a9bc43d 100644 --- a/IPython/html/tests/widgets/widget_int.js +++ b/IPython/html/tests/widgets/widget_int.js @@ -9,7 +9,7 @@ casper.notebook_test(function () { var int_text = {}; int_text.query = '.widget-area .widget-subarea .widget-hbox-single .my-second-int-text'; int_text.index = this.append_cell( - 'int_widget = widgets.IntTextWidget()\n' + + 'int_widget = widgets.IntText()\n' + 'display(int_widget)\n' + 'int_widget.add_class("my-second-int-text", selector="input")\n' + 'print(int_widget.model_id)\n'); diff --git a/IPython/html/tests/widgets/widget_selection.js b/IPython/html/tests/widgets/widget_selection.js index 25d5b86..dac47e0 100644 --- a/IPython/html/tests/widgets/widget_selection.js +++ b/IPython/html/tests/widgets/widget_selection.js @@ -44,10 +44,10 @@ casper.notebook_test(function () { //values=["' + selection_values + '"[i] for i in range(4)] selection_index = this.append_cell( 'values=["' + selection_values + '"[i] for i in range(4)]\n' + - 'selection = [widgets.DropdownWidget(values=values),\n' + - ' widgets.ToggleButtonsWidget(values=values),\n' + - ' widgets.RadioButtonsWidget(values=values),\n' + - ' widgets.SelectWidget(values=values)]\n' + + 'selection = [widgets.Dropdown(values=values),\n' + + ' widgets.ToggleButtons(values=values),\n' + + ' widgets.RadioButtons(values=values),\n' + + ' widgets.Select(values=values)]\n' + '[display(selection[i]) for i in range(4)]\n' + 'for widget in selection:\n' + ' def handle_change(name,old,new):\n' + diff --git a/IPython/html/tests/widgets/widget_selectioncontainer.js b/IPython/html/tests/widgets/widget_selectioncontainer.js index 1cc9526..57e9bd1 100644 --- a/IPython/html/tests/widgets/widget_selectioncontainer.js +++ b/IPython/html/tests/widgets/widget_selectioncontainer.js @@ -9,10 +9,10 @@ casper.notebook_test(function () { // Test tab view var multicontainer1_query = '.widget-area .widget-subarea div div.nav-tabs'; var multicontainer1_index = this.append_cell( - 'multicontainer = widgets.TabWidget()\n' + - 'page1 = widgets.TextWidget()\n' + - 'page2 = widgets.TextWidget()\n' + - 'page3 = widgets.TextWidget()\n' + + 'multicontainer = widgets.Tab()\n' + + 'page1 = widgets.Text()\n' + + 'page2 = widgets.Text()\n' + + 'page3 = widgets.Text()\n' + 'multicontainer.children = [page1, page2, page3]\n' + 'display(multicontainer)\n' + 'multicontainer.selected_index = 0\n' + @@ -64,10 +64,10 @@ casper.notebook_test(function () { // Test accordion view var multicontainer2_query = '.widget-area .widget-subarea .panel-group'; var multicontainer2_index = this.append_cell( - 'multicontainer = widgets.AccordionWidget()\n' + - 'page1 = widgets.TextWidget()\n' + - 'page2 = widgets.TextWidget()\n' + - 'page3 = widgets.TextWidget()\n' + + 'multicontainer = widgets.Accordion()\n' + + 'page1 = widgets.Text()\n' + + 'page2 = widgets.Text()\n' + + 'page3 = widgets.Text()\n' + 'multicontainer.children = [page1, page2, page3]\n' + 'multicontainer.set_title(2, "good")\n' + 'display(multicontainer)\n' + diff --git a/IPython/html/tests/widgets/widget_string.js b/IPython/html/tests/widgets/widget_string.js index 1288cbd..8e9acee 100644 --- a/IPython/html/tests/widgets/widget_string.js +++ b/IPython/html/tests/widgets/widget_string.js @@ -7,10 +7,10 @@ casper.notebook_test(function () { this.execute_cell_then(index); var string_index = this.append_cell( - 'string_widget = [widgets.TextWidget(value = "xyz", placeholder = "abc"),\n' + - ' widgets.TextareaWidget(value = "xyz", placeholder = "def"),\n' + - ' widgets.HTMLWidget(value = "xyz"),\n' + - ' widgets.LatexWidget(value = "$\\\\LaTeX{}$")]\n' + + 'string_widget = [widgets.Text(value = "xyz", placeholder = "abc"),\n' + + ' widgets.Textarea(value = "xyz", placeholder = "def"),\n' + + ' widgets.HTML(value = "xyz"),\n' + + ' widgets.Latex(value = "$\\\\LaTeX{}$")]\n' + '[display(widget) for widget in string_widget]\n'+ 'print("Success")'); this.execute_cell_then(string_index, function(index){ diff --git a/IPython/html/widgets/__init__.py b/IPython/html/widgets/__init__.py index 7b6d0a8..c16c7d7 100644 --- a/IPython/html/widgets/__init__.py +++ b/IPython/html/widgets/__init__.py @@ -1,12 +1,23 @@ from .widget import Widget, DOMWidget, CallbackDispatcher +from .widget_bool import Checkbox, ToggleButton +from .widget_button import Button +from .widget_box import Box, Popup, FlexBox, HBox, VBox +from .widget_float import FloatText, BoundedFloatText, FloatSlider, FloatProgress +from .widget_image import Image +from .widget_int import IntText, BoundedIntText, IntSlider, IntProgress +from .widget_selection import RadioButtons, ToggleButtons, Dropdown, Select +from .widget_selectioncontainer import Tab, Accordion +from .widget_string import HTML, Latex, Text, Textarea +from .interaction import interact, interactive, fixed + +# Deprecated classes from .widget_bool import CheckboxWidget, ToggleButtonWidget from .widget_button import ButtonWidget -from .widget_container import ContainerWidget, PopupWidget +from .widget_box import ContainerWidget, PopupWidget from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget from .widget_image import ImageWidget from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget from .widget_selectioncontainer import TabWidget, AccordionWidget from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget -from .interaction import interact, interactive, fixed diff --git a/IPython/html/widgets/interaction.py b/IPython/html/widgets/interaction.py index 1b59de8..86c7125 100644 --- a/IPython/html/widgets/interaction.py +++ b/IPython/html/widgets/interaction.py @@ -21,9 +21,9 @@ except ImportError: from inspect import getcallargs from IPython.core.getipython import get_ipython -from IPython.html.widgets import (Widget, TextWidget, - FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget, - ContainerWidget, DOMWidget) +from IPython.html.widgets import (Widget, Text, + FloatSlider, IntSlider, Checkbox, Dropdown, + Box, DOMWidget) from IPython.display import display, clear_output from IPython.utils.py3compat import string_types, unicode_type from IPython.utils.traitlets import HasTraits, Any, Unicode @@ -70,17 +70,17 @@ def _get_min_max_value(min, max, value=None, step=None): def _widget_abbrev_single_value(o): """Make widgets from single values, which can be used as parameter defaults.""" if isinstance(o, string_types): - return TextWidget(value=unicode_type(o)) + return Text(value=unicode_type(o)) elif isinstance(o, dict): - return DropdownWidget(values=o) + return Dropdown(values=o) elif isinstance(o, bool): - return CheckboxWidget(value=o) + return Checkbox(value=o) elif isinstance(o, float): min, max, value = _get_min_max_value(None, None, o) - return FloatSliderWidget(value=o, min=min, max=max) + return FloatSlider(value=o, min=min, max=max) elif isinstance(o, int): min, max, value = _get_min_max_value(None, None, o) - return IntSliderWidget(value=o, min=min, max=max) + return IntSlider(value=o, min=min, max=max) else: return None @@ -89,13 +89,13 @@ def _widget_abbrev(o): float_or_int = (float, int) if isinstance(o, (list, tuple)): if o and all(isinstance(x, string_types) for x in o): - return DropdownWidget(values=[unicode_type(k) for k in o]) + return Dropdown(values=[unicode_type(k) for k in o]) elif _matches(o, (float_or_int, float_or_int)): min, max, value = _get_min_max_value(o[0], o[1]) if all(isinstance(_, int) for _ in o): - cls = IntSliderWidget + cls = IntSlider else: - cls = FloatSliderWidget + cls = FloatSlider return cls(value=value, min=min, max=max) elif _matches(o, (float_or_int, float_or_int, float_or_int)): step = o[2] @@ -103,9 +103,9 @@ def _widget_abbrev(o): raise ValueError("step must be >= 0, not %r" % step) min, max, value = _get_min_max_value(o[0], o[1], step=step) if all(isinstance(_, int) for _ in o): - cls = IntSliderWidget + cls = IntSlider else: - cls = FloatSliderWidget + cls = FloatSlider return cls(value=value, min=min, max=max, step=step) else: return _widget_abbrev_single_value(o) @@ -176,7 +176,7 @@ def interactive(__interact_f, **kwargs): f = __interact_f co = kwargs.pop('clear_output', True) kwargs_widgets = [] - container = ContainerWidget() + container = Box() container.result = None container.args = [] container.kwargs = dict() diff --git a/IPython/html/widgets/tests/test_interaction.py b/IPython/html/widgets/tests/test_interaction.py index c5fe40d..0ef46d1 100644 --- a/IPython/html/widgets/tests/test_interaction.py +++ b/IPython/html/widgets/tests/test_interaction.py @@ -92,7 +92,7 @@ def test_single_value_string(): c = interactive(f, a=a) w = c.children[0] check_widget(w, - cls=widgets.TextWidget, + cls=widgets.Text, description='a', value=a, ) @@ -102,7 +102,7 @@ def test_single_value_bool(): c = interactive(f, a=a) w = c.children[0] check_widget(w, - cls=widgets.CheckboxWidget, + cls=widgets.Checkbox, description='a', value=a, ) @@ -115,7 +115,7 @@ def test_single_value_dict(): c = interactive(f, d=d) w = c.children[0] check_widget(w, - cls=widgets.DropdownWidget, + cls=widgets.Dropdown, description='d', values=d, value=next(iter(d.values())), @@ -126,7 +126,7 @@ def test_single_value_float(): c = interactive(f, a=a) w = c.children[0] check_widget(w, - cls=widgets.FloatSliderWidget, + cls=widgets.FloatSlider, description='a', value=a, min= -a if a > 0 else 3*a, @@ -141,7 +141,7 @@ def test_single_value_int(): nt.assert_equal(len(c.children), 1) w = c.children[0] check_widget(w, - cls=widgets.IntSliderWidget, + cls=widgets.IntSlider, description='a', value=a, min= -a if a > 0 else 3*a, @@ -159,7 +159,7 @@ def test_list_tuple_2_int(): c = interactive(f, tup=(min, max), lis=[min, max]) nt.assert_equal(len(c.children), 2) d = dict( - cls=widgets.IntSliderWidget, + cls=widgets.IntSlider, min=min, max=max, step=1, @@ -176,7 +176,7 @@ def test_list_tuple_3_int(): c = interactive(f, tup=(min, max, step), lis=[min, max, step]) nt.assert_equal(len(c.children), 2) d = dict( - cls=widgets.IntSliderWidget, + cls=widgets.IntSlider, min=min, max=max, step=step, @@ -193,7 +193,7 @@ def test_list_tuple_2_float(): c = interactive(f, tup=(min, max), lis=[min, max]) nt.assert_equal(len(c.children), 2) d = dict( - cls=widgets.FloatSliderWidget, + cls=widgets.FloatSlider, min=min, max=max, step=.1, @@ -212,7 +212,7 @@ def test_list_tuple_3_float(): c = interactive(f, tup=(min, max, step), lis=[min, max, step]) nt.assert_equal(len(c.children), 2) d = dict( - cls=widgets.FloatSliderWidget, + cls=widgets.FloatSlider, min=min, max=max, step=step, @@ -227,7 +227,7 @@ def test_list_tuple_str(): c = interactive(f, tup=tuple(values), lis=list(values)) nt.assert_equal(len(c.children), 2) d = dict( - cls=widgets.DropdownWidget, + cls=widgets.Dropdown, value=first, values=dvalues ) @@ -253,15 +253,15 @@ def test_defaults(): c = interactive(f) check_widgets(c, n=dict( - cls=widgets.IntSliderWidget, + cls=widgets.IntSlider, value=10, ), f=dict( - cls=widgets.FloatSliderWidget, + cls=widgets.FloatSlider, value=4.5, ), g=dict( - cls=widgets.IntSliderWidget, + cls=widgets.IntSlider, value=1, ), ) @@ -274,24 +274,24 @@ def test_default_values(): c = interactive(f) check_widgets(c, n=dict( - cls=widgets.IntSliderWidget, + cls=widgets.IntSlider, value=10, ), f=dict( - cls=widgets.FloatSliderWidget, + cls=widgets.FloatSlider, value=4.5, ), g=dict( - cls=widgets.IntSliderWidget, + cls=widgets.IntSlider, value=5, ), h=dict( - cls=widgets.DropdownWidget, + cls=widgets.Dropdown, values={'a': 1, 'b': 2}, value=2 ), j=dict( - cls=widgets.DropdownWidget, + cls=widgets.Dropdown, values={'hi':'hi', 'there':'there'}, value='there' ), @@ -305,34 +305,34 @@ def test_default_out_of_bounds(): c = interactive(f) check_widgets(c, f=dict( - cls=widgets.FloatSliderWidget, + cls=widgets.FloatSlider, value=5., ), h=dict( - cls=widgets.DropdownWidget, + cls=widgets.Dropdown, values={'a': 1}, value=1, ), j=dict( - cls=widgets.DropdownWidget, + cls=widgets.Dropdown, values={'hi':'hi', 'there':'there'}, value='hi', ), ) def test_annotations(): - @annotate(n=10, f=widgets.FloatTextWidget()) + @annotate(n=10, f=widgets.FloatText()) def f(n, f): pass c = interactive(f) check_widgets(c, n=dict( - cls=widgets.IntSliderWidget, + cls=widgets.IntSlider, value=10, ), f=dict( - cls=widgets.FloatTextWidget, + cls=widgets.FloatText, ), ) @@ -344,11 +344,11 @@ def test_priority(): c = interactive(f, kwarg='kwarg') check_widgets(c, kwarg=dict( - cls=widgets.TextWidget, + cls=widgets.Text, value='kwarg', ), annotate=dict( - cls=widgets.TextWidget, + cls=widgets.Text, value='annotate', ), ) @@ -362,7 +362,7 @@ def test_decorator_kwarg(): nt.assert_equal(len(displayed), 1) w = displayed[0].children[0] check_widget(w, - cls=widgets.IntSliderWidget, + cls=widgets.IntSlider, value=5, ) @@ -375,7 +375,7 @@ def test_decorator_no_call(): nt.assert_equal(len(displayed), 1) w = displayed[0].children[0] check_widget(w, - cls=widgets.TextWidget, + cls=widgets.Text, value='default', ) @@ -388,7 +388,7 @@ def test_call_interact(): nt.assert_equal(len(displayed), 1) w = displayed[0].children[0] check_widget(w, - cls=widgets.TextWidget, + cls=widgets.Text, value='default', ) @@ -401,7 +401,7 @@ def test_call_interact_kwargs(): nt.assert_equal(len(displayed), 1) w = displayed[0].children[0] check_widget(w, - cls=widgets.IntSliderWidget, + cls=widgets.IntSlider, value=10, ) @@ -417,7 +417,7 @@ def test_call_decorated_on_trait_change(): nt.assert_equal(len(displayed), 1) w = displayed[0].children[0] check_widget(w, - cls=widgets.TextWidget, + cls=widgets.Text, value='default', ) # test calling the function directly @@ -441,7 +441,7 @@ def test_call_decorated_kwargs_on_trait_change(): nt.assert_equal(len(displayed), 1) w = displayed[0].children[0] check_widget(w, - cls=widgets.TextWidget, + cls=widgets.Text, value='kwarg', ) # test calling the function directly @@ -458,7 +458,7 @@ def test_fixed(): nt.assert_equal(len(c.children), 1) w = c.children[0] check_widget(w, - cls=widgets.TextWidget, + cls=widgets.Text, value='text', description='b', ) @@ -467,16 +467,16 @@ def test_default_description(): c = interactive(f, b='text') w = c.children[0] check_widget(w, - cls=widgets.TextWidget, + cls=widgets.Text, value='text', description='b', ) def test_custom_description(): - c = interactive(f, b=widgets.TextWidget(value='text', description='foo')) + c = interactive(f, b=widgets.Text(value='text', description='foo')) w = c.children[0] check_widget(w, - cls=widgets.TextWidget, + cls=widgets.Text, value='text', description='foo', ) diff --git a/IPython/html/widgets/widget_bool.py b/IPython/html/widgets/widget_bool.py index ac07d7f..b7bbb1d 100644 --- a/IPython/html/widgets/widget_bool.py +++ b/IPython/html/widgets/widget_bool.py @@ -1,4 +1,4 @@ -"""BoolWidget class. +"""Bool class. Represents a boolean using a widget. """ @@ -15,20 +15,29 @@ Represents a boolean using a widget. #----------------------------------------------------------------------------- from .widget import DOMWidget from IPython.utils.traitlets import Unicode, Bool +from IPython.utils.warn import DeprecatedClass #----------------------------------------------------------------------------- # Classes #----------------------------------------------------------------------------- -class _BoolWidget(DOMWidget): +class _Bool(DOMWidget): + """A base class for creating widgets that represent booleans.""" value = Bool(False, help="Bool value", sync=True) - description = Unicode('', help="Description of the boolean (label).", sync=True) + description = Unicode('', help="Description of the boolean (label).", sync=True) disabled = Bool(False, help="Enable or disable user changes.", sync=True) -class CheckboxWidget(_BoolWidget): +class Checkbox(_Bool): + """Displays a boolean `value`.""" _view_name = Unicode('CheckboxView', sync=True) -class ToggleButtonWidget(_BoolWidget): - _view_name = Unicode('ToggleButtonView', sync=True) +class ToggleButton(_Bool): + """Displays a boolean `value`.""" + _view_name = Unicode('ToggleButtonView', sync=True) + + +# Remove in IPython 4.0 +CheckboxWidget = DeprecatedClass(Checkbox, 'CheckboxWidget') +ToggleButtonWidget = DeprecatedClass(ToggleButton, 'ToggleButtonWidget') diff --git a/IPython/html/widgets/widget_box.py b/IPython/html/widgets/widget_box.py new file mode 100644 index 0000000..bd204bd --- /dev/null +++ b/IPython/html/widgets/widget_box.py @@ -0,0 +1,73 @@ +"""Box class. + +Represents a container that can be used to group other widgets. +""" + +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + +from .widget import DOMWidget +from IPython.utils.traitlets import Unicode, Tuple, TraitError, Int, CaselessStrEnum +from IPython.utils.warn import DeprecatedClass + +class Box(DOMWidget): + """Displays multiple widgets in a group.""" + _view_name = Unicode('BoxView', sync=True) + + # Child widgets in the container. + # Using a tuple here to force reassignment to update the list. + # When a proper notifying-list trait exists, that is what should be used here. + children = Tuple(sync=True, allow_none=False) + + def __init__(self, children = (), **kwargs): + kwargs['children'] = children + super(Box, self).__init__(**kwargs) + self.on_displayed(Box._fire_children_displayed) + + def _fire_children_displayed(self): + for child in self.children: + child._handle_displayed() + + +class Popup(Box): + """Displays multiple widgets in an in page popup div.""" + _view_name = Unicode('PopupView', sync=True) + + description = Unicode(sync=True) + button_text = Unicode(sync=True) + + +class FlexBox(Box): + """Displays multiple widgets using the flexible box model.""" + _view_name = Unicode('FlexBoxView', sync=True) + orientation = CaselessStrEnum(values=['vertical', 'horizontal'], default_value='vertical', sync=True) + flex = Int(0, sync=True, help="""Specify the flexible-ness of the model.""") + def _flex_changed(self, name, old, new): + new = min(max(0, new), 2) + if self.flex != new: + self.flex = new + + _locations = ['start', 'center', 'end', 'baseline', 'stretch'] + pack = CaselessStrEnum( + values=_locations, + default_value='start', allow_none=False, sync=True) + align = CaselessStrEnum( + values=_locations, + default_value='start', allow_none=False, sync=True) + + +def VBox(*pargs, **kwargs): + """Displays multiple widgets vertically using the flexible box model.""" + kwargs['orientation'] = 'vertical' + return FlexBox(*pargs, **kwargs) + +def HBox(*pargs, **kwargs): + """Displays multiple widgets horizontally using the flexible box model.""" + kwargs['orientation'] = 'horizontal' + return FlexBox(*pargs, **kwargs) + + +# Remove in IPython 4.0 +ContainerWidget = DeprecatedClass(Box, 'ContainerWidget') +PopupWidget = DeprecatedClass(Popup, 'PopupWidget') + diff --git a/IPython/html/widgets/widget_button.py b/IPython/html/widgets/widget_button.py index 3fdfe72..17774cc 100644 --- a/IPython/html/widgets/widget_button.py +++ b/IPython/html/widgets/widget_button.py @@ -1,4 +1,4 @@ -"""ButtonWidget class. +"""Button class. Represents a button in the frontend using a widget. Allows user to listen for click events on the button and trigger backend code when the clicks are fired. @@ -16,11 +16,16 @@ click events on the button and trigger backend code when the clicks are fired. #----------------------------------------------------------------------------- from .widget import DOMWidget, CallbackDispatcher from IPython.utils.traitlets import Unicode, Bool +from IPython.utils.warn import DeprecatedClass #----------------------------------------------------------------------------- # Classes #----------------------------------------------------------------------------- -class ButtonWidget(DOMWidget): +class Button(DOMWidget): + """Button widget. + + This widget has an `on_click` method that allows you to listen for the + user clicking on the button. The click event itself is stateless.""" _view_name = Unicode('ButtonView', sync=True) # Keys @@ -29,7 +34,7 @@ class ButtonWidget(DOMWidget): def __init__(self, **kwargs): """Constructor""" - super(ButtonWidget, self).__init__(**kwargs) + super(Button, self).__init__(**kwargs) self._click_handlers = CallbackDispatcher() self.on_msg(self._handle_button_msg) @@ -54,3 +59,7 @@ class ButtonWidget(DOMWidget): Content of the msg.""" if content.get('event', '') == 'click': self._click_handlers(self) + + +# Remove in IPython 4.0 +ButtonWidget = DeprecatedClass(Button, 'ButtonWidget') diff --git a/IPython/html/widgets/widget_container.py b/IPython/html/widgets/widget_container.py deleted file mode 100644 index 6ba8206..0000000 --- a/IPython/html/widgets/widget_container.py +++ /dev/null @@ -1,34 +0,0 @@ -"""ContainerWidget class. - -Represents a container that can be used to group other widgets. -""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -from .widget import DOMWidget -from IPython.utils.traitlets import Unicode, Tuple, TraitError - -class ContainerWidget(DOMWidget): - _view_name = Unicode('ContainerView', sync=True) - - # Child widgets in the container. - # Using a tuple here to force reassignment to update the list. - # When a proper notifying-list trait exists, that is what should be used here. - children = Tuple(sync=True, allow_none=False) - - def __init__(self, children = (), **kwargs): - kwargs['children'] = children - super(ContainerWidget, self).__init__(**kwargs) - self.on_displayed(ContainerWidget._fire_children_displayed) - - def _fire_children_displayed(self): - for child in self.children: - child._handle_displayed() - - -class PopupWidget(ContainerWidget): - _view_name = Unicode('PopupView', sync=True) - - description = Unicode(sync=True) - button_text = Unicode(sync=True) diff --git a/IPython/html/widgets/widget_float.py b/IPython/html/widgets/widget_float.py index 7ddcd90..0c27456 100644 --- a/IPython/html/widgets/widget_float.py +++ b/IPython/html/widgets/widget_float.py @@ -1,4 +1,4 @@ -"""FloatWidget class. +"""Float class. Represents an unbounded float using a widget. """ @@ -15,17 +15,18 @@ Represents an unbounded float using a widget. #----------------------------------------------------------------------------- from .widget import DOMWidget from IPython.utils.traitlets import Unicode, CFloat, Bool, Enum +from IPython.utils.warn import DeprecatedClass #----------------------------------------------------------------------------- # Classes #----------------------------------------------------------------------------- -class _FloatWidget(DOMWidget): +class _Float(DOMWidget): value = CFloat(0.0, help="Float value", sync=True) disabled = Bool(False, help="Enable or disable user changes", sync=True) description = Unicode(help="Description of the value this widget represents", sync=True) -class _BoundedFloatWidget(_FloatWidget): +class _BoundedFloat(_Float): max = CFloat(100.0, help="Max value", sync=True) min = CFloat(0.0, help="Min value", sync=True) step = CFloat(0.1, help="Minimum step that the value can take (ignored by some views)", sync=True) @@ -42,20 +43,27 @@ class _BoundedFloatWidget(_FloatWidget): self.value = min(max(new, self.min), self.max) -class FloatTextWidget(_FloatWidget): +class FloatText(_Float): _view_name = Unicode('FloatTextView', sync=True) -class BoundedFloatTextWidget(_BoundedFloatWidget): +class BoundedFloatText(_BoundedFloat): _view_name = Unicode('FloatTextView', sync=True) -class FloatSliderWidget(_BoundedFloatWidget): +class FloatSlider(_BoundedFloat): _view_name = Unicode('FloatSliderView', sync=True) orientation = Enum([u'horizontal', u'vertical'], u'horizontal', help="Vertical or horizontal.", sync=True) readout = Bool(True, help="Display the current value of the slider next to it.", sync=True) -class FloatProgressWidget(_BoundedFloatWidget): +class FloatProgress(_BoundedFloat): _view_name = Unicode('ProgressView', sync=True) + + +# Remove in IPython 4.0 +FloatTextWidget = DeprecatedClass(FloatText, 'FloatTextWidget') +BoundedFloatTextWidget = DeprecatedClass(BoundedFloatText, 'BoundedFloatTextWidget') +FloatSliderWidget = DeprecatedClass(FloatSlider, 'FloatSliderWidget') +FloatProgressWidget = DeprecatedClass(FloatProgress, 'FloatProgressWidget') diff --git a/IPython/html/widgets/widget_image.py b/IPython/html/widgets/widget_image.py index 0e18bde..f8ff8d4 100644 --- a/IPython/html/widgets/widget_image.py +++ b/IPython/html/widgets/widget_image.py @@ -1,4 +1,4 @@ -"""ImageWidget class. +"""Image class. Represents an image in the frontend using a widget. """ @@ -17,11 +17,18 @@ import base64 from .widget import DOMWidget from IPython.utils.traitlets import Unicode, CUnicode, Bytes +from IPython.utils.warn import DeprecatedClass #----------------------------------------------------------------------------- # Classes #----------------------------------------------------------------------------- -class ImageWidget(DOMWidget): +class Image(DOMWidget): + """Displays an image as a widget. + + The `value` of this widget accepts a byte string. The byte string is the raw + image data that you want the browser to display. You can explicitly define + the format of the byte string using the `format` trait (which defaults to + "png").""" _view_name = Unicode('ImageView', sync=True) # Define the custom state properties to sync with the front-end @@ -33,3 +40,7 @@ class ImageWidget(DOMWidget): value = Bytes() def _value_changed(self, name, old, new): self._b64value = base64.b64encode(new) + + +# Remove in IPython 4.0 +ImageWidget = DeprecatedClass(Image, 'ImageWidget') diff --git a/IPython/html/widgets/widget_int.py b/IPython/html/widgets/widget_int.py index 4c9aa2c..807b527 100644 --- a/IPython/html/widgets/widget_int.py +++ b/IPython/html/widgets/widget_int.py @@ -1,4 +1,4 @@ -"""IntWidget class. +"""Int class. Represents an unbounded int using a widget. """ @@ -15,17 +15,21 @@ Represents an unbounded int using a widget. #----------------------------------------------------------------------------- from .widget import DOMWidget from IPython.utils.traitlets import Unicode, CInt, Bool, Enum +from IPython.utils.warn import DeprecatedClass #----------------------------------------------------------------------------- # Classes #----------------------------------------------------------------------------- -class _IntWidget(DOMWidget): +class _Int(DOMWidget): + """Base class used to create widgets that represent an int.""" value = CInt(0, help="Int value", sync=True) disabled = Bool(False, help="Enable or disable user changes", sync=True) description = Unicode(help="Description of the value this widget represents", sync=True) -class _BoundedIntWidget(_IntWidget): +class _BoundedInt(_Int): + """Base class used to create widgets that represent a int that is bounded + by a minium and maximum.""" step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True) max = CInt(100, help="Max value", sync=True) min = CInt(0, help="Min value", sync=True) @@ -41,20 +45,31 @@ class _BoundedIntWidget(_IntWidget): self.value = min(max(new, self.min), self.max) -class IntTextWidget(_IntWidget): +class IntText(_Int): + """Textbox widget that represents a int.""" _view_name = Unicode('IntTextView', sync=True) -class BoundedIntTextWidget(_BoundedIntWidget): +class BoundedIntText(_BoundedInt): + """Textbox widget that represents a int bounded by a minimum and maximum value.""" _view_name = Unicode('IntTextView', sync=True) -class IntSliderWidget(_BoundedIntWidget): +class IntSlider(_BoundedInt): + """Slider widget that represents a int bounded by a minimum and maximum value.""" _view_name = Unicode('IntSliderView', sync=True) orientation = Enum([u'horizontal', u'vertical'], u'horizontal', help="Vertical or horizontal.", sync=True) readout = Bool(True, help="Display the current value of the slider next to it.", sync=True) -class IntProgressWidget(_BoundedIntWidget): +class IntProgress(_BoundedInt): + """Progress bar that represents a int bounded by a minimum and maximum value.""" _view_name = Unicode('ProgressView', sync=True) + + +# Remove in IPython 4.0 +IntTextWidget = DeprecatedClass(IntText, 'IntTextWidget') +BoundedIntTextWidget = DeprecatedClass(BoundedIntText, 'BoundedIntTextWidget') +IntSliderWidget = DeprecatedClass(IntSlider, 'IntSliderWidget') +IntProgressWidget = DeprecatedClass(IntProgress, 'IntProgressWidget') diff --git a/IPython/html/widgets/widget_selection.py b/IPython/html/widgets/widget_selection.py index e9706d1..7c4f2f1 100644 --- a/IPython/html/widgets/widget_selection.py +++ b/IPython/html/widgets/widget_selection.py @@ -1,4 +1,4 @@ -"""SelectionWidget classes. +"""Selection classes. Represents an enumeration using a widget. """ @@ -20,11 +20,12 @@ from threading import Lock from .widget import DOMWidget from IPython.utils.traitlets import Unicode, List, Bool, Any, Dict, TraitError from IPython.utils.py3compat import unicode_type +from IPython.utils.warn import DeprecatedClass #----------------------------------------------------------------------------- # SelectionWidget #----------------------------------------------------------------------------- -class _SelectionWidget(DOMWidget): +class _Selection(DOMWidget): """Base class for Selection widgets ``values`` can be specified as a list or dict. If given as a list, @@ -109,17 +110,30 @@ class _SelectionWidget(DOMWidget): self.value_lock.release() -class ToggleButtonsWidget(_SelectionWidget): +class ToggleButtons(_Selection): + """Group of toggle buttons that represent an enumeration. Only one toggle + button can be toggled at any point in time.""" _view_name = Unicode('ToggleButtonsView', sync=True) -class DropdownWidget(_SelectionWidget): +class Dropdown(_Selection): + """Allows you to select a single item from a dropdown.""" _view_name = Unicode('DropdownView', sync=True) -class RadioButtonsWidget(_SelectionWidget): +class RadioButtons(_Selection): + """Group of radio buttons that represent an enumeration. Only one radio + button can be toggled at any point in time.""" _view_name = Unicode('RadioButtonsView', sync=True) -class SelectWidget(_SelectionWidget): +class Select(_Selection): + """Listbox that only allows one item to be selected at any given time.""" _view_name = Unicode('SelectView', sync=True) + + +# Remove in IPython 4.0 +ToggleButtonsWidget = DeprecatedClass(ToggleButtons, 'ToggleButtonsWidget') +DropdownWidget = DeprecatedClass(Dropdown, 'DropdownWidget') +RadioButtonsWidget = DeprecatedClass(RadioButtons, 'RadioButtonsWidget') +SelectWidget = DeprecatedClass(Select, 'SelectWidget') diff --git a/IPython/html/widgets/widget_selectioncontainer.py b/IPython/html/widgets/widget_selectioncontainer.py index ef91559..729090b 100644 --- a/IPython/html/widgets/widget_selectioncontainer.py +++ b/IPython/html/widgets/widget_selectioncontainer.py @@ -1,4 +1,4 @@ -"""SelectionContainerWidget class. +"""SelectionContainer class. Represents a multipage container that can be used to group other widgets into pages. @@ -14,13 +14,15 @@ pages. #----------------------------------------------------------------------------- # Imports #----------------------------------------------------------------------------- -from .widget_container import ContainerWidget +from .widget_box import Box from IPython.utils.traitlets import Unicode, Dict, CInt +from IPython.utils.warn import DeprecatedClass #----------------------------------------------------------------------------- # Classes #----------------------------------------------------------------------------- -class _SelectionContainerWidget(ContainerWidget): +class _SelectionContainer(Box): + """Base class used to display multiple child widgets.""" _titles = Dict(help="Titles of the pages", sync=True) selected_index = CInt(0, sync=True) @@ -50,9 +52,16 @@ class _SelectionContainerWidget(ContainerWidget): return None -class AccordionWidget(_SelectionContainerWidget): +class Accordion(_SelectionContainer): + """Displays children each on a separate accordion page.""" _view_name = Unicode('AccordionView', sync=True) -class TabWidget(_SelectionContainerWidget): +class Tab(_SelectionContainer): + """Displays children each on a separate accordion tab.""" _view_name = Unicode('TabView', sync=True) + + +# Remove in IPython 4.0 +AccordionWidget = DeprecatedClass(Accordion, 'AccordionWidget') +TabWidget = DeprecatedClass(Tab, 'TabWidget') diff --git a/IPython/html/widgets/widget_string.py b/IPython/html/widgets/widget_string.py index 9f6aa30..26b06cc 100644 --- a/IPython/html/widgets/widget_string.py +++ b/IPython/html/widgets/widget_string.py @@ -1,4 +1,4 @@ -"""StringWidget class. +"""String class. Represents a unicode string using a widget. """ @@ -15,37 +15,44 @@ Represents a unicode string using a widget. #----------------------------------------------------------------------------- from .widget import DOMWidget, CallbackDispatcher from IPython.utils.traitlets import Unicode, Bool +from IPython.utils.warn import DeprecatedClass #----------------------------------------------------------------------------- # Classes #----------------------------------------------------------------------------- -class _StringWidget(DOMWidget): +class _String(DOMWidget): + """Base class used to create widgets that represent a string.""" value = Unicode(help="String value", sync=True) disabled = Bool(False, help="Enable or disable user changes", sync=True) description = Unicode(help="Description of the value this widget represents", sync=True) placeholder = Unicode("", help="Placeholder text to display when nothing has been typed", sync=True) -class HTMLWidget(_StringWidget): +class HTML(_String): + """Renders the string `value` as HTML.""" _view_name = Unicode('HTMLView', sync=True) -class LatexWidget(_StringWidget): +class Latex(_String): + """Renders math inside the string `value` as Latex (requires $ $ or $$ $$ + and similar latex tags).""" _view_name = Unicode('LatexView', sync=True) -class TextareaWidget(_StringWidget): +class Textarea(_String): + """Multiline text area widget.""" _view_name = Unicode('TextareaView', sync=True) def scroll_to_bottom(self): self.send({"method": "scroll_to_bottom"}) -class TextWidget(_StringWidget): +class Text(_String): + """Single line textbox widget.""" _view_name = Unicode('TextView', sync=True) def __init__(self, **kwargs): - super(TextWidget, self).__init__(**kwargs) + super(Text, self).__init__(**kwargs) self._submission_callbacks = CallbackDispatcher() self.on_msg(self._handle_string_msg) @@ -71,3 +78,10 @@ class TextWidget(_StringWidget): remove: bool (optional) Whether to unregister the callback""" self._submission_callbacks.register_callback(callback, remove=remove) + + +# Remove in IPython 4.0 +HTMLWidget = DeprecatedClass(HTML, 'HTMLWidget') +LatexWidget = DeprecatedClass(Latex, 'LatexWidget') +TextareaWidget = DeprecatedClass(Textarea, 'TextareaWidget') +TextWidget = DeprecatedClass(Text, 'TextWidget') diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py index 693eeb3..6ad6acc 100644 --- a/IPython/utils/warn.py +++ b/IPython/utils/warn.py @@ -16,6 +16,7 @@ Utilities for warnings. Shoudn't we just use the built in warnings module. from __future__ import print_function import sys +import warnings from IPython.utils import io @@ -65,3 +66,16 @@ def fatal(msg,exit_val=1): warn(msg,exit_val=exit_val,level=4) + +def DeprecatedClass(base, class_name): + # Hook the init method of the base class. + def init_hook(self, *pargs, **kwargs): + base.__init__(self, *pargs, **kwargs) + + # Warn once per class. + if base not in DeprecatedClass._warned_classes: + DeprecatedClass._warned_classes.append(base) + warn('"{}" is deprecated, please use "{}" instead.'.format( + class_name, base.__name__)) + return type(class_name, (base,), {'__init__': init_hook}) +DeprecatedClass._warned_classes = [] diff --git a/docs/source/whatsnew/pr/incompat-deprecated-widget-names.rst b/docs/source/whatsnew/pr/incompat-deprecated-widget-names.rst new file mode 100644 index 0000000..6ccd7aa --- /dev/null +++ b/docs/source/whatsnew/pr/incompat-deprecated-widget-names.rst @@ -0,0 +1,6 @@ +* The widget classes have been renamed from `*Widget` to `*`. The old names are + still functional, but are deprecated. i.e. `IntSliderWidget` has been renamed + to `IntSlider`. +* The ContainerWidget was renamed to Box and no longer defaults as a flexible + box in the web browser. A new FlexBox widget was added, which allows you to + use the flexible box model.