shakespeare-2.0.0: Text/CssCommon.hs
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE CPP #-}
module Text.CssCommon where
import Text.Css
import Text.MkSizeType
import qualified Data.Text as TS
import Text.Printf (printf)
import Language.Haskell.TH
import Data.Word (Word8)
import Data.Bits
import Data.Text.Lazy.Builder (fromLazyText)
import qualified Data.Text.Lazy as TL
renderCssUrl :: (url -> [(TS.Text, TS.Text)] -> TS.Text) -> CssUrl url -> TL.Text
renderCssUrl r s = renderCss $ s r
data Color = Color Word8 Word8 Word8
deriving Show
instance ToCss Color where
toCss (Color r g b) =
let (r1, r2) = toHex r
(g1, g2) = toHex g
(b1, b2) = toHex b
in fromText $ TS.pack $ '#' :
if r1 == r2 && g1 == g2 && b1 == b2
then [r1, g1, b1]
else [r1, r2, g1, g2, b1, b2]
where
toHex :: Word8 -> (Char, Char)
toHex x = (toChar $ shiftR x 4, toChar $ x .&. 15)
toChar :: Word8 -> Char
toChar c
| c < 10 = mkChar c 0 '0'
| otherwise = mkChar c 10 'A'
mkChar :: Word8 -> Word8 -> Char -> Char
mkChar a b' c =
toEnum $ fromIntegral $ a - b' + fromIntegral (fromEnum c)
colorRed :: Color
colorRed = Color 255 0 0
colorBlack :: Color
colorBlack = Color 0 0 0
-- CSS size wrappers
-- | Create a CSS size, e.g. $(mkSize "100px").
mkSize :: String -> ExpQ
mkSize s = appE nameE valueE
where [(value, unit)] = reads s :: [(Double, String)]
absoluteSizeE = varE $ mkName "absoluteSize"
nameE = case unit of
"cm" -> appE absoluteSizeE (conE $ mkName "Centimeter")
"em" -> conE $ mkName "EmSize"
"ex" -> conE $ mkName "ExSize"
"in" -> appE absoluteSizeE (conE $ mkName "Inch")
"mm" -> appE absoluteSizeE (conE $ mkName "Millimeter")
"pc" -> appE absoluteSizeE (conE $ mkName "Pica")
"pt" -> appE absoluteSizeE (conE $ mkName "Point")
"px" -> conE $ mkName "PixelSize"
"%" -> varE $ mkName "percentageSize"
_ -> error $ "In mkSize, invalid unit: " ++ unit
valueE = litE $ rationalL (toRational value)
-- | Absolute size units.
data AbsoluteUnit = Centimeter
| Inch
| Millimeter
| Pica
| Point
deriving (Eq, Show)
-- | Not intended for direct use, see 'mkSize'.
data AbsoluteSize = AbsoluteSize
{ absoluteSizeUnit :: AbsoluteUnit -- ^ Units used for text formatting.
, absoluteSizeValue :: Rational -- ^ Normalized value in centimeters.
}
-- | Absolute size unit convertion rate to centimeters.
absoluteUnitRate :: AbsoluteUnit -> Rational
absoluteUnitRate Centimeter = 1
absoluteUnitRate Inch = 2.54
absoluteUnitRate Millimeter = 0.1
absoluteUnitRate Pica = 12 * absoluteUnitRate Point
absoluteUnitRate Point = 1 / 72 * absoluteUnitRate Inch
-- | Constructs 'AbsoluteSize'. Not intended for direct use, see 'mkSize'.
absoluteSize :: AbsoluteUnit -> Rational -> AbsoluteSize
absoluteSize unit value = AbsoluteSize unit (value * absoluteUnitRate unit)
instance Show AbsoluteSize where
show (AbsoluteSize unit value') = printf "%f" value ++ suffix
where value = fromRational (value' / absoluteUnitRate unit) :: Double
suffix = case unit of
Centimeter -> "cm"
Inch -> "in"
Millimeter -> "mm"
Pica -> "pc"
Point -> "pt"
instance Eq AbsoluteSize where
(AbsoluteSize _ v1) == (AbsoluteSize _ v2) = v1 == v2
instance Ord AbsoluteSize where
compare (AbsoluteSize _ v1) (AbsoluteSize _ v2) = compare v1 v2
instance Num AbsoluteSize where
(AbsoluteSize u1 v1) + (AbsoluteSize _ v2) = AbsoluteSize u1 (v1 + v2)
(AbsoluteSize u1 v1) * (AbsoluteSize _ v2) = AbsoluteSize u1 (v1 * v2)
(AbsoluteSize u1 v1) - (AbsoluteSize _ v2) = AbsoluteSize u1 (v1 - v2)
abs (AbsoluteSize u v) = AbsoluteSize u (abs v)
signum (AbsoluteSize u v) = AbsoluteSize u (abs v)
fromInteger x = AbsoluteSize Centimeter (fromInteger x)
instance Fractional AbsoluteSize where
(AbsoluteSize u1 v1) / (AbsoluteSize _ v2) = AbsoluteSize u1 (v1 / v2)
fromRational x = AbsoluteSize Centimeter (fromRational x)
instance ToCss AbsoluteSize where
toCss = fromText . TS.pack . show
-- | Not intended for direct use, see 'mkSize'.
data PercentageSize = PercentageSize
{ percentageSizeValue :: Rational -- ^ Normalized value, 1 == 100%.
}
deriving (Eq, Ord)
-- | Constructs 'PercentageSize'. Not intended for direct use, see 'mkSize'.
percentageSize :: Rational -> PercentageSize
percentageSize value = PercentageSize (value / 100)
instance Show PercentageSize where
show (PercentageSize value') = printf "%f" value ++ "%"
where value = fromRational (value' * 100) :: Double
instance Num PercentageSize where
(PercentageSize v1) + (PercentageSize v2) = PercentageSize (v1 + v2)
(PercentageSize v1) * (PercentageSize v2) = PercentageSize (v1 * v2)
(PercentageSize v1) - (PercentageSize v2) = PercentageSize (v1 - v2)
abs (PercentageSize v) = PercentageSize (abs v)
signum (PercentageSize v) = PercentageSize (abs v)
fromInteger x = PercentageSize (fromInteger x)
instance Fractional PercentageSize where
(PercentageSize v1) / (PercentageSize v2) = PercentageSize (v1 / v2)
fromRational x = PercentageSize (fromRational x)
instance ToCss PercentageSize where
toCss = fromText . TS.pack . show
-- | Converts number and unit suffix to CSS format.
showSize :: Rational -> String -> String
showSize value' unit = printf "%f" value ++ unit
where value = fromRational value' :: Double
mkSizeType "EmSize" "em"
mkSizeType "ExSize" "ex"
mkSizeType "PixelSize" "px"