packages feed

SFont-0.1: Graphics/UI/SDL/SFont.hs

-- A port of the SFont library for use with HSSDL
-- Liam O'Connor-Davis (liamoc@cse.unsw.edu.au)
-- Released under the BSD3 license

module Graphics.UI.SDL.SFont 
   ( initFont
   , SFont
   , write
   , textWidth
   , textHeight
   , writeChar
   ) where

import Graphics.UI.SDL
import Graphics.UI.SDL.Sprig
import Data.Array
import Data.List (groupBy)
import Data.Char (ord)

data SFont = SFont { surface :: Surface 
                   , charPos :: Array Int Int
                   } deriving (Show)

-- | Load a font from an SDL surface
initFont :: Surface -> IO SFont
initFont surface = do pinks <- let nums = [0..surfaceGetWidth surface] 
                               in sequence (map isPink nums) >>= return . zip nums 
                      let pos = ( map fst $ 
                                  map head $ 
                                  groupBy (\a b -> snd a == snd b) $ 
                                  pinks ) ++ [surfaceGetWidth surface]
                       in return $ SFont surface $ listArray (0,length pos) pos
  where                   
    isPink x = do pink <- mapRGB (surfaceGetPixelFormat surface) 255 0 255
                  color <- getPixel surface x 0
                  return $ pink == color

-- | Write the specified text at the given coordinates on the surface
write :: Surface -> SFont -> (Int, Int) -> String -> IO ()
write surf sfont (x, y) str = let xpos = map (+x) $ scanl (+) 0 $ map (charWidth sfont) str 
                                  ypos = repeat y
                                  crds = zip xpos ypos
                                  done = zip crds str
                              in sequence (map (uncurry $ writeChar surf sfont) done) >> return ()

writeChar :: Surface -> SFont -> (Int,Int) -> Char -> IO ()
writeChar dest font@(SFont src charPos) (x,y) c = let offset = (ord c - 33) * 2 + 1                       
                                                  in if all (inRange $ bounds charPos) [offset, offset+1] 
                                                     then let cWidth = charWidth font c
                                                              cHeight = textHeight font
                                                              srcRect = Rect (charPos ! offset) 0 cWidth cHeight
                                                              dstRect = Rect x y cWidth cHeight
                                                           in blit src (Just srcRect) dest (Just dstRect) >> return ()
                                                     else return ()
charWidth :: SFont -> Char -> Int
charWidth (SFont _ charPos) c = let offset = (ord c - 33) * 2 + 1
                                in if all (inRange $ bounds charPos) [offset, offset+1]
                                   then (charPos ! (offset + 1)) - (charPos ! offset)
                                   else (charPos ! 1) - (charPos ! 0)

-- | Returns the width in pixels of a given string rendered in the given font
textWidth :: SFont -> String -> Int
textWidth sfont = sum . map (charWidth sfont) 

-- | Returns the height of the font.
textHeight :: SFont -> Int
textHeight (SFont surf _ ) = surfaceGetHeight surf - 1