module GUI.Gtk.Structures.IO
( runWidget
, gtkContext
) where
import Control.Category
import Control.Monad
import Control.Monad.Writer
import Control.Concurrent
import Data.Maybe
import Prelude hiding ((.), id)
import Graphics.UI.Gtk hiding (Widget)
import qualified Graphics.UI.Gtk as Gtk
import Control.Monad.Restricted (Morph)
import Control.Monad.Register (Command (..))
import GUI.Gtk.Structures
gtkContext :: (Morph IO IO -> IO SWidget) -> IO ()
gtkContext m = do
_ <- unsafeInitGUIForThreadedRTS
tid <- myThreadId
let post :: Morph IO IO
post e = do
tid' <- myThreadId
if tid' == tid then e else postGUISync e
c <- m post
window <- windowNew
set window [ containerBorderWidth := 10, containerChild := snd c ]
_ <- window `on` deleteEvent $ liftIO mainQuit >> return False
widgetShowAll window
mainGUI
type SWidget = (IO (), Gtk.Widget)
runWidget
:: forall n m . (MonadIO m, MonadIO n)
=> Morph n IO
-> (IO () -> IO ())
-> Morph IO IO
-> Widget n m
-> m SWidget
runWidget nio post' post = toWidget
where
liftIO' :: MonadIO k => IO a -> k a
liftIO' = liftIO . post
reg :: Receive n m a -> Receive IO m a
reg s f = liftM (nio .) $ s $ liftM (fmap liftIO) . liftIO' . f . (nio .)
ger :: (Command -> IO ()) -> Send n m a -> Send IO m a
ger hd s f = s $ \a -> liftIO' $ do
hd Block
f a
hd Unblock
nhd :: Command -> IO ()
nhd = const $ return ()
toWidget :: Widget n m -> m SWidget
toWidget i = case i of
Action m -> m >>= toWidget
Label s -> do
w <- liftIO' $ labelNew Nothing
ger nhd s $ labelSetLabel w
return' w
Button s sens col m -> do
w <- liftIO' buttonNew
hd <- reg m $ \re -> on' w buttonActivated $ re ()
ger hd s $ buttonSetLabel w
ger hd sens $ widgetSetSensitive w
ger hd col $ \c -> do
widgetModifyBg w StateNormal c
widgetModifyBg w StatePrelight c
return' w
Entry (r, s) -> do
w <- liftIO' entryNew
hd <- reg s $ \re -> on' w entryActivate $ entryGetText w >>= re
ger hd r $ entrySetText w
return' w
Checkbox (r, s) -> do
w <- liftIO' checkButtonNew
hd <- reg s $ \re -> on' w toggled $ toggleButtonGetActive w >>= re
ger hd r $ toggleButtonSetActive w
return' w
Combobox ss (r, s) -> do
w <- liftIO' comboBoxNewText
liftIO' $ flip mapM_ ss $ comboBoxAppendText w
hd <- reg s $ \re -> on' w changed $ fmap (max 0) (comboBoxGetActive w) >>= re
ger hd r $ comboBoxSetActive w
return' w
List o xs -> do
ws <- mapM toWidget xs
w <- liftIO' $ case o of
Vertical -> fmap castToBox $ vBoxNew False 1
Horizontal -> fmap castToBox $ hBoxNew False 1
shs <- forM ws $ liftIO' . containerAdd'' w . snd
liftM (mapFst (sequence_ shs >>)) $ return'' ws w
Notebook' s xs -> do
ws <- mapM (toWidget . snd) xs
w <- liftIO' notebookNew
forM_ (zip ws xs) $ \(ww, (s, _)) -> do
liftIO' . flip (notebookAppendPage w) s $ snd $ ww
_ <- reg s $ \re -> on' w switchPage $ re
return'' ws w
Cell onCh f -> do
let b = True --False
w <- liftIO' $ case b of
True -> fmap castToContainer $ hBoxNew False 1
False -> fmap castToContainer $ alignmentNew 0 0 1 1
sh <- liftIO $ newMVar $ return ()
onCh $ \bv -> do
mx <- f toWidget bv
return $ mx >>= \(x, y) -> liftIO' $ do
_ <- swapMVar sh x
containerForeach w $ if b then widgetHideAll else containerRemove w
post' $ post $ do
ch <- containerGetChildren w
when (y `notElem` ch) $ containerAdd w y
x
liftM (mapFst (join (readMVar sh) >>)) $ return'' [] w
on' :: GObjectClass x => x -> Signal x c -> c -> IO (Command -> IO ())
on' o s c = liftM (flip f) $ on o s c where
f Kill = signalDisconnect
f Block = signalBlock
f Unblock = signalUnblock
return' :: Monad m => WidgetClass x => x -> m SWidget
return' w = return (widgetShowAll w, castToWidget w)
return'' :: Monad m => WidgetClass x => [SWidget] -> x -> m SWidget
return'' ws w = return (mapM_ fst ws >> widgetShow w, castToWidget w)
mapFst f (a, b) = (f a, b)
containerAdd'' w x = do
a <- alignmentNew 0 0 0 0
containerAdd a x
containerAdd w a
set w [ boxChildPacking a := PackNatural ]
return $ widgetShow a