{-----------------------------------------------------------------------------
reactive-banana-wx
Example: Currency Converter
------------------------------------------------------------------------------}
{-# LANGUAGE RecursiveDo #-}
import Data.Bits
import Data.Maybe
import Graphics.UI.WX hiding (Event)
import Graphics.UI.WXCore hiding (Event)
import Reactive.Banana
import Reactive.Banana.WX
import Text.Printf
{-----------------------------------------------------------------------------
Main
------------------------------------------------------------------------------}
main = start $ do
-- FIXME: Why does tab traversal not work?
f <- frame [ text := "Currency Converter", tabTraversal := True ]
dollar <- entry f [ processEnter := True ]
euro <- entry f [ processEnter := True ]
set f [layout := margin 10 $
column 10 [
grid 10 10 [[label "Dollar:", widget dollar],
[label "Euro:" , widget euro ]]
, label "Press enter to convert"
]]
network <- compile $ mdo
euroIn <- reactimateTextEntry euro euroOut
dollarIn <- reactimateTextEntry dollar dollarOut
let rate = 0.7 :: Double
withString f s
= maybe "-" (printf "%.2f") . fmap f
$ listToMaybe [x | (x,"") <- reads s]
-- define output values in terms of input values
dollarOut, euroOut :: Discrete String
dollarOut = withString (/ rate) <$> stepperD "0" euroIn
euroOut = withString (* rate) <$> stepperD "0" dollarIn
return ()
actuate network
-- text entry widget in terms of discrete time-varying values
reactimateTextEntry
:: TextCtrl a
-> Discrete String -- set programmatically (view)
-> NetworkDescription (Event String) -- read from user (controller)
reactimateTextEntry entry input = do
sink entry [ text :== input ]
-- FIXME: How to do real-time updates?
-- The keyboard event always lags one character behind.
-- Where is wxEVT_COMMAND_TEXT_UPDATED in wxHaskell?
e <- event0 entry command
b <- behavior entry text
return $ b <@ e