mirror of
https://github.com/IHaskell/IHaskell.git
synced 2025-04-16 19:36:06 +00:00
322 lines
8.8 KiB
Plaintext
322 lines
8.8 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "a0d6ef1e-d8cd-40dc-8928-aa984ea6e788",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"{-# LANGUAGE OverloadedStrings, TypeApplications #-}\n",
|
|
"import IHaskell.Display.Widgets\n",
|
|
"import Data.Proxy (Proxy(..))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "bdf75813-33a0-4b98-a41a-35b3d88bcee9",
|
|
"metadata": {},
|
|
"source": [
|
|
"# The `Link` widgets\n",
|
|
"\n",
|
|
"Have you ever wanted to sync some attributes between two widgets? Are you tired of setting handlers like `getValue ... >>= setValue ...`? Then today's your lucky day!\n",
|
|
"\n",
|
|
"The link widget allows you to sync two attributes in two different widgets. The main difference with using a handler (appart from the convenience) is that they are synced on the *frontend*. This is faster because it doesn't have to be sent to and processed by the kernel first.\n",
|
|
"\n",
|
|
"The `Link` widget has two fields, `Source` and `Target`, of type `WidgetFieldPair`. `WidgetFieldPair` has a constructor that receives a a widget and a field. We can link two widgets creating a `Link` widget and setting its `Source` and `Target` fields.\n",
|
|
"\n",
|
|
"Let's see an example linking two sliders:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"id": "107c6fc9-c1fd-433d-8719-fa3daea8bc51",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"application/vnd.jupyter.widget-view+json": {
|
|
"model_id": "a27260ed-9dfe-404a-9bcc-6d3da537794f",
|
|
"version_major": 2,
|
|
"version_minor": 0
|
|
}
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
},
|
|
{
|
|
"data": {
|
|
"application/vnd.jupyter.widget-view+json": {
|
|
"model_id": "183bfddc-f461-482e-8640-564bf8c1c3ad",
|
|
"version_major": 2,
|
|
"version_minor": 0
|
|
}
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"-- Creating the sliders\n",
|
|
"is1 <- mkIntSlider\n",
|
|
"is2 <- mkIntSlider\n",
|
|
"\n",
|
|
"-- Creating the link\n",
|
|
"link <- mkLink\n",
|
|
"setField @Source link (WidgetFieldPair is1 (Proxy @IntValue))\n",
|
|
"setField @Target link (WidgetFieldPair is2 (Proxy @IntValue))\n",
|
|
"\n",
|
|
"-- Displaying the widget\n",
|
|
"is1\n",
|
|
"is2"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "smart-gnome",
|
|
"metadata": {},
|
|
"source": [
|
|
"If we move the first slider, the second one moves too. If we move the bottom slider, the top one moves too. Isn't it great?\n",
|
|
"\n",
|
|
"We can also make *directional* links. That means that if you modify the source, the target is modified too, but not viceversa.\n",
|
|
"\n",
|
|
"By the way, we can link any type of widget, as long as its fields have javascript-compatible types."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"id": "f71e323b-ac72-42e5-8823-b768d6f9cb58",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"application/vnd.jupyter.widget-view+json": {
|
|
"model_id": "5455e23a-2c44-4481-ac98-041f45f16bb2",
|
|
"version_major": 2,
|
|
"version_minor": 0
|
|
}
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
},
|
|
{
|
|
"data": {
|
|
"application/vnd.jupyter.widget-view+json": {
|
|
"model_id": "9665b5d8-a36b-4216-9d1e-120c3f24e856",
|
|
"version_major": 2,
|
|
"version_minor": 0
|
|
}
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"-- We create the sliders\n",
|
|
"fs1 <- mkFloatSlider\n",
|
|
"fi2 <- mkIntSlider\n",
|
|
"\n",
|
|
"-- Making a directional link\n",
|
|
"link <- mkDirectionalLink\n",
|
|
"setField @Source link (WidgetFieldPair fs1 (Proxy @FloatValue))\n",
|
|
"setField @Target link (WidgetFieldPair fi2 (Proxy @IntValue))\n",
|
|
"\n",
|
|
"-- Displaying the sliders\n",
|
|
"fs1\n",
|
|
"fi2"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "stone-lightweight",
|
|
"metadata": {},
|
|
"source": [
|
|
"As we expect, the bottom widget is modified when the slider in the top one changes. But the top one doesn't change if the bottom one does.\n",
|
|
"\n",
|
|
"But this \"making a widget and setting a source and setting a target\" troupe is a bit tiring. For this reason, we have the `jslink` and `jsdlink` functions, that create a link or directional link given two `WidgetFieldPair`s.\n",
|
|
"\n",
|
|
"Here we have a simple example using boolean widgets:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"id": "91ccf115-57b4-4176-b157-0e79c27f4341",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<style>/* Styles used for the Hoogle display in the pager */\n",
|
|
".hoogle-doc {\n",
|
|
"display: block;\n",
|
|
"padding-bottom: 1.3em;\n",
|
|
"padding-left: 0.4em;\n",
|
|
"}\n",
|
|
".hoogle-code {\n",
|
|
"display: block;\n",
|
|
"font-family: monospace;\n",
|
|
"white-space: pre;\n",
|
|
"}\n",
|
|
".hoogle-text {\n",
|
|
"display: block;\n",
|
|
"}\n",
|
|
".hoogle-name {\n",
|
|
"color: green;\n",
|
|
"font-weight: bold;\n",
|
|
"}\n",
|
|
".hoogle-head {\n",
|
|
"font-weight: bold;\n",
|
|
"}\n",
|
|
".hoogle-sub {\n",
|
|
"display: block;\n",
|
|
"margin-left: 0.4em;\n",
|
|
"}\n",
|
|
".hoogle-package {\n",
|
|
"font-weight: bold;\n",
|
|
"font-style: italic;\n",
|
|
"}\n",
|
|
".hoogle-module {\n",
|
|
"font-weight: bold;\n",
|
|
"}\n",
|
|
".hoogle-class {\n",
|
|
"font-weight: bold;\n",
|
|
"}\n",
|
|
"\n",
|
|
".get-type {\n",
|
|
"color: green;\n",
|
|
"font-weight: bold;\n",
|
|
"font-family: monospace;\n",
|
|
"display: block;\n",
|
|
"white-space: pre-wrap;\n",
|
|
"}\n",
|
|
".show-type {\n",
|
|
"color: green;\n",
|
|
"font-weight: bold;\n",
|
|
"font-family: monospace;\n",
|
|
"margin-left: 1em;\n",
|
|
"}\n",
|
|
".mono {\n",
|
|
"font-family: monospace;\n",
|
|
"display: block;\n",
|
|
"}\n",
|
|
".err-msg {\n",
|
|
"color: red;\n",
|
|
"font-style: italic;\n",
|
|
"font-family: monospace;\n",
|
|
"white-space: pre;\n",
|
|
"display: block;\n",
|
|
"}\n",
|
|
"#unshowable {\n",
|
|
"color: red;\n",
|
|
"font-weight: bold;\n",
|
|
"}\n",
|
|
".err-msg.in.collapse {\n",
|
|
"padding-top: 0.7em;\n",
|
|
"}\n",
|
|
"\n",
|
|
".highlight-code {\n",
|
|
"white-space: pre;\n",
|
|
"font-family: monospace;\n",
|
|
"}\n",
|
|
"\n",
|
|
".suggestion-warning { \n",
|
|
"font-weight: bold;\n",
|
|
"color: rgb(200, 130, 0);\n",
|
|
"}\n",
|
|
".suggestion-error { \n",
|
|
"font-weight: bold;\n",
|
|
"color: red;\n",
|
|
"}\n",
|
|
".suggestion-name {\n",
|
|
"font-weight: bold;\n",
|
|
"}\n",
|
|
"\n",
|
|
"</style><span class='get-type'>jsdlink :: WidgetFieldPair -> WidgetFieldPair -> IO DirectionalLink</span>"
|
|
],
|
|
"text/plain": [
|
|
"jsdlink :: WidgetFieldPair -> WidgetFieldPair -> IO DirectionalLink"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
},
|
|
{
|
|
"data": {
|
|
"application/vnd.jupyter.widget-view+json": {
|
|
"model_id": "0b0885c4-d023-4bba-a41c-7ca0e53a33e7",
|
|
"version_major": 2,
|
|
"version_minor": 0
|
|
}
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
},
|
|
{
|
|
"data": {
|
|
"application/vnd.jupyter.widget-view+json": {
|
|
"model_id": "b21ab860-754e-469d-85fb-d6e820466311",
|
|
"version_major": 2,
|
|
"version_minor": 0
|
|
}
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
},
|
|
{
|
|
"data": {
|
|
"application/vnd.jupyter.widget-view+json": {
|
|
"model_id": "5d7e4d16-5ba4-4141-9499-72324df2c594",
|
|
"version_major": 2,
|
|
"version_minor": 0
|
|
}
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
":t jsdlink\n",
|
|
"chk <- mkCheckBox\n",
|
|
"tgb <- mkToggleButton\n",
|
|
"valid <- mkValid\n",
|
|
"\n",
|
|
"-- The Link widget cannot be displayed, so we ignore the return value\n",
|
|
"_ <- jslink (WidgetFieldPair chk (Proxy @BoolValue)) (WidgetFieldPair tgb (Proxy @BoolValue))\n",
|
|
"_ <- jsdlink (WidgetFieldPair chk (Proxy @BoolValue)) (WidgetFieldPair valid (Proxy @BoolValue))\n",
|
|
"\n",
|
|
"chk\n",
|
|
"tgb\n",
|
|
"valid"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "db91a9da-1075-4264-b633-0ab5a51d22f5",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Haskell",
|
|
"language": "haskell",
|
|
"name": "haskell"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": "ihaskell",
|
|
"file_extension": ".hs",
|
|
"mimetype": "text/x-haskell",
|
|
"name": "haskell",
|
|
"pygments_lexer": "Haskell",
|
|
"version": "9.8.2"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|