The IPython widgets, now in IHaskell !!

It is highly recommended that users new to jupyter/ipython take the User Interface Tour from the toolbar above (Help -> User Interface Tour).

This notebook introduces the IPython widgets, as implemented in IHaskell. The Button widget is also demonstrated as a live action example.

The Widget Hierarchy

These are all the widgets available from IPython/Jupyter.

Uncategorized Widgets

  • Button
  • ImageWidget
  • OutputWidget

Box Widgets

  • Box
  • FlexBox
  • Accordion
  • TabWidget

Boolean Widgets

  • CheckBox
  • ToggleButton

Integer Widgets

  • IntText
  • BoundedIntText
  • IntProgress
  • IntSlider
  • IntRangeSlider

Float Widgets

  • FloatText
  • BoundedFloatText
  • FloatProgress
  • FloatSlider
  • FloatRangeSlider

Selection Widgets

  • Selection
  • Dropdown
  • RadioButtons
  • Select
  • SelectMultiple
  • ToggleButtons

String Widgets

  • HTMLWidget
  • LatexWidget
  • TextArea
  • TextWidget

Using Widgets

Necessary Extensions and Imports

All the widgets and related functions are available from a single module, IHaskell.Display.Widgets. It is strongly recommended that users use the OverloadedStrings extension, as widgets make extensive use of Text.


In [1]:
{-# LANGUAGE OverloadedStrings #-}
import IHaskell.Display.Widgets

The module can be imported unqualified. Widgets with common names, such as Text, Image etc. have a -Widget suffix to prevent name collisions.

Widget interface

Each widget has different properties, but the surface level API is the same.

Every widget has:

  1. A constructor: An IO <widget> value/function of the form mk<widget_name>.
  2. A set of properties, which can be manipulated using setField and getField.

The setField and getField functions have nasty type signatures, but they can be used by just intuitively understanding them.


In [2]:
:t setField


setField :: forall (w :: WidgetType) (f :: Field). (RElem f (WidgetFields w) (RIndex f (WidgetFields w)), ToPairs (Attr f), IHaskellWidget (IPythonWidget w)) => IPythonWidget w -> SField f -> FieldType f -> IO ()

The setField function takes three arguments:

  1. A widget
  2. A Field
  3. A value for the Field

In [3]:
:t getField


getField :: forall (w :: WidgetType) (f :: Field). RElem f (WidgetFields w) (RIndex f (WidgetFields w)) => IPythonWidget w -> SField f -> IO (FieldType f)

The getField function takes a Widget and a Field and returns the value of that Field for the Widget.

Another utility function is properties, which shows all properties of a widget.


In [4]:
:t properties


properties :: forall (w :: WidgetType). IPythonWidget w -> IO ()

Displaying Widgets

IHaskell automatically displays anything displayable given to it directly.


In [5]:
-- Showables
1 + 2
"abc"


3
"abc"

Widgets can either be displayed this way, or explicitly using the display function from IHaskell.Display.


In [6]:
import IHaskell.Display
:t display


display :: forall a. IHaskellDisplay a => a -> IO Display

Multiple displays

A widget can be displayed multiple times. All these views are representations of a single object, and thus are linked.

When a widget is created, a model representing it is created in the frontend. This model is used by all the views, and any modification to it propagates to all of them.

Closing widgets

Widgets can be closed using the closeWidget function.


In [7]:
:t closeWidget


closeWidget :: forall w. IHaskellWidget w => w -> IO ()

Our first widget: Button

Let's play with buttons as a starting example:

As noted before, all widgets have a constructor of the form mk<Widget>. Thus, to create a Button, we use mkButton.


In [8]:
button <- mkButton     -- Construct a Button
:t button


button :: Button

Widgets can be displayed by just entering them into a cell.


In [9]:
button                 -- Display the button

To view a widget's properties, we use the properties function:


In [10]:
-- The button widget has many properties.
properties button


ViewModule
ViewName
MsgThrottle
Version
DisplayHandler
Visible
CSS
DOMClasses
Width
Height
Padding
Margin
Color
BackgroundColor
BorderColor
BorderWidth
BorderRadius
BorderStyle
FontStyle
FontWeight
FontSize
FontFamily
Description
Tooltip
Disabled
Icon
ButtonStyle
ClickHandler

Let's try making the button widget wider.


In [11]:
-- 250 pixels wide
setField button Width 250



There is a lot that can be customized. For example:


In [12]:
setField button Description "Click Me (._.\")"
setField button ButtonStyle SuccessButton
setField button BorderStyle RidgeBorder
setField button BorderWidth 20
setField button BorderRadius 30
setField button Padding 10
setField button Height 125
setField button FontFamily "cursive"
setField button FontSize 30



The button widget also provides a click handler. We can make it do anything, except console input. Universally, no widget event can trigger console input.


In [13]:
setField button ClickHandler $ putStrLn "fO_o"
button -- Displaying again for convenience



Now try clicking the button, and see the output. If we try to do console input, an error occurs.


In [14]:
setField button ClickHandler $ getLine >>= putStrLn