Commit 8b58b36e authored by Andrew Gibiansky's avatar Andrew Gibiansky

Merge branch 'master' of github.com:gibiansky/IHaskell

parents b19792bc 0a181a17
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
![IHaskell](https://raw.github.com/gibiansky/IHaskell/master/html/logo-64x64.png) ![IHaskell](https://raw.github.com/gibiansky/IHaskell/master/html/logo-64x64.png)
# IHaskell # IHaskell
> You can now try IHaskell directly in your browser at [try.jupyter.org](https://try.jupyter.org).
IHaskell is a kernel for the [Jupyter project](http://ipython.org), which allows you to use Haskell inside Jupyter frontends (including the console and notebook). IHaskell is a kernel for the [Jupyter project](http://ipython.org), which allows you to use Haskell inside Jupyter frontends (including the console and notebook).
For a tour of some IHaskell features, check out the [demo Notebook](http://nbviewer.ipython.org/github/gibiansky/IHaskell/blob/master/notebooks/IHaskell.ipynb). More example notebooks are available on the [wiki](https://github.com/gibiansky/IHaskell/wiki). For a tour of some IHaskell features, check out the [demo Notebook](http://nbviewer.ipython.org/github/gibiansky/IHaskell/blob/master/notebooks/IHaskell.ipynb). More example notebooks are available on the [wiki](https://github.com/gibiansky/IHaskell/wiki).
......
...@@ -48,7 +48,7 @@ if [ $# -gt 0 ]; then ...@@ -48,7 +48,7 @@ if [ $# -gt 0 ]; then
if [ $1 = "display" ] || [ $1 = "all" ]; then if [ $1 = "display" ] || [ $1 = "all" ]; then
# Install all the display libraries # Install all the display libraries
cd ihaskell-display cd ihaskell-display
for dir in `ls` for dir in `ls | grep -v ihaskell-widgets`
do do
INSTALLS="$INSTALLS ihaskell-display/$dir" INSTALLS="$INSTALLS ihaskell-display/$dir"
done done
...@@ -71,6 +71,10 @@ INSTALL_DIRS=`echo $INSTALLS | tr ' ' '\n' | sed 's#^#./#' | tr ' ' '\n'` ...@@ -71,6 +71,10 @@ INSTALL_DIRS=`echo $INSTALLS | tr ' ' '\n' | sed 's#^#./#' | tr ' ' '\n'`
echo CMD: cabal install --constraint "arithmoi -llvm" -j $INSTALL_DIRS --force-reinstalls --max-backjumps=-1 --reorder-goals echo CMD: cabal install --constraint "arithmoi -llvm" -j $INSTALL_DIRS --force-reinstalls --max-backjumps=-1 --reorder-goals
cabal install --constraint "arithmoi -llvm" -j $INSTALL_DIRS --force-reinstalls --max-backjumps=-1 --reorder-goals cabal install --constraint "arithmoi -llvm" -j $INSTALL_DIRS --force-reinstalls --max-backjumps=-1 --reorder-goals
if [ $1 = "display" ] || [ $1 = "all" ]; then
cabal install ihaskell-display/ihaskell-widgets
fi
if hash ihaskell 2>/dev/null; then if hash ihaskell 2>/dev/null; then
ihaskell install 2>/dev/null || echo "The command \"ihaskell install\" failed. Please check your 'ipython --version'. 3.0 or up is required but it is $(ipython --version)!" ihaskell install 2>/dev/null || echo "The command \"ihaskell install\" failed. Please check your 'ipython --version'. 3.0 or up is required but it is $(ipython --version)!"
else else
......
...@@ -37,7 +37,7 @@ chartData renderable format = do ...@@ -37,7 +37,7 @@ chartData renderable format = do
mkFile opts filename renderable mkFile opts filename renderable
-- Convert to base64. -- Convert to base64.
imgData <- fmap Char.pack $ readFile filename imgData <- Char.readFile filename
return $ return $
case format of case format of
PNG -> png width height $ base64 imgData PNG -> png width height $ base64 imgData
......
...@@ -60,8 +60,8 @@ displayImageAsJpg renderable = do ...@@ -60,8 +60,8 @@ displayImageAsJpg renderable = do
-- Write the image -- Write the image
saveJpgImage 95 filename renderable saveJpgImage 95 filename renderable
-- Convert to base64. -- Convert to base64.
imgData <- readFile filename imgData <- CBS.readFile filename
return $ Display [jpg (imWidth renderable) (imHeight renderable) $ base64 (CBS.pack imgData)] return $ Display [jpg (imWidth renderable) (imHeight renderable) $ base64 imgData]
-- The type DynamicImage does not have a function to extract width and height -- The type DynamicImage does not have a function to extract width and height
imWidth :: DynamicImage -> Int imWidth :: DynamicImage -> Int
......
...@@ -28,7 +28,7 @@ figureData figure format = do ...@@ -28,7 +28,7 @@ figureData figure format = do
writeFigure format fname (w, h) figure writeFigure format fname (w, h) figure
-- Read back, and convert to base64. -- Read back, and convert to base64.
imgData <- Char.pack <$> readFile fname imgData <- Char.readFile fname
let value = let value =
case format of case format of
PNG -> png w h $ base64 imgData PNG -> png w h $ base64 imgData
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The Numeric Widgets\n",
"\n",
"#### `Int` Widgets\n",
"\n",
"+ IntText\n",
"+ BoundedIntText\n",
"+ IntProgress\n",
"+ IntSlider\n",
"+ IntRangeSlider\n",
"\n",
"#### `Float` Widgets\n",
"\n",
"+ FloatText\n",
"+ BoundedFloatText\n",
"+ FloatProgress\n",
"+ FloatSlider\n",
"+ FloatRangeSlider\n",
"\n",
"**NOTE**: Only the `Int` widgets are shown in this notebook. The `Float` widgets are the same as their `Int` counterparts, but hold `Float`s instead of `Int`s."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `IntText` and `BoundedIntText`"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"int <- mkIntText\n",
"int"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"bit <- mkBoundedIntText\n",
"bit"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Both the widgets are similar, but the second one possesses some additional properties."
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"setField bit SMaxInt 20\n",
"setField bit SMinInt 10\n",
"setField bit SChangeHandler (getField bit SIntValue >>= print)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, the first widget will accept arbitrary input whereas the second one wil accept input the the 10-20 range. For example, try entering large values and hitting return/enter in the second widget."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `IntSlider` and `IntRangeSlider`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Both these widgets are sliders (duh!). `IntSlider` represents a single value, whereas `IntRangeSlider` represents a pair (range) of values."
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"ins <- mkIntSlider\n",
"irs <- mkIntRangeSlider"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"ins\n",
"irs"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(25,75)"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"getField irs SIntPairValue"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `IntProgress`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This widget is meant to be used as a progress bar."
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"inp <- mkIntProgress\n",
"inp"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"setField inp SIntValue 42"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Haskell",
"language": "haskell",
"name": "haskell"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
This diff is collapsed.
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The `Selection` Widgets\n",
"\n",
"+ Dropdown\n",
"+ RadioButtons\n",
"+ ToggleButtons\n",
"+ Select\n",
"+ SelectMultiple"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"These widgets can be used to choose between multiple alternatives. The `SelectMultiple` widget allows multiple selections, whereas `Dropdown`, `RadioButtons`, `ToggleButtons`, and `Select` only allow one selection."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"{-# LANGUAGE OverloadedStrings #-}\n",
"import IHaskell.Display.Widgets"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"-- Allows single selection\n",
"tgbs <- mkToggleButtons\n",
"\n",
"-- Allows multiple selections\n",
"msel <- mkSelectMultiple"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"setField msel SDescription \"Functions to show (One or more)\"\n",
"setField msel SOptions (OptionLabels [\"sin\", \"cos\"])\n",
"\n",
"setField tgbs SDescription \"Plot style\"\n",
"setField tgbs SOptions (OptionLabels [\"line\", \"point\"])"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import Graphics.Rendering.Chart.Easy hiding (tan)\n",
"import Graphics.Rendering.Chart.Backend.Cairo\n",
"import qualified Data.ByteString as B\n",
"import Data.Text (pack, unpack)\n",
"import IHaskell.Display (base64)\n",
"import Control.Applicative ((<$>))\n",
"\n",
"import Control.Monad (when, forM)\n",
"import Data.Maybe (fromJust)\n",
"\n",
"dset :: [(String, [(Double, Double)])]\n",
"dset = [(\"sin\", zmap sin r), (\"cos\", zmap cos r)]\n",
" where zmap f xs = zip xs (map f xs)\n",
" r = [0, 0.1 .. 6.3]\n",
"\n",
"i <- mkImageWidget\n",
"setField i SWidth 500\n",
"setField i SHeight 500\n",
"\n",
"-- Redraw the plot based on values from the widgets\n",
"refresh = do\n",
" -- Read values from the widgets\n",
" funs <- map unpack <$> getField msel SSelectedValues\n",
" sty <- unpack <$> getField tgbs SSelectedValue\n",
" \n",
" let pts = zip funs (map (fromJust . flip lookup dset) funs)\n",
" opts = def { _fo_size = (500, 500) }\n",
" toFile opts \".chart\" $ do\n",
" layout_title .= \"Plotting: \" ++ unwords funs\n",
" if sty == \"line\"\n",
" then mapM_ (\\(s, ps) -> plot (line s [ps])) pts\n",
" else mapM_ (\\(s, ps) -> plot (points s ps)) pts\n",
"\n",
" img <- B.readFile \".chart\"\n",
" setField i SB64Value (base64 img)\n",
" \n",
"-- Add event handlers to make widgets work\n",
"setField msel SSelectionHandler refresh\n",
"setField tgbs SSelectionHandler refresh"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- Display the widgets\n",
"msel\n",
"tgbs\n",
"i"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `Dropdown`, `RadioButtons` and `Select` widgets behave just like the `ToggleButtons` widget. They have the same properties, and the same functionality."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Haskell",
"language": "haskell",
"name": "haskell"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
# IPython widget messaging specification
> Largely based on: https://github.com/ipython/ipython/wiki/IPEP-23:-Backbone.js-Widgets
> The messaging specification as detailed is riddled with assumptions IHaskell's widget
> implementation makes. It works for us, so it should work for everyone.
## Creating widgets
Let's say the user types in some code, and the only effect of that code is the creation of a widget.
The kernel will open a comm for the widget, and store a reference to that comm inside it. Then, to
notify the frontend about the creation of a widget, an initial state update is sent on the widget's
comm.
> The comm should be opened with a `target_name` of `"ipython.widget"`.
The initial state update message looks like this:
```json
{
"method": "update",
"state": { "<some/all widget properties>" }
}
```
Any *numeric* property initialized with the empty string is provided the default value by the
frontend. Some numbers need to be sent as actual numbers (when non-null), whereas some (especially
those used by sliders) need to be sent as strings.
The initial state update must *at least* have the following fields:
- `msg_throttle` (default 3): To prevent the kernel from flooding with messages, the messages from
the widget to the kernel are throttled. If `msg_throttle` messages were sent, and all are still
processing, the widget will not send anymore state messages.
- `_view_name` (depends on the widget): The frontend uses a generic model to represent
widgets. This field determines how a set of widget properties gets rendered into a
widget. Has the form `IPython.<widgetname>`, e.g `IPython.Button`.
- `_css` (default value = empty list): A list of 3-tuples, (selector, key, value).
- `visible` (default = True): Whether the widget is visible or not.
- Rest of the properties as required initially.
This state update is also used with fragments of the overall state to sync changes between the
frontend and the kernel.
## Displaying widgets
The creation of a widget does not display it. To display a widget, the kernel sends a display
message to the frontend on the widget's comm.
```json
{
"method": "display"
}
```
## Custom messages
* Widgets can also send a custom message, having the form:
```json
{
"method": "custom",
"content": { "<message content>" }
}
```
This message is used by widgets for ad-hoc syncronization, event handling and other stuff. An example
is mentioned in the next section.
## Handling changes to widget in the frontend
Changes to widgets in the frontend lead to messages being sent to the backend. These messages have
two possible formats:
1. Backbone.js initiated sync:
```json
{
"method": "backbone",
"sync_data": { "<changes to sync with the backend>" }
}
```
These messages are sent by the Backbone.js library when some change is made to a widget. For
example, whenever a change is made to the text inside a `TextWidget`, the complete contents are sent
to the kernel so that the kernel stays up-to-date about the widget's contents.
2. Custom message:
```json
{
"method": "custom",
"content": { "<custom message data>" }
}
```
This form is generally used to notify the kernel about events. For example, the `TextWidget` sends a
custom message when the text is submitted by hitting the 'Enter' key.
---
*NOTE*: It's important that the messages sent on the comm are in response to an execution message
from the front-end or another widget's comm message. This is required so the widget framework knows
what cell triggered the message and can display the widget in the correct location.
---
# IHaskell-Widgets
This package implements the [ipython widgets](https://github.com/ipython/ipywidgets) in
IHaskell. The frontend (javascript) is provided by the jupyter/ipython notebook environment, whereas
the backend is implemented in haskell.
To know more about the widget messaging protocol, see [MsgSpec.md](MsgSpec.md).
...@@ -44,7 +44,7 @@ build-type: Simple ...@@ -44,7 +44,7 @@ build-type: Simple
-- Extra files to be distributed with the package, such as examples or a -- Extra files to be distributed with the package, such as examples or a
-- README. -- README.
-- extra-source-files: extra-source-files: README.md, MsgSpec.md
-- Constraint on the version of Cabal needed to build this package. -- Constraint on the version of Cabal needed to build this package.
cabal-version: >=1.10 cabal-version: >=1.10
...@@ -55,22 +55,52 @@ library ...@@ -55,22 +55,52 @@ library
-- Modules included in this library but not exported. -- Modules included in this library but not exported.
other-modules: IHaskell.Display.Widgets.Button other-modules: IHaskell.Display.Widgets.Button
IHaskell.Display.Widgets.Box.Box
IHaskell.Display.Widgets.Box.FlexBox
IHaskell.Display.Widgets.Box.SelectionContainer.Accordion
IHaskell.Display.Widgets.Box.SelectionContainer.Tab
IHaskell.Display.Widgets.Bool.CheckBox
IHaskell.Display.Widgets.Bool.ToggleButton
IHaskell.Display.Widgets.Int.IntText
IHaskell.Display.Widgets.Int.BoundedInt.BoundedIntText
IHaskell.Display.Widgets.Int.BoundedInt.IntProgress
IHaskell.Display.Widgets.Int.BoundedInt.IntSlider
IHaskell.Display.Widgets.Int.BoundedIntRange.IntRangeSlider
IHaskell.Display.Widgets.Float.FloatText
IHaskell.Display.Widgets.Float.BoundedFloat.BoundedFloatText
IHaskell.Display.Widgets.Float.BoundedFloat.FloatProgress
IHaskell.Display.Widgets.Float.BoundedFloat.FloatSlider
IHaskell.Display.Widgets.Float.BoundedFloatRange.FloatRangeSlider
IHaskell.Display.Widgets.Image IHaskell.Display.Widgets.Image
IHaskell.Display.Widgets.Output
IHaskell.Display.Widgets.Selection.Dropdown
IHaskell.Display.Widgets.Selection.RadioButtons
IHaskell.Display.Widgets.Selection.Select
IHaskell.Display.Widgets.Selection.ToggleButtons
IHaskell.Display.Widgets.Selection.SelectMultiple
IHaskell.Display.Widgets.String.HTML IHaskell.Display.Widgets.String.HTML
IHaskell.Display.Widgets.String.Latex IHaskell.Display.Widgets.String.Latex
IHaskell.Display.Widgets.String.Text IHaskell.Display.Widgets.String.Text
IHaskell.Display.Widgets.String.TextArea IHaskell.Display.Widgets.String.TextArea
IHaskell.Display.Widgets.Types
IHaskell.Display.Widgets.Common IHaskell.Display.Widgets.Common
-- LANGUAGE extensions used by modules in this package. -- LANGUAGE extensions used by modules in this package.
-- other-extensions: -- other-extensions:
-- Other library packages from which modules are imported. -- Other library packages from which modules are imported.
build-depends: aeson >= 0.8.1.0 build-depends: aeson >=0.7 && < 0.9
, base >=4.7 && <4.9 , base >=4.7 && <4.9
, ipython-kernel >= 0.6.1.0 , containers >= 0.5
, text >= 1.2.1.0 , ipython-kernel >= 0.6.1
, unordered-containers >= 0.2.5.1 , text >= 0.11
, unordered-containers -any
, nats -any
, vinyl >= 0.5
, vector -any
, singletons >= 0.9.0
, scientific -any
-- Waiting for the next release -- Waiting for the next release
, ihaskell -any , ihaskell -any
...@@ -81,3 +111,10 @@ library ...@@ -81,3 +111,10 @@ library
-- Base language which the package is written in. -- Base language which the package is written in.
default-language: Haskell2010 default-language: Haskell2010
-- Deal with small -fcontext-stack on ghc-7.8.
-- Default values:
-- ghc-7.6.* = 200
-- ghc-7.8.* = 20 -- Too small for vinyl & singletons
-- ghc-7.10.* = 100
if impl(ghc == 7.8.*)
ghc-options: -fcontext-stack=100
...@@ -2,11 +2,44 @@ module IHaskell.Display.Widgets (module X) where ...@@ -2,11 +2,44 @@ module IHaskell.Display.Widgets (module X) where
import IHaskell.Display.Widgets.Button as X import IHaskell.Display.Widgets.Button as X
import IHaskell.Display.Widgets.Box.Box as X
import IHaskell.Display.Widgets.Box.FlexBox as X
import IHaskell.Display.Widgets.Box.SelectionContainer.Accordion as X
import IHaskell.Display.Widgets.Box.SelectionContainer.Tab as X
import IHaskell.Display.Widgets.Bool.CheckBox as X
import IHaskell.Display.Widgets.Bool.ToggleButton as X
import IHaskell.Display.Widgets.Int.IntText as X
import IHaskell.Display.Widgets.Int.BoundedInt.BoundedIntText as X
import IHaskell.Display.Widgets.Int.BoundedInt.IntProgress as X
import IHaskell.Display.Widgets.Int.BoundedInt.IntSlider as X
import IHaskell.Display.Widgets.Int.BoundedIntRange.IntRangeSlider as X
import IHaskell.Display.Widgets.Float.FloatText as X
import IHaskell.Display.Widgets.Float.BoundedFloat.BoundedFloatText as X
import IHaskell.Display.Widgets.Float.BoundedFloat.FloatProgress as X
import IHaskell.Display.Widgets.Float.BoundedFloat.FloatSlider as X
import IHaskell.Display.Widgets.Float.BoundedFloatRange.FloatRangeSlider as X
import IHaskell.Display.Widgets.Image as X import IHaskell.Display.Widgets.Image as X
import IHaskell.Display.Widgets.Output as X
import IHaskell.Display.Widgets.Selection.Dropdown as X
import IHaskell.Display.Widgets.Selection.RadioButtons as X
import IHaskell.Display.Widgets.Selection.Select as X
import IHaskell.Display.Widgets.Selection.ToggleButtons as X
import IHaskell.Display.Widgets.Selection.SelectMultiple as X
import IHaskell.Display.Widgets.String.HTML as X import IHaskell.Display.Widgets.String.HTML as X
import IHaskell.Display.Widgets.String.Latex as X import IHaskell.Display.Widgets.String.Latex as X
import IHaskell.Display.Widgets.String.Text as X import IHaskell.Display.Widgets.String.Text as X
import IHaskell.Display.Widgets.String.TextArea as X import IHaskell.Display.Widgets.String.TextArea as X
import IHaskell.Display.Widgets.Common as X (ButtonStyle(..), ImageFormat(..)) import IHaskell.Display.Widgets.Common as X
import IHaskell.Display.Widgets.Types as X (setField, getField, properties)
import IHaskell.Display.Widgets.Types as X (triggerDisplay, triggerChange, triggerClick,
triggerSelection, triggerSubmit,
ChildWidget(..))
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeSynonymInstances #-}
module IHaskell.Display.Widgets.Bool.CheckBox (
-- * The CheckBox Widget
CheckBox,
-- * Constructor
mkCheckBox) where
-- To keep `cabal repl` happy when running from the ihaskell repo
import Prelude
import Control.Monad (when, join, void)
import Data.Aeson
import Data.HashMap.Strict as HM
import Data.IORef (newIORef)
import Data.Text (Text)
import Data.Vinyl (Rec(..), (<+>))
import IHaskell.Display
import IHaskell.Eval.Widgets
import IHaskell.IPython.Message.UUID as U
import IHaskell.Display.Widgets.Types
import IHaskell.Display.Widgets.Common
-- | A 'CheckBox' represents a Checkbox widget from IPython.html.widgets.
type CheckBox = IPythonWidget CheckBoxType
-- | Create a new output widget
mkCheckBox :: IO CheckBox
mkCheckBox = do
-- Default properties, with a random uuid
uuid <- U.random
let widgetState = WidgetState $ defaultBoolWidget "CheckboxView"
stateIO <- newIORef widgetState
let widget = IPythonWidget uuid stateIO
initData = object
["model_name" .= str "WidgetModel", "widget_class" .= str "IPython.Checkbox"]
-- Open a comm for this widget, and store it in the kernel state
widgetSendOpen widget initData $ toJSON widgetState
-- Return the image widget
return widget
instance IHaskellDisplay CheckBox where
display b = do
widgetSendView b
return $ Display []
instance IHaskellWidget CheckBox where
getCommUUID = uuid
comm widget (Object dict1) _ = do
let key1 = "sync_data" :: Text
key2 = "value" :: Text
Just (Object dict2) = HM.lookup key1 dict1
Just (Bool value) = HM.lookup key2 dict2
setField' widget SBoolValue value
triggerChange widget
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeSynonymInstances #-}
module IHaskell.Display.Widgets.Bool.ToggleButton (
-- * The ToggleButton Widget
ToggleButton,
-- * Constructor
mkToggleButton) where
-- To keep `cabal repl` happy when running from the ihaskell repo
import Prelude
import Control.Monad (when, join, void)
import Data.Aeson
import Data.HashMap.Strict as HM
import Data.IORef (newIORef)
import Data.Text (Text)
import Data.Vinyl (Rec(..), (<+>))
import IHaskell.Display
import IHaskell.Eval.Widgets
import IHaskell.IPython.Message.UUID as U
import IHaskell.Display.Widgets.Types
import IHaskell.Display.Widgets.Common
-- | A 'ToggleButton' represents a ToggleButton widget from IPython.html.widgets.
type ToggleButton = IPythonWidget ToggleButtonType
-- | Create a new output widget
mkToggleButton :: IO ToggleButton
mkToggleButton = do
-- Default properties, with a random uuid
uuid <- U.random
let boolState = defaultBoolWidget "ToggleButtonView"
toggleState = (STooltip =:: "")
:& (SIcon =:: "")
:& (SButtonStyle =:: DefaultButton)
:& RNil
widgetState = WidgetState (boolState <+> toggleState)
stateIO <- newIORef widgetState
let widget = IPythonWidget uuid stateIO
initData = object
["model_name" .= str "WidgetModel", "widget_class" .= str "IPython.ToggleButton"]
-- Open a comm for this widget, and store it in the kernel state
widgetSendOpen widget initData $ toJSON widgetState
-- Return the image widget
return widget
instance IHaskellDisplay ToggleButton where
display b = do
widgetSendView b
return $ Display []
instance IHaskellWidget ToggleButton where
getCommUUID = uuid
comm widget (Object dict1) _ = do
let key1 = "sync_data" :: Text
key2 = "value" :: Text
Just (Object dict2) = HM.lookup key1 dict1
Just (Bool value) = HM.lookup key2 dict2
setField' widget SBoolValue value
triggerChange widget
...@@ -213,7 +213,7 @@ mkConfig var = KernelConfig ...@@ -213,7 +213,7 @@ mkConfig var = KernelConfig
, displayResult = displayRes , displayResult = displayRes
, displayOutput = displayOut , displayOutput = displayOut
, completion = langCompletion , completion = langCompletion
, objectInfo = langInfo , inspectInfo = langInfo
, run = parseAndRun , run = parseAndRun
, debug = False , debug = False
} }
......
-- | Description : UUID generator and data structure -- | Description : UUID generator and data structure
-- --
-- Generate, parse, and pretty print UUIDs for use with IPython. -- Generate, parse, and pretty print UUIDs for use with IPython.
module IHaskell.IPython.Message.UUID (UUID, random, randoms) where module IHaskell.IPython.Message.UUID (UUID, random, randoms, uuidToString) where
import Control.Monad (mzero, replicateM) import Control.Monad (mzero, replicateM)
import Control.Applicative ((<$>)) import Control.Applicative ((<$>))
...@@ -16,7 +16,7 @@ data UUID = ...@@ -16,7 +16,7 @@ data UUID =
-- present in the correct locations. For the purposes of new UUIDs, it does not matter, -- present in the correct locations. For the purposes of new UUIDs, it does not matter,
-- but IPython expects UUIDs passed to kernels to be returned unchanged, so we cannot -- but IPython expects UUIDs passed to kernels to be returned unchanged, so we cannot
-- actually parse them. -- actually parse them.
UUID String UUID { uuidToString :: String }
deriving (Show, Read, Eq, Ord) deriving (Show, Read, Eq, Ord)
-- | Generate a list of random UUIDs. -- | Generate a list of random UUIDs.
......
...@@ -25,6 +25,7 @@ module IHaskell.IPython.Types ( ...@@ -25,6 +25,7 @@ module IHaskell.IPython.Types (
HistoryAccessType(..), HistoryAccessType(..),
HistoryReplyElement(..), HistoryReplyElement(..),
replyType, replyType,
showMessageType,
-- ** IPython display data message -- ** IPython display data message
DisplayData(..), DisplayData(..),
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment