frpnow-gtk3-0.2.0: Control/FRPNow/GTK/Buttons.hs
{- |
Module : Control.FRPNow.GTK.Buttons
Copyright : (c) George Steel 2017
License : BSD3
Maintainer : george.steel@gmail.org
Functions for creating buttons which interact with FRPNow.
-}
module Control.FRPNow.GTK.Buttons (
IconName, createButton, createDynamicButton, createToggleButton,
-- * Checkboxes
createCheckButton, createStaticChecklist, createDynamicChecklist,
) where
import Control.FRPNow.GTK.Core
import Control.FRPNow.GTK.Containers
import Graphics.UI.Gtk
import Control.Applicative
import Control.Monad
import Control.FRPNow
import Data.Maybe
import qualified Data.Text as T
import Data.Text (Text)
-- | Type for standard icon names.
-- The value should be contained in the standard list at <https://developer.gnome.org/icon-naming-spec/>.
type IconName = T.Text
-- | Creates a button with (optionally) text and an icon. Returns the button and when it is pressed.
createButton :: Maybe IconName -> Maybe Text -> Now (Button, EvStream ())
createButton micon mlbl = do
btn <- sync buttonNew
iattr <- case micon of
Just icon -> do
img <- sync $ imageNewFromIconName icon IconSizeButton
return [buttonImage := img]
Nothing -> return []
let tattr = maybeToList (fmap (buttonLabel :=) mlbl)
sync $ set btn (iattr ++ tattr)
pressed <- getUnitSignal buttonActivated btn
return (btn, pressed)
-- | Creates a toggle button with an initial state. Breutns the button and it's current state.
createToggleButton :: Maybe IconName -> Maybe Text -> Bool -> Now (ToggleButton, Behavior Bool)
createToggleButton micon mlbl initstate = do
btn <- sync toggleButtonNew
iattr <- case micon of
Just icon -> do
img <- sync $ imageNewFromIconName icon IconSizeButton
return [buttonImage := img]
Nothing -> return []
let tattr = maybeToList (fmap (buttonLabel :=) mlbl)
sync $ set btn (iattr ++ tattr ++ [toggleButtonActive := initstate])
updated <- getSignal toggled btn (toggleButtonGetActive btn >>=)
st <- sample $ fromChanges initstate updated
return (btn,st)
-- | Creates a button with dynamic text.
createDynamicButton :: Behavior Text -> Now (Button,EvStream ())
createDynamicButton s = do
button <- sync buttonNew
setAttr buttonLabel button s
stream <- getUnitSignal buttonActivated button
return (button,stream)
--------------------------------------------------------------------------------
-- | Creates a checkbox with text an an initial state. Returns the widget and its current state
createCheckButton :: Text -> Bool -> Now (CheckButton, Behavior Bool)
createCheckButton txt initstate = do
btn <- sync $ checkButtonNewWithLabel txt
sync $ set btn [toggleButtonActive := initstate]
updated <- getSignal toggled btn (toggleButtonGetActive btn >>=)
st <- sample $ fromChanges initstate updated
return (btn,st)
createChecklistItem :: (a, Text) -> Bool -> Now (CheckButton, Behavior [a])
createChecklistItem (val, txt) initstate = do
(btn,st) <- createCheckButton txt initstate
return (btn, fmap (\b -> if b then [val] else []) st)
-- | Creates a set of checkboxes from a list of (item,label) pairs and a list of initially-checked items. Returns a list of 'CheckButton's (use a function on the "Containers" module to pack them) and the currently-selected items.
createStaticChecklist :: Eq a => [(a,Text)] -> [a] -> Now ([CheckButton], Behavior [a])
createStaticChecklist items startchecked = do
btns <- forM items $ \item@(val,txt) ->
createChecklistItem item (val `elem` startchecked)
let (cbs, results) = unzip btns
vals = mconcat results
return (cbs, vals)
-- | Creates a checklist to select from a dynamic list of objects (updating the displayed checkboxes). Returns the checklist (stacked vertically in a VBox) and the currently selected items.
createDynamicChecklist :: Eq a => Behavior [(a, Text)] -> Now (VBox, Behavior [a])
createDynamicChecklist dynitems = do
box <- sync $ vBoxNew False 0
inititems <- sample dynitems
(initboxes,initselected) <- createStaticChecklist inititems []
sync $ forM_ initboxes $ \cb -> boxPackStart box cb PackNatural 0
let itemsChanged = toChanges dynitems
(outReplaced,replaceOut) <- callbackStream
selected <- sample $ foldrSwitch initselected outReplaced
flip callStream itemsChanged $ \itemslist -> do
let newitems = last itemslist
oldselection <- sample selected
sync $ clearChildren box
(newboxes,newselected) <- createStaticChecklist newitems oldselection
sync $ forM_ newboxes $ \cb -> boxPackStart box cb PackNatural 0
sync $ widgetShowAll box
sync $ replaceOut newselected
return ()
return (box,selected)