{-# LANGUAGE OverloadedStrings, ViewPatterns #-}
module Graphics.Layout.Grid.Table where
import Data.CSS.Syntax.Tokens (Token(..), NumericValue(..))
import Stylist (PropertyParser(..))
import Graphics.Layout.CSS.Length (Unitted, parseLength, Font', finalizeLength)
import Graphics.Layout.Box (Length(..), PaddedBox(..), zero, mapX, mapY)
import Graphics.Layout.Grid (Alignment(..))
import Data.Text.Glyphize (Direction(..))
import Data.Text.ParagraphLayout.Rich (
ParagraphOptions(..), ParagraphAlignment(..))
import Text.Read (readMaybe)
import Data.Text (unpack)
type Overflowed = [Int]
emptyRow :: Overflowed
emptyRow = []
commitRow :: Overflowed -> Overflowed
commitRow = map $ Prelude.max 0 . pred
allocCol :: Int -> Overflowed -> Int
allocCol ix cols = ix + length (span (> 0) $ drop ix cols)
insertCell :: Int -> Int -> Int -> Overflowed -> Overflowed
insertCell ix colspan rowspan cols =
before ++ replicate colspan rowspan ++ drop colspan after
where (before, after) = splitAt ix cols
data TableOptions = TableOptions {
-- | HTML rowspan attribute
rowspan :: Int,
-- | HTML colspan attribute
colspan :: Int,
-- | Parsed CSS caption-side.
captionBelow :: Bool,
-- | Parsed CSS border-collapse
borderCollapse :: Bool,
-- | Semi-parsed border-spacing, horizontal axis
borderHSpacing :: Unitted,
-- | Semi-parsed border-spacing, vertical axis
borderVSpacing :: Unitted,
-- TODO: Implement `table-layout: fixed`, that needs its own layout formula...
-- | Parsed CSS vertical-align
verticalAlign :: Unitted
}
instance PropertyParser TableOptions where
temp = TableOptions {
rowspan = 1, colspan = 1,
captionBelow = False, borderCollapse = False,
borderHSpacing = (0,"px"), borderVSpacing = (0,"px"),
verticalAlign = (0,"baseline")
}
inherit = id
longhand _ self "-argo-rowspan" [Ident "initial"] = Just self { rowspan = 1 }
longhand _ self "-argo-rowspan" [String x]
| Just y <- readMaybe $ unpack x, y >= 1 = Just self { rowspan = y }
longhand _ self "-argo-rowspan" [Number _ (NVInteger x)]
| x >= 1 = Just self { rowspan = fromEnum x }
longhand _ self "-argo-colspan" [Ident "initial"] = Just self { colspan = 1 }
longhand _ self "-argo-colspan" [String x]
| Just y <- readMaybe $ unpack x, y >= 1 = Just self { colspan = y }
longhand _ self "-argo-colspan" [Number _ (NVInteger x)]
| x >= 1 = Just self { colspan = fromEnum x }
longhand _ self "caption-side" [Ident "top"] = Just self { captionBelow = False }
longhand _ self "caption-side" [Ident "bottom"] = Just self { captionBelow = True }
longhand _ self "caption-side" [Ident "initial"] = Just self {captionBelow = False}
longhand _ self "border-collapse" [Ident "collapse"] =
Just self { borderCollapse = True }
longhand _ self "border-collapse" [Ident "separate"] =
Just self { borderCollapse = False }
longhand _ self "border-collapse" [Ident "initial"] =
Just self { borderCollapse = False }
longhand _ self "border-spacing" v@[Dimension _ _ _] | Just x <- parseLength v =
Just self { borderHSpacing = x, borderVSpacing = x }
longhand _ self "border-spacing" [x@(Dimension _ _ _), y@(Dimension _ _ _)]
| Just x' <- parseLength [x], Just y' <- parseLength [y] =
Just self { borderHSpacing = x', borderVSpacing = y' }
longhand _ self "border-spacing" [Ident "initial"] =
Just self { borderHSpacing = (0,"px"), borderVSpacing = (0,"px") }
longhand _ self "vertical-align" [Ident x]
| x `elem` ["baseline", "sub", "super", "text-top", "text-bottom",
"middle", "top", "bottom"] = Just self { verticalAlign = (0,x) }
| x == "initial" = Just self { verticalAlign = (0,"baseline") }
| otherwise = Nothing
longhand _ self "vertical-align" v | Just x <- parseLength v =
Just self { verticalAlign = x }
longhand _ _ _ _ = Nothing
finalizeGap :: TableOptions -> Font' -> (Length, Length)
finalizeGap TableOptions { borderCollapse = True } _ = (Pixels 0, Pixels 0)
finalizeGap TableOptions { borderHSpacing = x, borderVSpacing = y } font =
(finalizeLength x font, finalizeLength y font)
type UPaddedBox = PaddedBox Unitted Unitted
collapseBorders :: TableOptions -> UPaddedBox -> UPaddedBox
collapseBorders TableOptions { borderCollapse = False } ret = ret
collapseBorders _ box = box {
margin = zero,
border = mapX half $ mapY half $ border box
}
collapseTBorders :: TableOptions -> UPaddedBox -> UPaddedBox
collapseTBorders TableOptions { borderCollapse = False } ret = ret
collapseTBorders _ box = box {
padding = zero,
border = mapX half $ mapY half $ border box
}
half (x,u) = (x/2,u)
finalizeVAlign :: TableOptions -> Alignment
finalizeVAlign TableOptions { verticalAlign = (_,"top") } = Start
finalizeVAlign TableOptions { verticalAlign = (_,"middle") } = Mid
finalizeVAlign TableOptions { verticalAlign = (_,"bottom") } = End
finalizeVAlign _ = Start -- FIXME: Support baseline alignment!
finalizeHAlign :: ParagraphOptions -> Direction -> Alignment
finalizeHAlign (paragraphAlignment -> AlignStart) _ = Start
finalizeHAlign (paragraphAlignment -> AlignEnd) _ = End
finalizeHAlign (paragraphAlignment -> AlignLeft) DirLTR = Start
finalizeHAlign (paragraphAlignment -> AlignLeft) _ = End
finalizeHAlign (paragraphAlignment -> AlignRight) DirLTR = End
finalizeHAlign (paragraphAlignment -> AlignRight) _ = Start
finalizeHAlign (paragraphAlignment -> AlignCentreH) _ = Mid