LambdaHack-0.1.20110117: src/Display/Gtk.hs
module Display.Gtk
(displayId, startup, shutdown,
display, nextEvent, setBG, setFG, setBold, Session,
white, black, yellow, blue, magenta, red, green, attr, Attr) where
import Control.Monad
import Control.Concurrent
import Graphics.UI.Gtk.Gdk.Events -- TODO: replace, deprecated
import Graphics.UI.Gtk hiding (Attr)
import Data.List as L
import Data.IORef
import Data.Map as M
import Geometry
import Keys as K
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
unsafeInitGUIForThreadedRTS
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"
fontDescriptionSetSize f 12
widgetModifyFont tv (Just f)
currentfont <- newIORef f
onButtonPress tv (\ e -> case e of
Button { Graphics.UI.Gtk.Gdk.Events.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 -> postGUIAsync (writeChan ec (Graphics.UI.Gtk.Gdk.Events.eventKeyName e)) >> return True)
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 =
postGUIAsync $
do
tb <- textViewGetBuffer (sview session)
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) ]
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
-- | reads until a non-dead key encountered
readUndeadChan :: Chan String -> IO String
readUndeadChan ch =
do
x <- readChan ch
if dead x then readUndeadChan ch else return x
where
dead x =
case x of
"Shift_R" -> True
"Shift_L" -> True
"Control_L" -> True
"Control_R" -> True
"Super_L" -> True
"Super_R" -> True
"Menu" -> True
"Alt_L" -> True
"Alt_R" -> True
"ISO_Level2_Shift" -> True
"ISO_Level3_Shift" -> True
"ISO_Level2_Latch" -> True
"ISO_Level3_Latch" -> True
"Num_Lock" -> True
"Caps_Lock" -> True
_ -> False
keyTranslate :: String -> Maybe K.Key
keyTranslate "less" = Just (K.Char '<')
keyTranslate "greater" = Just (K.Char '>')
keyTranslate "period" = Just (K.Char '.')
keyTranslate "colon" = Just (K.Char ':')
keyTranslate "comma" = Just (K.Char ',')
keyTranslate "space" = Just (K.Char ' ')
keyTranslate "question" = Just (K.Char '?')
keyTranslate "asterisk" = Just (K.Char '*')
keyTranslate "Escape" = Just K.Esc
keyTranslate "Return" = Just K.Return
keyTranslate "KP_Up" = Just K.Up
keyTranslate "KP_Down" = Just K.Down
keyTranslate "KP_Left" = Just K.Left
keyTranslate "KP_Right" = Just K.Right
keyTranslate "KP_Home" = Just K.Home
keyTranslate "KP_End" = Just K.End
keyTranslate "KP_Page_Up" = Just K.PgUp
keyTranslate "KP_Page_Down" = Just K.PgDn
keyTranslate "KP_Begin" = Just K.Begin
keyTranslate "KP_Enter" = Just K.Return
keyTranslate ['K','P','_',c] = Just (K.Char c) -- for numbers
keyTranslate [c] = Just (K.Char c)
keyTranslate _ = Nothing
nextEvent :: Session -> IO K.Key
nextEvent session =
do
e <- readUndeadChan (schan session)
maybe (nextEvent session) return (keyTranslate e)
setBold = id -- not supported yet
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)