~alcinnz/CatTrap

ref: 878e6868a7d2cbc0d08ebd81185775e1bbac1ca6 CatTrap/Graphics/Layout/Grid/Table.hs -rw-r--r-- 5.5 KiB
878e6868 — Adrian Cochrane Parse & apply CSS <table>-styling properties. 11 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
{-# 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