~alcinnz/CatTrap

972a1386b41bbece7d7b1493246a0266e9ef8088 — Adrian Cochrane 5 months ago 8fb3f54
Test flexbox pagination!
2 files changed, 378 insertions(+), 7 deletions(-)

M Graphics/Layout/Flex.hs
M test/Test.hs
M Graphics/Layout/Flex.hs => Graphics/Layout/Flex.hs +15 -5
@@ 64,6 64,7 @@ flexSumBasis :: FlexParent a Double -> Double
flexSumBasis self = maximum [Prelude.sum $
        intersperse (baseGap self) $ map basis row | row <- children self]

-- NOTE: shrink propery may yield negative sizes. Caller will want to enforce min-sizes.
flexWrap :: CastDouble b => FlexParent a b -> Double -> FlexParent a b
flexWrap self size
    | NoWrap <- wrap self = post self


@@ 75,9 76,15 @@ flexWrap self size
    }
    wrapRow :: CastDouble b => [FlexChild a b] -> [[FlexChild a b]]
    wrapRow [] = []
    wrapRow kids@(kid:_) = let (row, rest) = splitRow kids $ basis' kid
    wrapRow kids@(kid:_) = let (row, rest) = splitRow' kids $ basis' kid
        in row:wrapRow rest
    splitRow :: CastDouble b => [FlexChild a b] -> Double -> ([FlexChild a b], [FlexChild a b])
    splitRow, splitRow' :: CastDouble b => [FlexChild a b] -> Double ->
            ([FlexChild a b], [FlexChild a b])
    -- This wrapper function ensures we don't end up with empty rows, or infinite loops.
    splitRow' (kid:kids) end =
        let (kids', rest) = splitRow kids (end + baseGap' self + basis' kid)
        in (kid:kids', rest)
    splitRow' [] _ = ([], [])
    splitRow (kid:kids) end
        | end > size = ([], kid:kids)
        | otherwise = let (kids', rest) = splitRow kids (end + baseGap' self + basis' kid)


@@ 93,16 100,19 @@ flexWrap self size
    resizeRow :: CastDouble b => [FlexChild a b] -> [FlexChild a b]
    resizeRow row
        | rowSize > size = [kid {
                basis = fromDouble $ basis' kid - shrink kid * sfr
                basis = fromDouble $ basis' kid - shrink kid * nanguard sfr
            } | kid <- row]
        | rowSize < size = [kid {
                basis = fromDouble $ basis' kid + grow kid * gfr
                basis = fromDouble $ basis' kid + grow kid * nanguard gfr
            } | kid <- row]
        | otherwise = row
      where
        rowSize = Prelude.sum $ intersperse (baseGap' self) $ map basis' row
        sfr = (rowSize - size)/(Prelude.sum $ map shrink row)
        gfr = (size - rowSize)/(Prelude.sum $ map grow row)
        nanguard x | isNaN x = 0
            | isInfinite x = 0
            | otherwise = x
    baseGap' :: CastDouble b => FlexParent a b -> Double
    baseGap' = toDouble . baseGap
    basis' :: CastDouble b => FlexChild a b -> Double


@@ 207,7 217,7 @@ flexSplit cb h _ self@FlexParent { direction = Row, pageWidth = w } =
    self' = flexWrap self w
    (page0, page1) = splitRows (-crossGap self) $ children self
    splitRows start (row:rows)
        | start > h = ([row], rows)
        | start >= h = ([], row:rows)
        | otherwise =
            let (rows', rest) = flip splitRows rows $
                    start + crossGap self + flexRowSize (inline . cb) row

M test/Test.hs => test/Test.hs +363 -2
@@ 10,7 10,7 @@ import Stylist.Tree (StyleTree(..))
import Data.Maybe (fromJust)

import Graphics.Layout.Box as B
import Graphics.Layout.Grid
import Graphics.Layout.Grid as Grid
import Graphics.Layout.Flow
import Graphics.Layout



@@ 18,6 18,7 @@ import Graphics.Layout.CSS
import Graphics.Layout.Grid.Table
import Graphics.Layout.Inline.CSS
import Graphics.Layout.CSS.Font (placeholderFont)
import Graphics.Layout.Flex as Flex

import Data.Text.ParagraphLayout.Rich (constructParagraph,
        defaultParagraphOptions, defaultTextOptions,


@@ 360,7 361,7 @@ spec = do
            let defaultPageOptions = PageOptions 0 0 2 2
            let gridItem x y = GridItem {
                cellStart = x, cellEnd = y,
                alignment = Start,
                Grid.alignment = Start,
                minSize = 0, natSize = 0
              }
            let track cells' = Track {


@@ 410,6 411,366 @@ spec = do
                            LayoutFlow () lengthBox [inline "H"]
                        ]
                    ]
    describe "Flexbox" $ do
        it "wraps properly" $ do
            let child l = FlexChild {
                grow = 0,
                shrink = 0,
                basis = l,
                Flex.alignment = AlStart,
                flexInner = ()
              }
            let baseFlex = FlexParent {
                direction = Row,
                reverseRows = False,
                wrap = NoWrap,
                justify = JStart,
                alignLines = Just JStart,
                baseGap = 2,
                crossGap = 2,
                Flex.children = [[(child 10) { grow = 1 }, (child 20) { shrink = 1 },
                        (child 30) { grow = 2 }, (child 40) { shrink = 2 }]],
                pageWidth = 0
              } :: FlexParent () Double
            -- These test results don't look right...
            flexWrap baseFlex 50 `shouldBe` baseFlex {
                Flex.children = [[(child 10) { grow = 1 },
                        (child 1.3333333333333321) { shrink = 1 }, (child 30) { grow = 2 },
                        (child 2.6666666666666643) { shrink = 2}]]
              }
            flexWrap baseFlex 40 `shouldBe` baseFlex {
                Flex.children = [[(child 10) { grow = 1 },
                        (child $ -2) { shrink = 1 }, (child 30) { grow = 2 },
                        (child $ -4) { shrink = 2}]]
              }
            flexWrap baseFlex 30 `shouldBe` baseFlex {
                Flex.children = [[(child 10) { grow = 1 },
                        (child $ -5.333333333333332) { shrink = 1 }, (child 30) { grow = 2 },
                        (child $ -10.666666666666664) { shrink = 2}]]
              }
            flexWrap baseFlex 20 `shouldBe` baseFlex {
                Flex.children = [[(child 10) { grow = 1 },
                        (child $ -8.666666666666668) { shrink = 1 }, (child 30) { grow = 2 },
                        (child $ -17.333333333333336) { shrink = 2}]]
              }
            flexWrap baseFlex 10 `shouldBe` baseFlex {
                Flex.children = [[(child 10) { grow = 1 },
                        (child $ -12) { shrink = 1 }, (child 30) { grow = 2 },
                        (child $ -24) { shrink = 2}]]
              }
            flexWrap baseFlex { direction = Flex.Column } 50 `shouldBe` baseFlex {
                direction = Flex.Column,
                Flex.children = [[(child 10) { grow = 1 },
                        (child 1.3333333333333321) { shrink = 1 }, (child 30) { grow = 2 },
                        (child 2.6666666666666643) { shrink = 2}]]
              }
            flexWrap baseFlex { direction = Flex.Column } 40 `shouldBe` baseFlex {
                direction = Flex.Column,
                Flex.children = [[(child 10) { grow = 1 },
                        (child $ -2) { shrink = 1 }, (child 30) { grow = 2 },
                        (child $ -4) { shrink = 2}]]
              }
            flexWrap baseFlex { direction = Flex.Column } 30 `shouldBe` baseFlex {
                direction = Flex.Column,
                Flex.children = [[(child 10) { grow = 1 },
                        (child $ -5.333333333333332) { shrink = 1 }, (child 30) { grow = 2 },
                        (child $ -10.666666666666664) { shrink = 2}]]
              }
            flexWrap baseFlex { direction = Flex.Column } 20 `shouldBe` baseFlex {
                direction = Flex.Column,
                Flex.children = [[(child 10) { grow = 1 },
                        (child $ -8.666666666666668) { shrink = 1 }, (child 30) { grow = 2 },
                        (child $ -17.333333333333336) { shrink = 2}]]
              }
            flexWrap baseFlex { direction = Flex.Column } 10 `shouldBe` baseFlex {
                direction = Flex.Column,
                Flex.children = [[(child 10) { grow = 1 },
                        (child $ -12) { shrink = 1 }, (child 30) { grow = 2 },
                        (child $ -24) { shrink = 2}]]
              }
            flexWrap baseFlex { reverseRows = True } 50 `shouldBe` baseFlex {
                reverseRows = True,
                Flex.children = [[
                    FlexChild {
                        grow = 0.0,
                        shrink = 2.0,
                        basis = 2.6666666666666643,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                        grow = 2.0,
                        shrink = 0.0,
                        basis = 30.0,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                        grow = 0.0,
                        shrink = 1.0,
                        basis = 1.3333333333333321,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                       grow = 1.0,
                       shrink = 0.0,
                       basis = 10.0,
                       Flex.alignment = AlStart,
                       flexInner = ()
                    }
                ]]
              }
            flexWrap baseFlex { reverseRows = True } 40 `shouldBe` baseFlex {
                reverseRows = True,
                Flex.children = [[
                    FlexChild {
                        grow = 0.0,
                        shrink = 2.0,
                        basis = -4,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                        grow = 2.0,
                        shrink = 0.0,
                        basis = 30.0,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                        grow = 0.0,
                        shrink = 1.0,
                        basis = -2,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                       grow = 1.0,
                       shrink = 0.0,
                       basis = 10.0,
                       Flex.alignment = AlStart,
                       flexInner = ()
                    }
                ]]
            }
            flexWrap baseFlex { reverseRows = True } 30 `shouldBe` baseFlex {
                reverseRows = True,
                Flex.children = [[
                    FlexChild {
                        grow = 0.0,
                        shrink = 2.0,
                        basis = -10.666666666666664,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                        grow = 2.0,
                        shrink = 0.0,
                        basis = 30.0,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                        grow = 0.0,
                        shrink = 1.0,
                        basis = -5.333333333333332,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                       grow = 1.0,
                       shrink = 0.0,
                       basis = 10.0,
                       Flex.alignment = AlStart,
                       flexInner = ()
                    }
                ]]
            }
            flexWrap baseFlex { reverseRows = True } 20 `shouldBe` baseFlex {
                reverseRows = True,
                Flex.children = [[
                    FlexChild {
                        grow = 0.0,
                        shrink = 2.0,
                        basis = -17.333333333333336,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                        grow = 2.0,
                        shrink = 0.0,
                        basis = 30.0,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                        grow = 0.0,
                        shrink = 1.0,
                        basis = -8.666666666666668,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                       grow = 1.0,
                       shrink = 0.0,
                       basis = 10.0,
                       Flex.alignment = AlStart,
                       flexInner = ()
                    }
                ]]
              }
            flexWrap baseFlex { reverseRows = True } 10 `shouldBe` baseFlex {
                reverseRows = True,
                Flex.children = [[
                    FlexChild {
                        grow = 0.0,
                        shrink = 2.0,
                        basis = -24,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                        grow = 2.0,
                        shrink = 0.0,
                        basis = 30.0,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                        grow = 0.0,
                        shrink = 1.0,
                        basis = -12,
                        Flex.alignment = AlStart,
                        flexInner = ()
                    },
                    FlexChild {
                       grow = 1.0,
                       shrink = 0.0,
                       basis = 10.0,
                       Flex.alignment = AlStart,
                       flexInner = ()
                    }
                ]]
              }
            flexWrap baseFlex { wrap = Wrap } 50 `shouldBe` baseFlex {
                wrap = Wrap,
                Flex.children = [[(child 10) { grow = 1 },
                        (child 6) { shrink = 1 }, (child 30) { grow = 2 }], [
                        (child 40) { shrink = 2}]]
              }
            flexWrap baseFlex { wrap = Wrap } 40 `shouldBe` baseFlex {
                wrap = Wrap,
                Flex.children = [[(child 18) { grow = 1 },
                        (child 20) { shrink = 1 }], [(child 40) { grow = 2 }],
                        [(child 40) { shrink = 2}]]
              }
            flexWrap baseFlex { wrap = Wrap } 30 `shouldBe` baseFlex {
                wrap = Wrap,
                Flex.children = [[(child 10) { grow = 1 },
                        (child 18) { shrink = 1 }], [(child 30) { grow = 2 }],
                        [(child 30) { shrink = 2}]]
              }
            flexWrap baseFlex { wrap = Wrap } 20 `shouldBe` baseFlex {
                wrap = Wrap,
                Flex.children = [[(child 20) { grow = 1 }],
                        [(child 20) { shrink = 1 }], [(child 30) { grow = 2 }],
                        [(child 20) { shrink = 2}]]
              }
            flexWrap baseFlex { wrap = Wrap } 10 `shouldBe` baseFlex {
                wrap = Wrap,
                Flex.children = [[(child 10) { grow = 1 }], [(child 10) { shrink = 1 }],
                        [(child 30) { grow = 2 }], [(child 10) { shrink = 2}]]
              }
            flexWrap baseFlex { wrap = WrapReverse } 50 `shouldBe` baseFlex {
                wrap = WrapReverse,
                Flex.children = [[(child 40) { shrink = 2}], [(child 10) { grow = 1 },
                        (child 6) { shrink = 1 }, (child 30) { grow = 2 }]]
              }
            flexWrap baseFlex { wrap = WrapReverse } 40 `shouldBe` baseFlex {
                wrap = WrapReverse,
                Flex.children = [[(child 40) { shrink = 2}], [(child 40) { grow = 2 }],
                        [(child 18) { grow = 1 }, (child 20) { shrink = 1 }]]
              }
            flexWrap baseFlex { wrap = WrapReverse } 30 `shouldBe` baseFlex {
                wrap = WrapReverse,
                Flex.children = [[(child 30) { shrink = 2}], [(child 30) { grow = 2 }],
                        [(child 10) { grow = 1 }, (child 18) { shrink = 1 }]]
              }
            flexWrap baseFlex { wrap = WrapReverse } 20 `shouldBe` baseFlex {
                wrap = WrapReverse,
                Flex.children = [[(child 20) { shrink = 2}], [(child 30) { grow = 2 }],
                        [(child 20) { shrink = 1 }], [(child 20) { grow = 1 }]]
              }
            flexWrap baseFlex { wrap = WrapReverse } 10 `shouldBe` baseFlex {
                wrap = WrapReverse,
                Flex.children = [[(child 10) { shrink = 2}], [(child 30) { grow = 2 }],
                        [(child 10) { shrink = 1 }], [(child 10) { grow = 1 }]]
              }
        it "Paginates properly" $ do
            let child l align = FlexChild {
                grow = 0,
                shrink = 0,
                basis = l,
                Flex.alignment = align,
                flexInner = l
              }
            let baseFlex = FlexParent {
                direction = Row,
                reverseRows = False,
                wrap = Wrap,
                justify = JStart,
                alignLines = Just JStart,
                baseGap = 2,
                crossGap = 2,
                Flex.children = [[(child 10 AlStart) { grow = 1 },
                        (child 20 AlCenter) { shrink = 1 },
                        (child 30 AlEnd) { grow = 2 },
                        (child 40 AlStretch) { shrink = 2 }]],
                pageWidth = 80
              } :: FlexParent Double Double
            let self = flexWrap baseFlex 50
            self `shouldBe` baseFlex {
                Flex.children = [[(child 10 AlStart) { grow = 1 },
                        (child 6 AlCenter) { shrink = 1, flexInner = 20 },
                        (child 30 AlEnd) { grow = 2 }], [
                        (child 40 AlStretch) { shrink = 2}]]
              }
            flexSplit (\x -> Size x x) 30 50 self `shouldBe` (baseFlex {
                Flex.children = [[(child 10 AlStart) { grow = 1 },
                        (child 6 AlCenter) { shrink = 1, flexInner = 20 },
                        (child 30 AlEnd) { grow = 2 }]]
              }, baseFlex {
                Flex.children = [[(child 40 AlStretch) { shrink = 2}]]
              })
            print self { direction = Flex.Column }
            flexSplit (\x -> Size x x) 40 50 self { direction = Flex.Column } `shouldBe` (baseFlex {
                direction = Flex.Column,
                Flex.children = [[(child 10 AlStart) { grow = 1 },
                        (child (-4) AlCenter) { shrink = 1, flexInner = 20 },
                        (child 30 AlEnd) { grow = 2 }], [(child 40 AlStretch) { shrink = 2}]]
              }, baseFlex {
                direction = Flex.Column,
                Flex.children = []
              })
            flexSplit (\x -> Size x x) 10 50 self { direction = Flex.Column } `shouldBe` (baseFlex {
                direction = Flex.Column,
                Flex.children = []
              }, baseFlex {
                direction = Flex.Column,
                Flex.children = [[(child 10 AlStart) { grow = 1 },
                        (child 6 AlCenter) { shrink = 1, flexInner = 20 },
                        (child 30 AlEnd) { grow = 2 }], [(child 40 AlStretch) { shrink = 2}]]
              })
            flexSplit (\x -> Size x x) 10 50 self { direction = Flex.Column, pageWidth = 40 } `shouldBe` (baseFlex {
                Flex.children = [[(child 10 AlStart) { grow = 1 },
                        (child 6 AlCenter) { shrink = 1, flexInner = 20 },
                        (child 30 AlEnd) { grow = 2 }]],
                pageWidth = 40
              }, baseFlex {
                Flex.children = [[(child 40 AlStretch) { shrink = 2}]],
                pageWidth = 40
              })


runMath = flip evalCalc [] . mapCalc fst . flip parseCalc [] . filter (/= Whitespace) . tokenize