{-# LANGUAGE ViewPatterns, NoMonomorphismRestriction, ScopedTypeVariables, GeneralizedNewtypeDeriving, TypeSynonymInstances, NamedFieldPuns, RecordWildCards #-} {-# OPTIONS -Wall #-} module Graphics.Aosd.Pango( -- * Base TextRenderer(..),Width(..),textRenderer, -- * PangoText PangoText,pText,pRaw,pEmpty,pTag, -- ** Markup tags pSpan,pBold,pBig,pItalic,pStrikethrough,pSmall,pSub,pSup,pUnderline,pMono, -- *** Span shorthands pSized, -- ** Standard text combinators pIntercalate,pUnlines,pUnwords,pShow, -- * Reexports SpanAttribute(..), LayoutAlignment(..), LayoutWrapMode(..), TabPosition, Size(..), sRGB, module Graphics.Aosd, module Data.Monoid, module Data.Colour.Names ) where import Control.Monad.IO.Class import Foreign.C import Graphics.Aosd import Graphics.Aosd.Util import Graphics.Rendering.Pango.Cairo import Graphics.Rendering.Pango.Enums import Graphics.Rendering.Pango.Layout import Control.Monad(void) import Graphics.Rendering.Pango.Markup import Data.Monoid import Data.String import Data.List(intersperse) import Data.Colour import Data.Colour.SRGB import Data.Colour.Names data TextRenderer = TextRenderer { -- | Hint: Use 'sRGB' or "Data.Colour.Names". colour :: Colour Double, -- | 0: Transparent, 1: Opaque. opacity :: Double, -- | Uses 'layoutSetWidth' if set. width :: Maybe Width, -- | Uses 'layoutSetWrap' if set. wrapMode :: Maybe LayoutWrapMode, -- | Uses 'layoutSetJustify' if set. justify :: Maybe Bool, -- | Uses 'layoutSetAlignment' if set. alignment :: Maybe LayoutAlignment, -- | Uses 'layoutSetSpacing' if set. lineSpacing :: Maybe Double, -- | Uses 'layoutSetTabs' if set. tabs :: Maybe [TabPosition], -- | Uses 'layoutSetSingleParagraphMode' if set. singleParagraphMode :: Maybe Bool, -- | The actual text tcText :: PangoText } data Width = Unlimited -- ^ The layout will be as wide as necessary to hold all the lines without wrapping | Width Double -- ^ The layout will be wrapped (according to 'wrapMode') to the given width in Pango units deriving(Show,Eq) unsup :: String -> t unsup s = error (s ++ " unsupported for Graphics.Aosd.Pango.Width") -- | Supports only 'fromInteger'. instance Num Width where fromInteger = Width . fromIntegral (+) = unsup "(+)" (*) = unsup "(*)" abs = unsup "abs" signum = unsup "signum" (-) = unsup "(-)" negate = unsup "negate" -- | Supports only 'fromRational'. instance Fractional Width where fromRational = Width . fromRational (/) = unsup "/" recip = unsup "recip" -- | Construct a 'TextConf' with most fields set to 'Nothing' textRenderer :: PangoText -> TextRenderer textRenderer t = TextRenderer { colour = green, opacity = 1, width = Nothing, wrapMode = Nothing, justify = Nothing, alignment = Nothing, lineSpacing = Nothing, tabs = Nothing, singleParagraphMode = Nothing, tcText = t } -- | Plain text or some Pango markup. Suggestion: Use {-\# LANGUAGE OverloadedStrings \#-}. data PangoText = PlainText ShowS | PangoMarkup ShowS | Empty toMarkup :: PangoText -> ShowS toMarkup (PlainText s) = showString (escapeMarkup (s "")) toMarkup (PangoMarkup s) = s toMarkup Empty = mempty -- | Uses 'pText' (not 'pRaw'). instance IsString PangoText where fromString = pText instance Monoid PangoText where mempty = Empty mappend Empty x2 = x2 mappend x1 Empty = x1 mappend (PlainText s1) (PlainText s2) = PlainText (s1 . s2) mappend x1 x2 = PangoMarkup (toMarkup x1 . toMarkup x2) instance Show PangoText where showsPrec _ Empty = showString "pEmpty" showsPrec prec (PlainText s) = showParen (prec >= 11) (showString "pText " . shows (s "")) showsPrec prec (PangoMarkup s) = showParen (prec >= 11) (showString "pRaw " . shows (s "")) pEmpty :: PangoText pEmpty = Empty -- | Raw Pango markup, see . pRaw :: String -> PangoText pRaw = PangoMarkup . showString -- | Plain text. pText :: String -> PangoText pText = PlainText . showString pSpan :: [SpanAttribute] -> PangoText -> PangoText pSpan (attrs :: [SpanAttribute]) inner = PangoMarkup it where it = -- adapted from 'Graphics.Rendering.Pango.Markup.markSpan' showString "') (map shows attrs) . toMarkup inner . showString "" pIntercalate :: PangoText -> [PangoText] -> PangoText pIntercalate x = mconcat . intersperse x pUnlines :: [PangoText] -> PangoText pUnlines = pIntercalate (pText "\n") pUnwords :: [PangoText] -> PangoText pUnwords = pIntercalate (pText " ") pShow :: Show a => a -> PangoText pShow = pText . show -- | Set font size in points pSized :: Double -> PangoText -> PangoText pSized pt = pSpan [FontSize (SizePoint pt)] pTag :: String -- ^ Tag name -> PangoText -> PangoText pTag tagName inner = PangoMarkup $ showChar '<' . showString tagName . showChar '>' . toMarkup inner . showString "' pBold :: PangoText -> PangoText pBold = pTag "b" pBig :: PangoText -> PangoText pBig = pTag "big" pItalic :: PangoText -> PangoText pItalic = pTag "i" pStrikethrough :: PangoText -> PangoText pStrikethrough = pTag "s" -- | Subscript pSub :: PangoText -> PangoText pSub = pTag "sub" -- | Superscript pSup :: PangoText -> PangoText pSup = pTag "sup" pSmall :: PangoText -> PangoText pSmall = pTag "small" -- | Monospace font pMono :: PangoText -> PangoText pMono = pTag "tt" -- | Underline pUnderline :: PangoText -> PangoText pUnderline = pTag "u" layoutSetWidth' :: PangoLayout -> Width -> IO () layoutSetWidth' layout w = layoutSetWidth layout (case w of Unlimited -> Nothing Width x -> Just x) instance AosdRenderer TextRenderer where toGeneralRenderer TextRenderer{..} = do fm <- cairoFontMapGetDefault -- resolution <- cairoFontMapGetResolution fm cxt <- cairoCreateContext (Just fm) layout <- layoutEmpty cxt case tcText of Empty -> return () PlainText s -> layoutSetText layout (s "") PangoMarkup s -> void (layoutSetMarkup layout (s "")) let go :: (PangoLayout -> a -> IO ()) -> Maybe a -> IO () go f = maybeDo (f layout) go layoutSetWidth' width go layoutSetWrap wrapMode go layoutSetJustify justify go layoutSetAlignment alignment go layoutSetSpacing lineSpacing go layoutSetTabs tabs go layoutSetSingleParagraphMode singleParagraphMode (grInkExtent,grPositioningExtent) <- layoutGetPixelExtents layout let render = do --updateLayout layout -- No idea when this is neccessary setSourceColour colour opacity showLayout layout return GeneralRenderer { grInkExtent, grPositioningExtent, grRender = render } -- getSize l = do -- -- (ink,logical) -- a@(Rectangle xi yi wi hi, Rectangle xl yl wl hl) <- layoutGetPixelExtents l -- -- -- print ("ink",fst a) -- -- print ("logical",snd a) -- -- let w = max (xi+wi) (xl+wl) -- h = max (yi+hi) (yl+hl) -- -- -- return (fi w, fi h) -- -- where -- fi = fromIntegral -- --