{-# LANGUAGE TypeFamilies #-} {-# OPTIONS -Wall #-} -------------------------------------------------------------------------------- -- | -- Module : Wumpus.Drawing.Text.Text -- Copyright : (c) Stephen Tetley 2011 -- License : BSD3 -- -- Maintainer : stephen.tetley@gmail.com -- Stability : unstable -- Portability : GHC -- -- Left-to-right text. -- -------------------------------------------------------------------------------- module Wumpus.Drawing.Text.CatText ( CatText , leftAlign , centerAlign , rightAlign , blank , space , string , (<>) , (<+>) , fontColour ) where import Wumpus.Drawing.Chains import Wumpus.Drawing.Text.Base import Wumpus.Basic.Kernel -- package: wumpus-basic import Wumpus.Basic.Utils.JoinList ( JoinList, ViewL(..), viewl ) import qualified Wumpus.Basic.Utils.JoinList as JL import Wumpus.Core -- package: wumpus-core import Data.Char ( ord ) -- Need to know line width (horizontal) and line count (vertical) -- to render... -- -- Can obviously access line count if we avoid avoid operators -- for vertical composition operator and delegate it to rendering -- instead: -- -- > rightAlign :: [CatText u] -> PosImage u (BoundingBox u) -- -- A CatPrim returns a drawing function (AdvGraphic) to be used -- drawing final rendering. -- type CatPrim u = CF (u, AdvGraphic u) newtype CatText u = CatText { getCatText :: JoinList (CatPrim u) } -- | 'HMove' : @ half_max_width * line_width -> Horizontal_Displacement @ -- type HMove u = u -> u -> u leftAMove :: Num u => HMove u leftAMove half_max _ = negate half_max centerAMove :: Fractional u => HMove u centerAMove _ elt_w = negate $ 0.5 * elt_w rightAMove :: Num u => HMove u rightAMove half_max elt_w = half_max - elt_w leftAlign :: (Real u, FromPtSize u, Floating u) => [CatText u] -> PosImage u (BoundingBox u) leftAlign = drawMulti leftAMove centerAlign :: (Real u, FromPtSize u, Floating u) => [CatText u] -> PosImage u (BoundingBox u) centerAlign = drawMulti centerAMove rightAlign :: (Real u, FromPtSize u, Floating u) => [CatText u] -> PosImage u (BoundingBox u) rightAlign = drawMulti rightAMove drawMulti :: (Real u, FromPtSize u, Floating u) => HMove u -> [CatText u] -> PosImage u (BoundingBox u) drawMulti moveF xs = promoteR2 $ \start rpos -> evalAllLines xs >>= \all_lines -> centerToBaseline >>= \down -> borderedTextObjectPos line_count (fst all_lines) >>= \opos -> let chn = centerSpinePoints line_count 0 gs = positionHLines moveF down all_lines gf = unchainZip emptyLocGraphic gs chn posG = makePosImage opos gf bbox = objectPosBounds start rpos opos in replaceAns bbox $ atStartPos posG start rpos where line_count = length xs positionHLines :: Fractional u => HMove u -> u -> (u,[(u, AdvGraphic u)]) -> [LocGraphic u] positionHLines mkH down (max_w,xs) = map fn xs where half_max = 0.5 * max_w moveF w1 = let v = vec (mkH half_max w1) (-down) in moveStart $ displaceVec v fn (elt_w, gf) = ignoreAns $ moveF elt_w $ gf evalAllLines :: (Num u, Ord u) => [CatText u] -> DrawingInfo (u, [(u, AdvGraphic u)]) evalAllLines = fmap post . mapM evalLine where post xs = let mx = foldr (\(a,_) x -> max a x) 0 xs in (mx,xs) evalLine :: Num u => CatText u -> DrawingInfo (u, AdvGraphic u) evalLine ct = case viewl $ getCatText ct of EmptyL -> return (0, replaceAns (hvec 0) $ emptyLocGraphic) af :< rest -> af >>= \a -> go a (viewl rest) where go acc EmptyL = return acc go (dx,af) (mf :< ms) = let moveF = moveStart (displaceH dx) in mf >>= \(u,gf) -> go (dx+u, af `oplus` moveF gf) (viewl ms) -- | Build a blank CatText with no output and a 0 width vector. -- blank :: Num u => CatText u blank = catOne $ return (0, replaceAns (hvec 0) $ emptyLocGraphic) -- | Note - a space character is not draw in the output, instead -- 'space' advances the width vector by the width of a space in -- the current font. -- space :: FromPtSize u => CatText u space = catOne $ charVector (CharEscInt $ ord ' ') >>= \v -> return (advanceH v, replaceAns v $ emptyLocGraphic) -- | Build a CatText from a string. -- string :: FromPtSize u => String -> CatText u string = catOne . stringPrim infixr 6 <>, <+> -- | Concatenate two CatTexts separated with no spacing. -- (<>) :: CatText u -> CatText u -> CatText u a <> b = CatText $ JL.join (getCatText a) (getCatText b) -- | Concatenate two CatTexts separated with a space. -- (<+>) :: FromPtSize u => CatText u -> CatText u -> CatText u a <+> b = a <> space <> b -- Note - @fill@ combinators cf. @wl-pprint@ (but left and right) -- will be very useful. -- -- Also PosImages can be inlined in text... -- catOne :: CatPrim u -> CatText u catOne = CatText . JL.one stringPrim :: FromPtSize u => String -> CatPrim u stringPrim = escapedPrim . escapeString escapedPrim :: FromPtSize u => EscapedText -> CatPrim u escapedPrim esc = textVector esc >>= \v -> return (vector_x v, replaceAns v $ escapedline esc) catMap :: (AdvGraphic u -> AdvGraphic u) -> CatText u -> CatText u catMap f = CatText . fmap (fmap (\(u,ag) -> (u, f $ ag))) . getCatText catlocal :: DrawingContextF -> CatText u -> CatText u catlocal fn = catMap (localize fn) fontColour :: RGBi -> CatText u -> CatText u fontColour rgb = catlocal (strokeColour rgb)