LambdaHack-0.2.10: Game/LambdaHack/Frontend/Vty.hs
-- | Text frontend based on Vty.
module Game.LambdaHack.Frontend.Vty
( -- * Session data type for the frontend
FrontendSession
-- * The output and input operations
, fdisplay, fpromptGetKey
-- * Frontend administration tools
, frontendName, startup
) where
import qualified Data.List as L
import Data.Text.Encoding (encodeUtf8)
import Graphics.Vty
import qualified Graphics.Vty as Vty
import Game.LambdaHack.Common.Animation (DebugModeCli (..), SingleFrame (..))
import qualified Game.LambdaHack.Common.Color as Color
import qualified Game.LambdaHack.Common.Key as K
-- | Session data maintained by the frontend.
data FrontendSession = FrontendSession
{ svty :: !Vty -- internal vty session
, sdebugCli :: !DebugModeCli -- ^ client configuration
-- ^ Configuration of the frontend session.
}
-- | The name of the frontend.
frontendName :: String
frontendName = "vty"
-- | Starts the main program loop using the frontend input and output.
startup :: DebugModeCli -> (FrontendSession -> IO ()) -> IO ()
startup sdebugCli k = do
svty <- mkVty
k FrontendSession{..}
Vty.shutdown svty
-- | Output to the screen via the frontend.
fdisplay :: FrontendSession -- ^ frontend session data
-> Bool
-> Maybe SingleFrame -- ^ the screen frame to draw
-> IO ()
fdisplay _ _ Nothing = return ()
fdisplay FrontendSession{svty} _ (Just SingleFrame{..}) =
let img = (foldr (<->) empty_image
. L.map (foldr (<|>) empty_image
. L.map (\ Color.AttrChar{..} ->
char (setAttr acAttr) acChar)))
sfLevel
pic = pic_for_image $
utf8_bytestring (setAttr Color.defAttr) (encodeUtf8 sfTop)
<-> img <->
utf8_bytestring (setAttr Color.defAttr) (encodeUtf8 sfBottom)
in update svty pic
-- | Input key via the frontend.
nextEvent :: FrontendSession -> IO K.KM
nextEvent sess@FrontendSession{svty, sdebugCli=DebugModeCli{snoMore}} =
if snoMore then return K.escKey
else do
e <- next_event svty
case e of
EvKey n mods -> do
let key = keyTranslate n
modifier = modifierTranslate mods
return K.KM {key, modifier}
_ -> nextEvent sess
-- | Display a prompt, wait for any key.
fpromptGetKey :: FrontendSession -> SingleFrame -> IO K.KM
fpromptGetKey sess frame = do
fdisplay sess True $ Just frame
nextEvent sess
keyTranslate :: Key -> K.Key
keyTranslate n =
case n of
KEsc -> K.Esc
KEnter -> K.Return
(KASCII ' ') -> K.Space
(KASCII '\t') -> K.Tab
KBackTab -> K.BackTab
KUp -> K.Up
KDown -> K.Down
KLeft -> K.Left
KRight -> K.Right
KHome -> K.Home
KPageUp -> K.PgUp
KEnd -> K.End
KPageDown -> K.PgDn
KBegin -> K.Begin
(KASCII c) -> K.Char c
_ -> K.Unknown (show n)
-- | Translates modifiers to our own encoding.
modifierTranslate :: [Modifier] -> K.Modifier
modifierTranslate mods =
if MCtrl `elem` mods then K.Control else K.NoModifier
-- 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 :: Color.Color -> Attr -> Attr
hack c a = if Color.isBright c then with_style a bold else a
setAttr :: Color.Attr -> Attr
setAttr Color.Attr{fg, bg} =
-- This optimization breaks display for white background terminals:
-- if (fg, bg) == Color.defAttr
-- 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.Brown = 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