{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": false, "input": [ "from IPython.html import widgets\n", "from IPython.display import display" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook shows how widgets can be used to manipulate the properties of other widgets." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To list the properties of a widget and allow the user to modify them, a function that keeps widgets in sync with traits is required. This function will syncronize a traitlet of one widget with a traitlet of another widget. The method also supports one way syncronization of types that have string representations with string traits." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def sync_widgets_properties(widget_a, property_a, widget_b, property_b, str_rep=False):\n", " def set_property_a(name, old, new):\n", " if old != new:\n", " if str_rep:\n", " setattr(widget_a, property_a, str(new))\n", " else:\n", " setattr(widget_a, property_a, new)\n", " def set_property_b(name, old, new):\n", " if old != new and not str_rep:\n", " setattr(widget_b, property_b, new)\n", " widget_a.on_trait_change(set_property_b, property_a)\n", " widget_b.on_trait_change(set_property_a, property_b)\n", " if str_rep:\n", " setattr(widget_a, property_a, str(getattr(widget_b, property_b)))\n", " else:\n", " setattr(widget_a, property_a, getattr(widget_b, property_b))\n", " \n", " return widget_a" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This function will create a best match widget to represent a traitlet of another widget. The function will then bind the two widgets using the `sync_widget_properties` method above." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def create_hooked_widget(control, key):\n", " property_type = type(getattr(control, key))\n", " \n", " if key == \"orientation\":\n", " return sync_widgets_properties(widgets.SelectionWidget(values=['vertical', 'horizontal'], default_view_name='ToggleButtonsView'), 'value', control, key)\n", " elif property_type is int:\n", " return sync_widgets_properties(widgets.IntWidget(), 'value', control, key)\n", " elif property_type is float:\n", " return sync_widgets_properties(widgets.FloatWidget(), 'value', control, key)\n", " elif property_type is bool:\n", " return sync_widgets_properties(widgets.BoolWidget(), 'value', control, key)\n", " elif property_type is str or property_type is unicode:\n", " return sync_widgets_properties(widgets.StringWidget(), 'value', control, key)\n", " else:\n", " return sync_widgets_properties(widgets.StringWidget(disabled=True), 'value', control, key, str_rep=True)\n", " " ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This function creates a modal that allows the user to read the doc string associated with a callable. The user can then invoke the callbable from the same modal." ] }, { "cell_type": "code", "collapsed": false, "input": [ "modals = {}\n", "def get_method_modal(control, method_name, parent=None):\n", " if not method_name in dir(control):\n", " return None\n", " if not control in modals:\n", " modals[control] = {}\n", " if not method_name in modals[control]:\n", " new_modal = widgets.ContainerWidget(default_view_name=\"ModalView\")\n", " new_modal.description=\"Invoke \" + method_name\n", " new_modal.button_text = method_name + \"(...)\"\n", " \n", " doc_str = 'No doc string'\n", " try:\n", " doc_str = '
' + getattr(control, method_name).__doc__ + ''\n", " except:\n", " pass\n", " \n", " doc_label = widgets.StringWidget(parent=new_modal,default_view_name='HTMLView', value=doc_str)\n", " doc_label.set_css('color', 'blue')\n", " exec_box = widgets.ContainerWidget(parent=new_modal)\n", " exec_box.hbox()\n", " exec_box.pack_center()\n", " exec_box.align_center()\n", " open_label = widgets.StringWidget(parent=exec_box,default_view_name='HTMLView', value=method_name+'( ')\n", " exec_str = widgets.StringWidget(parent=exec_box)\n", " close_label = widgets.StringWidget(parent=exec_box,default_view_name='HTMLView', value=' )')\n", " button_row = widgets.ContainerWidget(parent=new_modal)\n", " button_row.hbox()\n", " button_row.pack_end()\n", " button_box = widgets.ContainerWidget(parent=button_row)\n", " button_box.flex0()\n", " exec_button = widgets.ButtonWidget(parent=button_box, description=\"Execute\")\n", " \n", " def handle_method_exec():\n", " my_control = control\n", " exec \"my_control.\" + method_name.replace('\\n', '') + \"(\" + exec_str.value + \")\" in globals(), locals()\n", " exec_button.on_click(handle_method_exec)\n", " exec_str.on_submit(handle_method_exec)\n", " \n", " if parent is not None:\n", " new_modal.parent = parent\n", " \n", " modals[control][method_name] = new_modal\n", " display(new_modal)\n", " return modals[control][method_name]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This function renders the control panel." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def hook_control(control, parent=None):\n", " explorer = widgets.ContainerWidget()\n", " if parent is not None:\n", " explorer.parent = parent\n", " explorer.hbox()\n", " \n", " viewer = widgets.ContainerWidget(parent=explorer)\n", " viewer.set_css({\n", " 'background': 'white',\n", " 'border': '1px solid #000',\n", " 'overflow': 'hidden',\n", " })\n", " viewer.flex2()\n", " \n", " control.parent = viewer\n", " \n", " side = widgets.ContainerWidget(parent=explorer)\n", " side.flex1()\n", " \n", " side_tab = widgets.MulticontainerWidget(parent=side)\n", " side_tab.set_css('margin', '5px')\n", " \n", " properties = widgets.ContainerWidget(parent=side_tab)\n", " methods = widgets.ContainerWidget(parent=side_tab)\n", " side_tab.set_title(0, 'Properties')\n", " side_tab.set_title(1, 'Methods')\n", " \n", " for key in sorted(control.keys):\n", " property_control = create_hooked_widget(control, key)\n", " property_control.parent = properties\n", " property_control.description = key + ':'\n", " \n", " methods.vbox()\n", " methods.set_css('overflow', 'hidden')\n", " \n", " methods_container = widgets.ContainerWidget(parent=methods)\n", " methods_container.flex1()\n", " methods_buttons = widgets.ContainerWidget(parent=methods)\n", " methods_buttons.flex0()\n", " methods_buttons.hbox()\n", " methods_buttons.pack_end()\n", " methods_buttons.set_css({\n", " 'padding-top': '5px',\n", " 'padding-right': '50px',\n", " })\n", " \n", " execute_button = widgets.ButtonWidget(parent=methods_buttons, description=\"Invoke\")\n", " \n", " method_list = widgets.SelectionWidget(parent=methods_container, default_view_name=\"ListBoxView\")\n", " method_list.description = \"Names:\"\n", " method_list.set_css('height', '400px')\n", " method_list.values = [attr_name for attr_name in dir(control) if callable(getattr(control, attr_name)) and not attr_name.startswith('_')]\n", " \n", " def handle_execute_method():\n", " get_method_modal(control, method_list.value, parent=parent)\n", " execute_button.on_click(handle_execute_method)\n", " \n", " display(explorer) \n", " explorer.add_class('well')\n", " return explorer" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This final bit of code allows the user to select what control and view he/she wants to manipulate." ] }, { "cell_type": "code", "collapsed": false, "input": [ "control_tester = widgets.ContainerWidget()\n", "widget_names = [widget_name for widget_name in dir(widgets) if widget_name.endswith('Widget') and widget_name != \"Widget\"]\n", "widget_selector = widgets.SelectionWidget(parent=control_tester, description=\"Widget type:\", values=widget_names)\n", "view_name = widgets.StringWidget(parent=control_tester, description=\"View name (optional):\")\n", "display_button_container = widgets.ContainerWidget(parent=control_tester)\n", "display_button_container.hbox()\n", "display_button_container.pack_end()\n", "display_button_container.set_css(\"padding\", \"5px\")\n", "display_button = widgets.ButtonWidget(parent=display_button_container, description=\"Display\")\n", "display(control_tester)\n", "\n", "last_displayed = [None]\n", "def handle_display():\n", " if last_displayed[0] is not None:\n", " last_displayed[0].close()\n", " widget_type = getattr(widgets, widget_selector.value)\n", " widget = widget_type()\n", " if len(view_name.value) > 0:\n", " widget.default_view_name = view_name.value\n", " last_displayed[0] = hook_control(widget)\n", "display_button.on_click(handle_display)\n", "view_name.on_submit(handle_display)\n" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 } ], "metadata": {} } ] }