reactive-0.0: src/Examples.hs
{-# LANGUAGE TypeOperators, FlexibleContexts, TypeSynonymInstances, FlexibleInstances #-}
----------------------------------------------------------------------
-- |
-- Module : Examples
-- Copyright : (c) Conal Elliott 2007
-- License : BSD3
--
-- Maintainer : conal@conal.net
-- Stability : experimental
--
-- Simple test for Reactive
----------------------------------------------------------------------
-- module Main where
-- base
import Data.Monoid
import Control.Monad ((>=>),forM_)
import Control.Applicative
import Control.Arrow (first,second)
import Control.Concurrent (forkIO, killThread, threadDelay, ThreadId)
-- wxHaskell
import Graphics.UI.WX hiding (Event,Reactive)
import qualified Graphics.UI.WX as WX
-- TypeCompose
import Control.Compose ((:.)(..), inO,inO2)
import Data.Title
-- Reactive
import Data.Reactive
{--------------------------------------------------------------------
Mini-Phooey
--------------------------------------------------------------------}
type Win = Panel ()
type Wio = ((->) Win) :. IO :. (,) Layout
type Wio' a = Win -> IO (Layout,a)
wio :: Wio' a -> Wio a
wio = O . O
unWio :: Wio a -> Wio' a
unWio = unO . unO
inWio :: (Wio' a -> Wio' b) -> (Wio a -> Wio b)
inWio f = wio . f . unWio
inWio2 :: (Wio' a -> Wio' b -> Wio' c) -> (Wio a -> Wio b -> Wio c)
inWio2 f = inWio . f . unWio
instance Title_f Wio where
title_f str = inWio ((fmap.fmap.first) (boxed str))
-- Bake in vertical layout. See phooey for flexible layout.
instance Monoid Layout where
mempty = WX.empty
mappend = above
instance Monoid a => Monoid (Wio a) where
mempty = wio mempty
mappend = inWio2 mappend
type WioE a = Wio (Event a)
type WioR a = Wio (Reactive a)
buttonE :: String -> WioE ()
buttonE str = wio $ \ win ->
do (e, snk) <- mkEvent
b <- button win [ text := str, on command := snk () ]
return (hwidget b, e)
buttonE' :: String -> a -> WioE a
buttonE' str a = (a `replace`) <$> buttonE str
sliderE :: (Int,Int) -> Int -> WioE Int
sliderE (lo,hi) initial = wio $ \ win ->
do (e, snk) <- mkEvent
s <- hslider win True lo hi
[ selection := initial ]
set s [ on command := getAttr selection s >>= snk ]
return (hwidget s, {-traceE shw-} e)
sliderR :: (Int,Int) -> Int -> WioR Int
sliderR lh initial = stepper initial <$> sliderE lh initial
stringO :: Wio (Sink String)
stringO = wio $ \ win ->
do ctl <- textEntry win []
return (hwidget ctl, setAttr text ctl)
showO :: Show a => Wio (Sink a)
showO = (. show) <$> stringO
showR :: Show a => WioR (Sink a)
showR = pure <$> showO
-- | Horizontally-filled widget layout
hwidget :: Widget w => w -> Layout
hwidget = hfill . widget
-- | Binary layout combinator
above, leftOf :: Layout -> Layout -> Layout
la `above` lb = fill (column 0 [la,lb])
la `leftOf` lb = fill (row 0 [la,lb])
-- | Get attribute. Just a flipped 'get'. Handy for partial application.
getAttr :: Attr w a -> w -> IO a
getAttr = flip get
-- | Set a single attribute. Handy for partial application.
setAttr :: Attr w a -> w -> Sink a
setAttr attr ctl x = set ctl [ attr := x ]
{--------------------------------------------------------------------
Running
--------------------------------------------------------------------}
-- | Fork a 'Wio': handle frame & widget creation, and apply layout.
forkWio :: (o -> IO ThreadId) -> String -> Wio o -> IO ()
forkWio forker name w = start $
do f <- frame [ visible := False, text := name ]
pan <- panel f []
(l,o) <- unWio w pan
set pan [ layout := l ]
forker o
set f [ layout := fill (widget pan)
, visible := True
]
-- | Fork a 'WioE'
forkWioE :: String -> WioE Action -> IO ()
forkWioE = forkWio forkE
-- | Fork a 'WioR'
forkWioR :: String -> WioR Action -> IO ()
forkWioR = forkWio forkR
{--------------------------------------------------------------------
Examples
--------------------------------------------------------------------}
alarm :: Double -> Int -> IO (Event Int)
alarm secs reps =
do (e,snk) <- mkEvent
forkIO $ forM_ [1 .. reps] $ \ i ->
do threadDelay micros
snk i
return e
where
micros = round (1.0e6 * secs)
t0 = alarm 0.5 10 >>= \ e -> runE $ print <$> {-traceE (const "boo!")-} e
mkAB :: WioE String
mkAB = buttonE' "a" "a" `mappend` buttonE' "b" "b"
t1 = forkWioE "t1" $ liftA2 (<$>) stringO mkAB
acc :: WioE String
acc = g <$> mkAB
where
g :: Event String -> Event String
g e = "" `accumE` (flip (++) <$> e)
t2 = forkWioE "t2" $ liftA2 (<$>) stringO acc
total :: Show a => WioR (Sink a)
total = title "total" showR
apples, bananas, fruit :: WioR Int
apples = title "apples" $ sliderR (0,10) 3
bananas = title "bananas" $ sliderR (0,10) 7
fruit = title "fruit" $ (liftA2.liftA2) (+) apples bananas
t3 = forkWioR "t3" $ liftA2 (<**>) fruit total
t4 = forkWioR "t4" $ liftA2 (<*>) showR (sliderR (0,10) 0)
t5 = forkWioR "t5" $ liftA2 (<$>) showO (sliderR (0,10) 0)
main = t3