packages feed

LambdaHack-0.1.20110918: src/Display/Vty.hs

module Display.Vty
  (displayId, startup, shutdown, display, nextEvent, Session) where

import Graphics.Vty as V
import Data.List as L
import Data.Char
import qualified Data.ByteString.Char8 as BS

import Geometry
import qualified Keys as K (Key(..))
import qualified Color

displayId = "vty"

type Session = V.Vty

startup :: (Session -> IO ()) -> IO ()
startup k = V.mkVty >>= k

display :: Area -> Session -> (Loc -> (Color.Attr, Char)) -> String -> String
           -> IO ()
display ((y0,x0),(y1,x1)) vty f msg status =
  let img = (foldr (<->) V.empty_image .
             L.map (foldr (<|>) V.empty_image .
                    L.map (\ (x,y) -> let (a, c) = f (y, x)
                                      in  char (setAttr a) c)))
            [ [ (x,y) | x <- [x0..x1] ] | y <- [y0..y1] ]
  in  V.update vty (pic_for_image
       (utf8_bytestring (setAttr Color.defaultAttr)
        (BS.pack (toWidth (x1 - x0 + 1) msg)) <->
        img <->
        utf8_bytestring (setAttr Color.defaultAttr)
        (BS.pack (toWidth (x1 - x0 + 1) status))))

toWidth :: Int -> String -> String
toWidth n x = take n (x ++ repeat ' ')

keyTranslate :: V.Event -> K.Key
keyTranslate e =
  case e of
    V.EvKey KEsc []          -> K.Esc
    V.EvKey KEnter []        -> K.Return
    V.EvKey (KASCII '\t') [] -> K.Tab
    V.EvKey KUp []           -> K.Up
    V.EvKey KDown []         -> K.Down
    V.EvKey KLeft []         -> K.Left
    V.EvKey KRight []        -> K.Right
    V.EvKey KHome []         -> K.Home
    V.EvKey KPageUp []       -> K.PgUp
    V.EvKey KEnd []          -> K.End
    V.EvKey KPageDown []     -> K.PgDn
    V.EvKey KBegin []        -> K.Begin
    -- No KP_ keys in vty; see https://github.com/coreyoconnor/vty/issues/8
    -- For now, movement keys are more important than hero selection:
    V.EvKey (KASCII c) []
      | c `elem` ['1'..'9']  -> K.KP c
      | otherwise            -> K.Char c
    _                        -> K.Unknown (show e)

nextEvent :: Session -> IO K.Key
nextEvent session =
  do
    e <- V.next_event session
    return (keyTranslate e)

-- A hack to get bright colors via the bold attribute. Depending on terminal
-- settings this is needed or not and the characters really get bold or not.
-- HSCurses does this by default, but in Vty you have to request the hack.
hack c a = if Color.isBright c then with_style a bold else a

setAttr (fg, bg) =
-- This optimization breaks display for white background terminals:
--  if (fg, bg) == Color.defaultAttr
--  then def_attr
--  else
    hack fg $ hack bg $
      def_attr { attr_fore_color = SetTo (aToc fg),
                 attr_back_color = SetTo (aToc bg) }

aToc :: Color.Color -> Color
aToc Color.Black     = black
aToc Color.Red       = red
aToc Color.Green     = green
aToc Color.Yellow    = yellow
aToc Color.Blue      = blue
aToc Color.Magenta   = magenta
aToc Color.Cyan      = cyan
aToc Color.White     = white
aToc Color.BrBlack   = bright_black
aToc Color.BrRed     = bright_red
aToc Color.BrGreen   = bright_green
aToc Color.BrYellow  = bright_yellow
aToc Color.BrBlue    = bright_blue
aToc Color.BrMagenta = bright_magenta
aToc Color.BrCyan    = bright_cyan
aToc Color.BrWhite   = bright_white