Simple example notebook that shows how one can use widgets to build custom dialogs.
from IPython.html import widgets
from IPython.display import display
By using Bootstrap's modal class and ContainerWidgets, we can build a simple dialog window.
def scrub_text_html(text):
text = text.replace('&', '&')
text = text.replace(' ', ' ')
text = text.replace('<', '<')
text = text.replace('>', '>')
text = text.replace('\n', '<br>\n')
return text
def create_dialog(title=None, on_hidden=None):
dialog = widgets.ContainerWidget(visible=False)
dialog_header = widgets.ContainerWidget(parent=dialog)
dialog_header_close = widgets.ButtonWidget(parent=dialog_header, description = '×')
dialog_header_label = widgets.StringWidget(parent=dialog_header, default_view_name='HTMLView')
dialog_body = widgets.ContainerWidget(parent=dialog)
dialog_footer = widgets.ContainerWidget(parent=dialog)
if title is None or title == '':
title = ' '
dialog_header_label.value = '<h3>%s</h3>' % scrub_text_html(title)
def handle_close():
dialog.visible = False
if on_hidden is not None:
on_hidden(dialog)
dialog_header_close.on_click(handle_close)
display(dialog)
dialog_header.add_class('modal-header')
dialog_body.add_class('modal-body')
dialog_footer.add_class('modal-footer')
dialog.add_class('modal')
dialog_header_close.remove_class('btn')
dialog_header_close.add_class('close')
return dialog_body, dialog_footer, dialog
Using this show_dialog
method, custom dialogs can be made using widgets. Below is an example of a Yes/No dialog.
# Since Python has a global thread lock, everything runs on a single thread.
# Because of this, we use an asynronous model (callbacks).
def show_yes_no(prompt, yes_callback=None, no_callback=None, title=None):
def handle_hidden(dialog_window):
if no_callback is not None:
no_callback()
dialog_window.close()
(dialog_body, dialog_footer, dialog_window) = create_dialog(title=title, on_hidden=handle_hidden)
def handle_yes():
dialog_window.visible = False
if yes_callback is not None:
yes_callback()
dialog_window.close()
def handle_no():
dialog_window.visible = False
handle_hidden(dialog_window)
yes_button = widgets.ButtonWidget(parent=dialog_footer, description='Yes')
yes_button.on_click(handle_yes)
no_button = widgets.ButtonWidget(parent=dialog_footer, description='No')
no_button.on_click(handle_no)
prompt_label = widgets.StringWidget(parent=dialog_body, value=scrub_text_html(prompt), default_view_name='HTMLView')
display(yes_button)
display(no_button)
display(prompt_label)
yes_button.add_class('btn-success')
no_button.add_class('btn-danger')
dialog_window.visible=True
Test¶
def yes():
show_yes_no("Do you want to show the dialog again?", yes, title="Self displaying dialog")
yes()
Dialog result handlers can contain nested dialogs. The following example shows how syncronous logic can be simulated using closures.
title = "Interactive Story"
def open_door():
show_yes_no("The house is empty. You are tired and decide to sleep. You live to see another day.")
def stay_outside():
def fight():
show_yes_no("You try to fight the wolves but die in the process.", title=title)
def panic():
def flight():
show_yes_no("You run as fast as you can. You manage to escape the\n" + \
"wolves but the cold is beginning to get to you. You\n" + \
"sit in the snow to take a nap. You freeze and die.", title=title)
show_yes_no("You panic. Do you enter the cabin now?", open_door, flight, title=title)
show_yes_no("A pack of wolves approach. Do you want to fight them?", fight, panic, title=title)
show_yes_no("You are standing outside in a blizzard on a cold winter night.\n" + \
"A warm cabin with the lights on is in front of you.\n\n" + \
"Do you want to enter the cabin?", open_door, stay_outside, title=title)