From b47a0b46c730af87d9231b13666ffb21c29e150f Mon Sep 17 00:00:00 2001 From: Adrian Cochrane Date: Sat, 4 Mar 2023 14:51:21 +1300 Subject: [PATCH] Unittest & fix abstract layout. --- Graphics/Layout.hs | 261 ++++++++++++++++++++++++++++++++++++++-- Graphics/Layout/Box.hs | 38 +++++- Graphics/Layout/Grid.hs | 29 +++-- test/Test.hs | 147 +++++++++++++++++++++- 4 files changed, 450 insertions(+), 25 deletions(-) diff --git a/Graphics/Layout.hs b/Graphics/Layout.hs index c42026d..89cfefc 100644 --- a/Graphics/Layout.hs +++ b/Graphics/Layout.hs @@ -1,21 +1,260 @@ +{-# LANGUAGE OverloadedStrings, RecordWildCards #-} module Graphics.Layout where -import Graphics.Layout.Box -import Graphics.Layout.Grid +import Graphics.Layout.Box as B +import Graphics.Layout.Grid as G +import Graphics.Layout.Flow as F + +import Data.Maybe (fromMaybe) data LayoutItem m n x = LayoutFlow x (PaddedBox m n) [LayoutItem m n x] | LayoutGrid x (Grid m n) [(GridItem m n, LayoutItem m n x)] -- More to come... -{-boxMinWidth :: Double -> LayoutItem y Length x -> (Double, LayoutItem y Length x) -boxNatWidth :: Double -> LayoutItem y Length x -> (Double, LayoutItem y Length x) -boxMaxWidth :: PaddedBox y Length -> LayoutItem y Length x -> (Double, LayoutItem y Length x) -boxWidth :: PaddedBox y Length -> LayoutItem y Length x -> (Double, LayoutItem y Double x) -boxNatHeight :: LayoutItem Length Double x -> (Double, LayoutItem Length Double x) +layoutGetBox (LayoutFlow _ ret _) = ret +layoutGetBox (LayoutGrid _ self _) = zero { + B.min = containerMin self, + B.size = containerSize self, + B.max = containerMax self +} +setCellBox' (child, cell) = cell { gridItemBox = layoutGetBox child } + +boxMinWidth :: Zero y => Maybe Double -> LayoutItem y Length x -> (Double, LayoutItem y Length x) +boxMinWidth parent (LayoutFlow val self childs) = (min', LayoutFlow val self' childs') + where + self' = self {B.min = Size (Pixels min') (block $ B.min self) } + min' = flowMinWidth parent' self childs'' + childs'' = map (mapX' $ lowerLength selfWidth) $ map layoutGetBox childs' + childs' = map snd $ map (boxMinWidth $ Just selfWidth) childs + selfWidth = width $ mapX' (lowerLength parent') self + parent' = fromMaybe 0 parent +boxMinWidth parent (LayoutGrid val self childs) = + (min', LayoutGrid val self' $ zip cells' childs') + where + self' = self { + containerMin = Size (Pixels min') (block $ containerMin self), + colBounds = zip cells (map snd (colBounds self) ++ repeat 0) + } + (min', cells) = gridMinWidths parent' self cells'' + cells'' = [ setCellBox (mapX' (lowerLength selfWidth) $ gridItemBox cell) cell + | cell <- cells'] + cells' = map setCellBox' $ zip childs' $ map fst childs + childs'' = map (mapX' $ lowerLength selfWidth) $ map layoutGetBox childs' + childs' = map snd $ map (boxMinWidth $ Just selfWidth) $ map snd childs + selfWidth = lowerLength parent' $ inline $ containerSize self + parent' = fromMaybe (gridEstWidth self [ + GridItem startRow endRow startCol endCol alignment zeroBox | + (GridItem {..}, _) <- childs]) parent + zeroBox :: PaddedBox Double Double + zeroBox = zero +boxNatWidth :: Zero y => Maybe Double -> LayoutItem y Length x -> (Double, LayoutItem y Length x) +boxNatWidth parent (LayoutFlow val self childs) = (size', LayoutFlow val self childs') + -- NOTE: Need to preserve auto/percentage in actual width calculation. + -- self' doesn't preserve this. CatTrap will need a decent refactor! + where + self' = self {size = Size (Pixels size') (block $ size self) } + size' = flowNatWidth parent' self childs'' + childs'' = map (mapX' $ lowerLength selfWidth) $ map layoutGetBox childs' + childs' = map snd $ map (boxNatWidth $ Just selfWidth) childs + selfWidth = width $ mapX' (lowerLength parent') self + parent' = fromMaybe 0 parent +boxNatWidth parent (LayoutGrid val self childs) = + (size', LayoutGrid val self' $ zip cells' childs') + where + self' = self { + containerSize = Size (Pixels size') (block $ containerSize self), + colBounds = zip (map fst (colBounds self) ++ repeat 0) cells + } + (size', cells) = gridNatWidths parent' self cells'' + cells'' = [ + cell { gridItemBox = mapX' (lowerLength selfWidth) $ gridItemBox cell } + | cell <- cells'] + cells' = map setCellBox $ zip childs' $ map fst childs + setCellBox (child, cell) = cell { gridItemBox = layoutGetBox child } + childs'' = map (mapX' $ lowerLength selfWidth) $ map layoutGetBox childs' + childs' = map snd $ map (boxNatWidth $ Just selfWidth) $ map snd childs + selfWidth = lowerLength parent' $ inline $ containerSize self + parent' = fromMaybe (gridEstWidth self [ + GridItem startRow endRow startCol endCol alignment zeroBox | + (GridItem {..}, _) <- childs]) parent + zeroBox :: PaddedBox Double Double + zeroBox = zero +boxMaxWidth :: PaddedBox a Double -> LayoutItem y Length x -> (Double, LayoutItem y Length x) +boxMaxWidth parent (LayoutFlow val self childs) = (max', LayoutFlow val self' childs) + where + self' = self { B.max = Size (Pixels max') (block $ B.max self) } + max' = flowMaxWidth parent self +boxMaxWidth parent (LayoutGrid val self childs) = + (max', LayoutGrid val self' childs) + where + self' = self { containerMax = Size (Pixels max') (block $ containerMax self) } + (max', _) = gridMaxWidths parent self $ colBounds self +boxWidth :: Zero y => PaddedBox b Double -> LayoutItem y Length x -> + (Double, LayoutItem y Double x) +boxWidth parent (LayoutFlow val self childs) = (size', LayoutFlow val self' childs') + where + childs' = map (snd . boxWidth self') childs + self' = (mapX' (lowerLength $ inline $ size parent) self) { + size = Size size' $ block $ B.max self + } + size' = flowWidth parent self +boxWidth parent (LayoutGrid val self childs) = (size', LayoutGrid val self' childs') + where + childs' = map recurse childs + recurse (cell, child) = (cell', child') + where + cell' = cell { gridItemBox = layoutGetBox child' } + (_, child') = boxWidth parent' child + parent' = zero { + B.min = containerMin self', + B.size = containerSize self', + B.max = containerMax self' + } + self' = Grid { + containerSize = Size size' $ block $ containerSize self, + containerMin = mapSizeX (lowerLength outerwidth) $ containerMin self, + containerMax = mapSizeX (lowerLength outerwidth) $ containerMax self, + gap = mapSizeX (lowerLength outerwidth) $ gap self, + columns = [("", Left width) | width <- widths], + + rows = rows self, + rowBounds = rowBounds self, + colBounds = colBounds self + } + outerwidth = inline $ size parent + (size', widths) = gridWidths parent self $ colBounds self + +boxNatHeight :: Double -> LayoutItem Length Double x -> (Double, LayoutItem Length Double x) +boxNatHeight parent (LayoutFlow val self childs) = (size', LayoutFlow val self' childs') + where + self' = self { + size = Size width (Pixels size') + } + size' = flowNatHeight parent self childs'' + childs'' = map (mapY' (lowerLength parent)) $ map layoutGetBox childs' + childs' = map snd $ map (boxNatHeight width) childs + width = inline $ size self +boxNatHeight parent (LayoutGrid val self childs) = + (size', LayoutGrid val self' $ zip cells childs') + where + self' = self { + containerSize = Size width $ Pixels size' + } + lowerGridUnit (Left length) = Left $ lowerLength width length + lowerGridUnit (Right x) = Right x + (size', heights) = gridNatHeights parent self cells' + cells' = [setCellBox (mapY' (lowerLength width) $ gridItemBox cell) cell | cell <- cells] + cells = map setCellBox' $ zip childs' $ map fst childs + childs' = map snd $ map (boxNatHeight width) $ map snd childs + width = inline $ containerSize self boxMinHeight :: Double -> LayoutItem Length Double x -> (Double, LayoutItem Length Double x) -boxMaxHeight :: Double -> LayoutItem Length Double x -> (Double, LayoutItem Length Double x) -boxHeight :: Double -> LayoutItem Length Double x -> (Double, LayoutItem Length Length x) -boxPosition :: LayoutItem Double Double x -> LayoutItem Double Double x +boxMinHeight parent (LayoutFlow val self childs) = (min', LayoutFlow val self' childs') + where + childs' = map snd $ map (boxMinHeight $ inline $ size self) childs + self' = self { + B.min = Size (inline $ B.min self) (Pixels min') + } + min' = flowMinHeight parent self +boxMinHeight parent (LayoutGrid val self childs) = (min', LayoutGrid val self' childs') + where + childs' = map recurse childs + recurse (cell, child) = (cell', child') + where + cell' = setCellBox (layoutGetBox child') cell + (_, child') = boxMinHeight width child + self' = self { + containerMin = Size width $ Pixels min', + rowBounds = zip heights (map snd (rowBounds self) ++ repeat 0) + } + (min', heights) = gridMinHeights width self childs0 + childs0 = [ GridItem { + gridItemBox = mapY' (lowerLength width) $ gridItemBox cell, + startRow = startRow cell, endRow = endRow cell, + startCol = startCol cell, endCol = endCol cell, alignment = alignment cell + } | (cell, _) <- childs] + width = inline $ containerSize self +boxMaxHeight :: PaddedBox Double Double -> LayoutItem Length Double x -> + (Double, LayoutItem Length Double x) +boxMaxHeight parent (LayoutFlow val self childs) = (max', LayoutFlow val self' childs') + where + childs' = map snd $ map (boxMaxHeight $ mapY' (lowerLength width) self') childs + self' = self { + B.max = Size (inline $ B.max self) (Pixels max') + } + max' = flowMaxHeight (inline $ size parent) self + width = inline $ size self +boxMaxHeight parent (LayoutGrid val self childs) = (max', LayoutGrid val self' childs') + where + childs' = map recurse childs + recurse (cell, child) = (cell', child') + where + cell' = setCellBox (layoutGetBox child') cell + (_, child') = boxMaxHeight parent' child + parent' :: PaddedBox Double Double + parent' = zero { + B.min = mapSizeY (lowerLength width) $ containerMin self, + B.size = mapSizeY (lowerLength width) $ containerSize self, + B.max = Size (inline $ containerMax self') max' + } + self' = self { + containerMax = Size (inline $ containerSize self) (Pixels max') + } + (max', heights) = gridMaxHeights parent self $ rowBounds self + width = inline $ size parent +boxHeight :: PaddedBox Double Double -> LayoutItem Length Double x -> + (Double, LayoutItem Double Double x) +boxHeight parent (LayoutFlow val self childs) = (size', LayoutFlow val self' childs') + where + childs' = map snd $ map (boxHeight self') childs + self' = (mapY' (lowerLength $ inline $ size parent) self) { + size = Size (inline $ size self) size' + } + size' = flowHeight parent self + width = inline $ size self +boxHeight parent (LayoutGrid val self childs) = (size', LayoutGrid val self' childs') + where + childs' = map recurse childs + recurse (cell, child) = (cell', child') + where + cell' = setCellBox (layoutGetBox child') cell + (_, child') = boxHeight (layoutGetBox $ LayoutGrid val self' []) child + self' = Grid { + containerSize = Size (inline $ containerSize self) size', + containerMin = mapSizeY (lowerLength width) $ containerMin self, + containerMax = mapSizeY (lowerLength width) $ containerMax self, + gap = mapSizeY (lowerLength width) $ gap self, + + rows = map lowerSize $ rows self, rowBounds = rowBounds self, + columns = columns self, colBounds = colBounds self + } + (size', heights) = gridHeights parent self $ rowBounds self + lowerSize (n, Left x) = (n, Left $ lowerLength width x) + lowerSize (n, Right x) = (n, Right x) + width = inline $ size parent + +boxPosition :: (Double, Double) -> LayoutItem Double Double x -> + LayoutItem Double Double ((Double, Double), x) +boxPosition pos@(x, y) (LayoutFlow val self childs) = LayoutFlow (pos, val) self childs' + where + childs' = map recurse $ zip pos' childs + recurse ((Size x' y'), child) = boxPosition (x + x', y + y') child + pos' = positionFlow $ map layoutGetBox childs +boxPosition pos@(x, y) (LayoutGrid val self childs) = LayoutGrid (pos, val) self childs' + where + childs' = map recurse $ zip pos' childs + recurse ((Size x' y'), (cell, child)) = (cell, boxPosition (x + x', y + y') child) + pos' = gridPosition self $ map fst childs boxLayout :: PaddedBox Double Double -> LayoutItem Length Length x -> Bool -> - LayoutItem Double Double x-} + LayoutItem Double Double ((Double, Double), x) +boxLayout parent self paginate = self8 + where + (_, self0) = boxMinWidth Nothing self + (_, self1) = boxNatWidth Nothing self0 + (_, self2) = boxMaxWidth parent self1 + (_, self3) = boxWidth parent self2 + (natsize, self4) = boxNatHeight (inline $ size parent) self3 + (_, self5) = boxMinHeight natsize self4 + (_, self6) = boxMaxHeight parent self5 + (_, self7) = boxHeight parent self6 + self8 = boxPosition (0, 0) self7 diff --git a/Graphics/Layout/Box.hs b/Graphics/Layout/Box.hs index 44877e4..c337314 100644 --- a/Graphics/Layout/Box.hs +++ b/Graphics/Layout/Box.hs @@ -10,6 +10,8 @@ mapX cb self = self { left = cb $ left self, right = cb $ right self } mapY cb self = self { top = cb $ top self, bottom = cb $ bottom self } data Size m n = Size {inline :: n, block :: m} deriving (Eq, Show) +mapSizeY cb self = Size (inline self) (cb $ block self) +mapSizeX cb self = Size (cb $ inline self) (block self) data PaddedBox m n = PaddedBox { min :: Size m n, @@ -35,7 +37,26 @@ lengthBox = PaddedBox { padding = Border zero zero zero zero, border = Border zero zero zero zero, margin = Border zero zero zero zero - } where zero = Pixels 0 + } + +mapX' :: (n -> nn) -> PaddedBox m n -> PaddedBox m nn +mapX' cb PaddedBox {..} = PaddedBox { + min = Size (cb $ inline min) (block min), + size = Size (cb $ inline size) (block size), + max = Size (cb $ inline max) (block max), + padding = mapX cb padding, + border = mapX cb border, + margin = mapX cb margin + } +mapY' :: (m -> mm) -> PaddedBox m n -> PaddedBox mm n +mapY' cb PaddedBox {..} = PaddedBox { + min = Size (inline min) (cb $ block min), + size = Size (inline size) (cb $ block size), + max = Size (inline max) (cb $ block max), + padding = mapY cb padding, + border = mapY cb border, + margin = mapY cb margin + } width PaddedBox {..} = left margin + left border + left padding + inline size + right padding + right border + right margin @@ -56,3 +77,18 @@ lowerLength :: Double -> Length -> Double lowerLength _ (Pixels x) = x lowerLength outerwidth (Percent x) = x * outerwidth lowerLength _ _ = 0 + +class Zero a where + zero :: a + +instance Zero Double where zero = 0 +instance Zero Length where zero = Pixels 0 +instance (Zero m, Zero n) => Zero (PaddedBox m n) where + zero = PaddedBox { + min = Size zero zero, + max = Size zero zero, + size = Size zero zero, + padding = Border zero zero zero zero, + border = Border zero zero zero zero, + margin = Border zero zero zero zero + } diff --git a/Graphics/Layout/Grid.hs b/Graphics/Layout/Grid.hs index 66fd35c..6bb3ad2 100644 --- a/Graphics/Layout/Grid.hs +++ b/Graphics/Layout/Grid.hs @@ -14,7 +14,9 @@ data Grid m n = Grid { columns :: [(Name, Either n Double)], colBounds :: [(Double, Double)], gap :: Size m n, - containerSize :: Size m n -- wrap in a Flow box to get padding, etc. + containerSize :: Size m n, -- wrap in a Flow box to get padding, etc. + containerMin :: Size m n, + containerMax :: Size m n } data GridItem m n = GridItem { startRow :: Int, endRow :: Int, startCol :: Int, endCol :: Int, @@ -31,8 +33,13 @@ buildGrid rows columns = Grid { columns = zip (repeat "") columns, colBounds = [], gap = Size (Pixels 0) (Pixels 0), - containerSize = Size Auto Auto + containerSize = Size Auto Auto, + containerMin = Size Auto Auto, + containerMax = Size Auto Auto } +-- Created to address typesystem issues with record syntax. +setCellBox :: PaddedBox mm nn -> GridItem m n -> GridItem mm nn +setCellBox box' GridItem {..} = GridItem startRow endRow startCol endCol alignment box' cellsForCol :: [GridItem y x] -> Int -> [GridItem y x] cellsForCol cells ix = @@ -109,11 +116,6 @@ gridWidths parent self subwidths = colWidth' fr ((_, nat), Left Auto) = Prelude.min nat fr colWidth' fr (_, Right x) = x*fr -gridEstHeight :: Grid Length Double -> [GridItem Double Double] -> Double -gridEstHeight self childs = fst $ gridMaxHeights zeroBox self $ zip mins nats - where - mins = snd $ gridMinHeights 0 self childs - nats = snd $ gridNatHeights 0 self childs gridNatHeights :: Double -> Grid Length Double -> [GridItem Double Double] -> (Double, [Double]) gridNatHeights parent self childs = (sum $ intersperse (lowerLength parent $ block $ gap self) ret, ret) @@ -202,21 +204,24 @@ gridLayout parent self childs paginate = (self', zip positions childs) columns = zip (map fst $ rows self) $ map Left cols', colBounds = colBounds', gap = Size (lowerLength width' gapX) (lowerLength width' gapY), - containerSize = Size width' height' + containerSize = Size width' height', + containerMin = Size width' height', + containerMax = Size width' height' } Size gapX gapY = gap self (height', rows') = gridHeights parent self0 rowBounds' rowBounds' = zip rowMins rowNats - (_, rowMins) = gridMinHeights estHeight self0 childs - (_, rowNats) = gridNatHeights estHeight self0 childs - estHeight = gridEstHeight self0 childs + (_, rowMins) = gridMinHeights width' self0 childs + (_, rowNats) = gridNatHeights width' self0 childs self0 = self { columns = zip (map fst $ columns self) $ map Left cols', colBounds = colBounds', gap = Size (lowerLength width' gapX) gapY, - containerSize = let Size _ y = containerSize self in Size width' y + containerSize = let Size _ y = containerSize self in Size width' y, + containerMin = let Size _ y = containerSize self in Size width' y, + containerMax = let Size _ y = containerSize self in Size width' y } (width', cols') = gridWidths parent self colBounds' colBounds' = zip colMins colNats diff --git a/test/Test.hs b/test/Test.hs index 38231fd..7ab08cf 100644 --- a/test/Test.hs +++ b/test/Test.hs @@ -5,9 +5,11 @@ import Test.Hspec import Graphics.Layout.Arithmetic import Data.CSS.Syntax.Tokens (tokenize, Token(..)) + import Graphics.Layout.Box as B import Graphics.Layout.Grid import Graphics.Layout.Flow +import Graphics.Layout main :: IO () main = hspec spec @@ -25,7 +27,7 @@ spec = do runMath "6 * (9 - 42)" `shouldBe` -198 runMath "6 * calc(9 - 42)" `shouldBe` -198 runMath "6 * abs(9 - 42)" `shouldBe` 198 - describe "Width sizing" $ do + describe "Flow sizing" $ do -- Based on http://hixie.ch/tests/adhoc/css/box/block/ it "Can overflow parent" $ do width (fst $ layoutFlow zeroBox { @@ -62,6 +64,13 @@ spec = do margin = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2), size = Size Auto $ Pixels 1 } [] False) `shouldBe` 5 + it "Fits children" $ do + let child = mapX' (lowerLength 100) $ lengthBox { + size = Size (Pixels 10) (Pixels 10) + } + height (fst $ layoutFlow zeroBox { + size = Size 100 100 + } lengthBox [child, child] False) `shouldBe` 20 it "Collapses margins" $ do let a :: PaddedBox Length Double a = PaddedBox { @@ -134,5 +143,141 @@ spec = do }] True containerSize minGrid `shouldBe` Size 10 10 fst (head minCells) `shouldBe` Size 0 0 + describe "Abstract layout" $ do + it "Can overflow parent" $ do + width (layoutGetBox $ boxLayout zeroBox { + size = Size 3 1 + } (LayoutFlow () lengthBox { + border = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2) + } []) False) `shouldBe` 4 + height (layoutGetBox $ boxLayout zeroBox { + size = Size 3 1 + } (LayoutFlow () lengthBox { + border = Border (Pixels 2) (Pixels 2) (Pixels 2) (Pixels 2) + } []) False) `shouldBe` 4 + width (layoutGetBox $ boxLayout zeroBox { + size = Size 3 1 + } (LayoutFlow () lengthBox { + padding = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2) + } []) False) `shouldBe` 4 + height (layoutGetBox $ boxLayout zeroBox { + size = Size 3 1 + } (LayoutFlow () lengthBox { + padding = Border (Pixels 2) (Pixels 2) (Pixels 2) (Pixels 2) + } []) False) `shouldBe` 4 + width (layoutGetBox $ boxLayout zeroBox { + size = Size 3 1 + } (LayoutFlow () lengthBox { + margin = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2) + } []) False) `shouldBe` 4 + height (layoutGetBox $ boxLayout zeroBox { + size = Size 3 1 + } (LayoutFlow () lengthBox { + margin = Border (Pixels 2) (Pixels 2) (Pixels 2) (Pixels 2) + } []) False) `shouldBe` 4 + it "Fits to parent" $ do + width (layoutGetBox $ boxLayout zeroBox { + size = Size 5 1 + } (LayoutFlow () lengthBox { + border = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2), + size = Size Auto $ Pixels 1 + } []) False) `shouldBe` 5 + width (layoutGetBox $ boxLayout zeroBox { + size = Size 5 1 + } (LayoutFlow () lengthBox { + padding = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2), + size = Size Auto $ Pixels 1 + } []) False) `shouldBe` 5 + width (layoutGetBox $ boxLayout zeroBox { + size = Size 5 1 + } (LayoutFlow () lengthBox { + margin = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2), + size = Size Auto $ Pixels 1 + } []) False) `shouldBe` 5 + it "Fits children" $ do + let child = LayoutFlow () lengthBox { + size = Size (Pixels 10) (Pixels 10), + B.max = Size (Pixels 10) (Pixels 10) + } [] + height (layoutGetBox $ boxLayout zeroBox { + size = Size 100 100 + } child False) `shouldBe` 10 + height (layoutGetBox $ boxLayout zeroBox { + size = Size 100 100 + } (LayoutFlow () lengthBox [child, child]) False) `shouldBe` 20 + it "Collapses margins" $ do + let a :: LayoutItem Length Length () + a = LayoutFlow () PaddedBox { + B.min = Size Auto Auto, + size = Size Auto Auto, + B.max = Size Auto Auto, + padding = Border (Pixels 0) (Pixels 0) (Pixels 0) (Pixels 0), + border = Border (Pixels 0) (Pixels 0) (Pixels 0) (Pixels 0), + margin = Border (Pixels 5) (Pixels 10) (Pixels 0) (Pixels 0) + } [] + b :: LayoutItem Length Length () + b = LayoutFlow () PaddedBox { + B.min = Size Auto Auto, + size = Size Auto Auto, + B.max = Size Auto Auto, + padding = Border (Pixels 0) (Pixels 0) (Pixels 0) (Pixels 0), + border = Border (Pixels 0) (Pixels 0) (Pixels 0) (Pixels 0), + margin = Border (Pixels 10) (Pixels 5) (Pixels 0) (Pixels 0) + } [] + height (layoutGetBox $ boxLayout zeroBox { + size = Size 100 100 + } (LayoutFlow () lengthBox [a, a]) False) `shouldBe` 25 + height (layoutGetBox $ boxLayout zeroBox { + size = Size 100 100 + } (LayoutFlow () lengthBox [b, b]) False) `shouldBe` 25 + height (layoutGetBox $ boxLayout zeroBox { + size = Size 100 100 + } (LayoutFlow () lengthBox [a, b]) False) `shouldBe` 20 + height (layoutGetBox $ boxLayout zeroBox { + size = Size 100 100 + } (LayoutFlow () lengthBox [b, a]) False) `shouldBe` 25 + + it "computes single-columns widths/heights" $ do + let zeroCell = LayoutFlow () lengthBox [] + let nonzeroCell = LayoutFlow () lengthBox { + B.min = Size (Pixels 10) (Pixels 10), + size = Size (Pixels 20) (Pixels 20) + } [] + + let LayoutGrid (_, _) pxGrid pxCells = boxLayout zeroBox { + size = Size 100 100 + } (LayoutGrid () (buildGrid [Left $ Pixels 10] [Left $ Pixels 10]) + [(GridItem 0 1 0 1 (Size Start Start) lengthBox, zeroCell)]) True + let LayoutFlow (pos, _) _ _ = snd $ head pxCells + containerSize pxGrid `shouldBe` Size 10 10 + pos `shouldBe` (0, 0) + let LayoutGrid (_, _) pxGrid pxCells = boxLayout zeroBox { + size = Size 100 100 + } (LayoutGrid () (buildGrid [Left $ Percent 0.5] [Left $ Percent 0.5]) + [(GridItem 0 1 0 1 (Size Start Start) lengthBox, zeroCell)]) True + let LayoutFlow (pos, _) _ _ = snd $ head pxCells + containerSize pxGrid `shouldBe` Size 50 50 + pos `shouldBe` (0, 0) + let LayoutGrid (_, _) pxGrid pxCells = boxLayout zeroBox { + size = Size 100 100 + } (LayoutGrid () (buildGrid [Left Auto] [Left Auto]) + [(GridItem 0 1 0 1 (Size Start Start) lengthBox, nonzeroCell)]) True + let LayoutFlow (pos, _) _ _ = snd $ head pxCells + containerSize pxGrid `shouldBe` Size 20 10 -- FIXME Is the 10 correct? + pos `shouldBe` (0, 0) + let LayoutGrid (_, _) pxGrid pxCells = boxLayout zeroBox { + size = Size 100 100 + } (LayoutGrid () (buildGrid [Left Preferred] [Left Preferred]) + [(GridItem 0 1 0 1 (Size Start Start) lengthBox, nonzeroCell)]) True + let LayoutFlow (pos, _) _ _ = snd $ head pxCells + containerSize pxGrid `shouldBe` Size 20 0 -- FIXME Is the 0 correct? + pos `shouldBe` (0, 0) + let LayoutGrid (_, _) pxGrid pxCells = boxLayout zeroBox { + size = Size 100 100 + } (LayoutGrid () (buildGrid [Left Min] [Left Min]) + [(GridItem 0 1 0 1 (Size Start Start) lengthBox, nonzeroCell)]) True + let LayoutFlow (pos, _) _ _ = snd $ head pxCells + containerSize pxGrid `shouldBe` Size 10 10 + pos `shouldBe` (0, 0) runMath = flip evalCalc [] . mapCalc fst . flip parseCalc [] . filter (/= Whitespace) . tokenize -- 2.30.2