These widgets can be used to represent a Boolean value. The idea is pretty simple, the widget can be in one of two states which represent the two boolean values.
Checked / On : True
Unchecked / Off : False
In [1]:
    
{-# LANGUAGE OverloadedStrings #-}
import IHaskell.Display.Widgets
import Data.Text (pack, unpack)
import Text.Printf (printf)
    
In [2]:
    
-- Constructors
chk <- mkCheckBox
tgb <- mkToggleButton
-- For demonstration
o <- mkHTMLWidget
    
Below, we represent one boolean using a checkbox, and the other using a toggle button. The logical and (&&) of the two is displayed below.
In [3]:
    
-- Display
chk
tgb
o
    
The BoolValue field represents the underlying boolean value.
In [4]:
    
setField chk Description "Bool 1: "
setField tgb Description "Bool 2"
-- Helper function
refresh b =
  let stat = if b then "green" else "red"
      fmt = "<div style=\"background:%s;color:#ffffff\"><b>%s</b></div>"
  in setField o StringValue $ pack $ printf fmt stat (show b)
 -- Cosmetic changes
setField o Description "Bool 1 && Bool 2"
setField o Padding 10
 -- And (&&) the two values, and send output to html widget
setHandler w = setField w ChangeHandler $ do
  b1 <- getField chk BoolValue
  b2 <- getField tgb BoolValue
  refresh (b1 && b2)
setHandler chk
setHandler tgb
    
    
Let's try to create a graphical 8-bit-binary to decimal converter. We'll represent seven bits using ToggleButton widgets, and the negative bit using a CheckBox. The binary number is represented using 1+7-bit sign-and-magnitude representation for simplicity.
Boxes are used to layout the widgets in an appealing manner, and the output widget is used to display the result.
In [5]:
    
-- First, some library functions
import Control.Monad (replicateM, forM_)
import Data.IORef
import IHaskell.Display (plain)
    
Now, we create a CheckBox and seven ToggleButtons.
In [6]:
    
sign <- mkCheckBox
bits <- replicateM 7 mkToggleButton
setField sign Description "Negative"
forM_ bits $ \t -> do
  setField t ButtonStyle PrimaryButton
  setField t BorderRadius 20
    
    
Then we create a FlexBox to hold the widgets, and an HTMLWidget to display the output.
In [7]:
    
box <- mkFlexBox
out <- mkHTMLWidget
-- Sub-containers
box1 <- mkFlexBox
setField box1 Children [ChildWidget sign, ChildWidget out]
box2 <- mkFlexBox
setField box2 Children (map ChildWidget $ reverse bits)
-- Add widgets to the container
setField box Children (map ChildWidget [box1, box2])
setField box Orientation VerticalOrientation
-- Add some UI chrome
setField box BoxStyle InfoBox
setField box BorderRadius 20
setField out BorderStyle GrooveBorder
setField out BorderRadius 20
setField out BorderWidth 4
setField out Width 100
setField out Height 30
setField out Margin 10
setField sign Padding 10
setField box2 Padding 10
setField box2 Pack BaselineLocation
-- Display the container
box
    
    
Now, we implement the logic of our converter, and make it send the output to the HTMLWidget we created above.
In [8]:
    
import Control.Arrow (first, second)
-- Mutable value, with a sign bit
val <- newIORef (0 :: Int, False)
-- Helper function to redraw output
refresh :: (Int, Bool) -> IO ()
refresh (x, b) = 
  let val = x * if b then (-1) else 1
      fmt = "<div align=\"center\"><b>%d</b></div>"
  in setField out StringValue (pack $ printf fmt val)
setField sign ChangeHandler $ do
  -- Change sign for value
  modifyIORef val (second not)
  -- Redraw output
  readIORef val >>= refresh
forM_ (zip bits (iterate (*2) 1)) $ \(t, n) -> do
  setField t Description "0"
  setField t ChangeHandler $ do
    f <- getField t BoolValue
    setField t Description (if f then "1" else "0")
    modifyIORef val (first $ if f then (+n) else (\x->x-n))
    readIORef val >>= refresh