packages feed

LambdaHack-0.1.20080413: Display/Gtk.hs

module Display.Gtk
  (displayId, startup, shutdown, 
   display, nextEvent, setBG, setFG, Session,
   white, black, yellow, blue, magenta, red, green, attr, Attr) where

import Control.Monad
import Control.Concurrent
import Graphics.UI.Gtk hiding (Attr)
import Data.List as L
import Data.IORef
import Data.Map as M

import Geometry

displayId = "gtk"

data Session =
  Session {
    schan :: Chan String,
    stags :: Map AttrKey TextTag,
    sview :: TextView }

doAttr :: TextTag -> AttrKey -> IO ()
doAttr tt (BG Blue)    = set tt [ textTagBackground := "#0000CC" ]
doAttr tt (BG Magenta) = set tt [ textTagBackground := "#CC00CC" ]
doAttr tt (BG Green)   = set tt [ textTagBackground := "#00CC00" ]
doAttr tt (BG Red)     = set tt [ textTagBackground := "#CC0000" ]
doAttr tt (BG White)   = set tt [ textTagBackground := "#FFFFFF" ]
doAttr tt (FG Green)   = set tt [ textTagForeground := "#00FF00" ]
doAttr tt (FG Red)     = set tt [ textTagForeground := "#FF0000" ]
doAttr tt (FG Blue)    = set tt [ textTagForeground := "#0000FF" ]
doAttr tt (FG Yellow)  = set tt [ textTagForeground := "#CCCC00" ]
doAttr tt (FG Black)   = set tt [ textTagForeground := "#000000" ]
doAttr tt _            = return ()

startup :: (Session -> IO ()) -> IO ()
startup k =
  do
    initGUI
    w <- windowNew

    ttt <- textTagTableNew
    -- text attributes
    tts <- fmap M.fromList $
           mapM (\ c -> do
                          tt <- textTagNew Nothing
                          textTagTableAdd ttt tt
                          doAttr tt c
                          return (c,tt))
                [ x | c <- [minBound .. maxBound], x <- [FG c, BG c]]

    -- text buffer
    tb <- textBufferNew (Just ttt)
    textBufferSetText tb (unlines (replicate 25 (replicate 80 ' ')))

    -- create text view
    tv <- textViewNewWithBuffer tb
    containerAdd w tv
    textViewSetEditable tv False
    textViewSetCursorVisible tv False

    -- font
    f <- fontDescriptionNew
    fontDescriptionSetFamily f "Monospace"
    widgetModifyFont tv (Just f)
    currentfont <- newIORef f
    onButtonPress tv (\ e -> case e of
                               Button { eventButton = RightButton } ->
                                 do
                                   fsd <- fontSelectionDialogNew "Choose font"
                                   cf <- readIORef currentfont
                                   -- fd <- fontDescriptionToString cf
                                   -- fontSelectionDialogSetFontName fsd fd
                                   fontSelectionDialogSetPreviewText fsd "+##@##-...|"
                                   response <- dialogRun fsd
                                   when (response == ResponseOk) $
                                     do
                                       fn <- fontSelectionDialogGetFontName fsd
                                       case fn of
                                         Just fn' -> do
                                                       fd <- fontDescriptionFromString fn'
                                                       writeIORef currentfont fd
                                                       widgetModifyFont tv (Just fd)
                                         Nothing  -> return ()
                                   widgetDestroy fsd
                                   return True
                               _ -> return False)

    let black = Color minBound minBound minBound
    let white = Color maxBound maxBound maxBound
    widgetModifyBase tv StateNormal black
    widgetModifyText tv StateNormal white

    ec <- newChan 
    forkIO $ k (Session ec tts tv)
    
    onKeyPress tv (\ e -> writeChan ec (eventKeyName e) >> yield >> return True)

    idleAdd (yield >> return True) priorityDefaultIdle
    onDestroy w mainQuit -- set quit handler
    widgetShowAll w
    yield
    mainGUI

shutdown _ = mainQuit

display :: Area -> Session -> (Loc -> (Attr, Char)) -> String -> String -> IO ()
display ((y0,x0),(y1,x1)) session f msg status =
  do
    sbuf <- textViewGetBuffer (sview session)
    ttt <- textBufferGetTagTable sbuf
    tb <- textBufferNew (Just ttt)
    let text = unlines [ [ snd (f (y,x)) | x <- [x0..x1] ] | y <- [y0..y1] ]
    textBufferSetText tb (msg ++ "\n" ++ text ++ status)
    sequence_ [ setTo tb (stags session) (y,x) a | 
                y <- [y0..y1], x <- [x0..x1], let loc = (y,x), let (a,c) = f (y,x) ]
    textViewSetBuffer (sview session) tb

setTo :: TextBuffer -> Map AttrKey TextTag -> Loc -> Attr -> IO ()
setTo tb tts (ly,lx) a =
  do
    ib <- textBufferGetIterAtLineOffset tb (ly+1) lx
    ie <- textIterCopy ib
    textIterForwardChar ie
    mapM_ (\ c -> textBufferApplyTag tb (tts ! c) ib ie) a

nextEvent :: Session -> IO String
nextEvent session = readChan (schan session)

setBG c = (BG c :)
setFG c = (FG c :)
blue    = Blue
magenta = Magenta
red     = Red
yellow  = Yellow
green   = Green
white   = White
black   = Black
attr    = []

type Attr = [AttrKey]

data AttrKey =
    FG AttrColor
  | BG AttrColor
  deriving (Eq, Ord)

type Color = AttrColor

data AttrColor =
    Blue
  | Magenta
  | Red
  | Green
  | Yellow
  | White
  | Black
  deriving (Eq, Ord, Enum, Bounded)