~alcinnz/CatTrap

f7444393d107bb90a9d4000994ae4cd0e5aac2b9 — Adrian Cochrane 1 year, 8 months ago 85d144a
Refactor grid sizes to be dynamically computed.
4 files changed, 85 insertions(+), 108 deletions(-)

M Graphics/Layout.hs
M Graphics/Layout/Box.hs
M Graphics/Layout/Grid.hs
M Graphics/Layout/Grid/CSS.hs
M Graphics/Layout.hs => Graphics/Layout.hs +22 -57
@@ 37,9 37,9 @@ layoutGetBox :: (Zero m, Zero n, CastDouble m, CastDouble n) =>
        LayoutItem m n x -> PaddedBox m n
layoutGetBox (LayoutFlow _ ret _) = ret
layoutGetBox (LayoutGrid _ self _) = zero {
    B.min = containerMin self,
    B.size = containerSize self,
    B.max = containerMax self
    B.min = Size (fromDouble $ gridMinWidth toDouble self) (fromDouble $ gridMinHeight toDouble self),
    B.size = Size (fromDouble $ gridNatWidth toDouble self) (fromDouble $ gridNatHeight toDouble self),
    B.max = Size (fromDouble $ gridNatWidth toDouble self) (fromDouble $ gridNatHeight toDouble self)
}
layoutGetBox (LayoutInline _ f self _ _) = zero {
    B.min = inlineMin f self, B.size = inlineSize f self, B.max = inlineSize f self


@@ 77,17 77,14 @@ boxMinWidth parent (LayoutFlow val self childs) = LayoutFlow val self' childs'
    parent' = fromMaybe 0 parent
boxMinWidth parent (LayoutGrid val self childs) = 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)
      }
    self' = self { colMins = cells }
    (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 (boxMinWidth $ Just selfWidth) $ map snd childs
    selfWidth = lowerLength parent' $ inline $ containerSize self
    selfWidth = gridNatWidth (lowerLength parent') self
    parent' = fromMaybe (gridEstWidth self [
        GridItem startRow endRow startCol endCol alignment zeroBox |
        (GridItem {..}, _) <- childs]) parent


@@ 108,10 105,7 @@ boxNatWidth parent (LayoutFlow val self childs) = LayoutFlow val self' childs'
    parent' = fromMaybe 0 parent
boxNatWidth parent (LayoutGrid val self childs) = 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
      }
    self' = self { colNats = cells }
    (size', cells) = gridNatWidths parent' self cells''
    cells'' = [
        cell { gridItemBox = mapX' (lowerLength selfWidth) $ gridItemBox cell }


@@ 120,7 114,7 @@ boxNatWidth parent (LayoutGrid val self childs) = LayoutGrid val self' $ zip cel
    setCellBox (child, cell) = cell { gridItemBox = layoutGetBox child }
    childs'' = map (mapX' $ lowerLength selfWidth) $ map layoutGetBox childs'
    childs' = map (boxNatWidth $ Just selfWidth) $ map snd childs
    selfWidth = lowerLength parent' $ inline $ containerSize self
    selfWidth = gridNatWidth (lowerLength parent') self
    parent' = fromMaybe (gridEstWidth self [
        GridItem startRow endRow startCol endCol alignment zeroBox |
        (GridItem {..}, _) <- childs]) parent


@@ 136,10 130,7 @@ boxMaxWidth parent (LayoutFlow val self childs) = LayoutFlow val self' childs'
    self'' = mapX' (lowerLength $ inline $ B.size parent) self'
    self' = self { B.max = Size (Pixels max') (block $ B.max self) }
    max' = flowMaxWidth parent self
boxMaxWidth parent (LayoutGrid val self childs) = LayoutGrid val self' childs
  where
    self' = self { containerMax = Size (Pixels max') (block $ containerMax self) }
    (max', _) = gridMaxWidths parent self $ colBounds self
boxMaxWidth parent (LayoutGrid val self childs) = LayoutGrid val self childs
boxMaxWidth parent self@(LayoutInline _ _ _ _ _) = self
boxMaxWidth parent self@(LayoutInline' _ _ _ _ _) = self
boxMaxWidth parent self@(LayoutSpan _ f self') = self


@@ 158,26 149,18 @@ boxWidth parent (LayoutGrid val self childs) = LayoutGrid val self' 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'
          }
        child' = boxWidth (mapX' (lowerLength size') $ gridItemBox cell) child
    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 = map Left widths,

        rows = rows self,
        rowBounds = rowBounds self,
        colBounds = colBounds self,
        rowMins = rowMins self, rowNats = rowNats self,
        colMins = colMins self, colNats = colNats self,
        subgridRows = subgridRows self, subgridColumns = subgridColumns self
      }
    outerwidth = inline $ size parent
    (size', widths) = gridWidths parent self $ colBounds self
    (size', widths) = gridWidths parent self (colMins self) (colNats self)
boxWidth parent (LayoutInline val font (Paragraph a b c d) paging vals) =
    LayoutInline val font (Paragraph a b c d { paragraphMaxWidth = round width }) paging vals
  where width = B.inline $ B.size parent


@@ 191,18 174,15 @@ boxNatHeight parent (LayoutFlow val self childs) = LayoutFlow val self' childs'
    size' = flowNatHeight parent self childs''
    childs'' = map (mapY' (lowerLength parent)) $ map layoutGetBox childs'
    childs' = map (boxNatHeight $ inline $ size self) childs
boxNatHeight parent (LayoutGrid val self childs) = LayoutGrid val self' $ zip cells childs'
boxNatHeight parent (LayoutGrid val self childs) = 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 (boxNatHeight width) $ map snd childs
    width = inline $ containerSize self
    width = gridNatWidth id self
boxNatHeight parent self@(LayoutInline _ _ _ _ _) = self
boxNatHeight parent self@(LayoutInline' _ _ _ _ _) = self
boxNatHeight parent self@(LayoutSpan _ _ _) = self


@@ 219,17 199,14 @@ boxMinHeight parent (LayoutGrid val self childs) = LayoutGrid val self' childs'
      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)
      }
    self' = self { rowMins = heights }
    (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
    width = gridNatWidth id self
boxMinHeight parent self@(LayoutInline _ _ _ _ _) = self
boxMinHeight _ self@(LayoutInline' _ _ _ _ _) = self
boxMinHeight parent self@(LayoutSpan _ font self') = self


@@ 241,23 218,14 @@ boxMaxHeight parent (LayoutFlow val self childs) = LayoutFlow val 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) = LayoutGrid val self' childs'
boxMaxHeight parent (LayoutGrid val self childs) = 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
        child' = boxMaxHeight (mapY' (lowerLength width) $ gridItemBox cell) child
    (max', heights) = gridMaxHeights parent self (rowMins self) (rowNats self)
    width = inline $ size parent
boxMaxHeight parent (LayoutInline val font self' paging vals) =
    LayoutInline val font self' paging vals


@@ 281,16 249,13 @@ boxHeight parent (LayoutGrid val self childs) = LayoutGrid val self' childs'
        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,
        rows = map lowerSize $ rows self, rowMins = rowMins self, rowNats = rowNats self,
        columns = columns self, colMins = colMins self, colNats = colNats self,
        subgridRows = subgridRows self, subgridColumns = subgridColumns self
      }
    (size', heights) = gridHeights parent self $ rowBounds self
    (size', heights) = gridHeights parent self (rowMins self) (rowNats self)
    lowerSize (Left x) = Left $ lowerLength width x
    lowerSize (Right x) = Right x
    width = inline $ size parent

M Graphics/Layout/Box.hs => Graphics/Layout/Box.hs +10 -5
@@ 97,13 97,18 @@ instance (Zero m, Zero n) => Zero (PaddedBox m n) where
        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
        padding = Border zero zero zero zero,
        border = Border zero zero zero zero,
        margin = Border zero zero zero zero
    }

class CastDouble a where
    fromDouble :: Double -> a
    toDouble :: a -> Double

instance CastDouble Double where fromDouble = id
instance CastDouble Length where fromDouble = Pixels
instance CastDouble Double where
    fromDouble = id
    toDouble = id
instance CastDouble Length where
    fromDouble = Pixels
    toDouble = lowerLength 0

M Graphics/Layout/Grid.hs => Graphics/Layout/Grid.hs +50 -40
@@ 1,6 1,7 @@
{-# LANGUAGE RecordWildCards, OverloadedStrings #-}
module Graphics.Layout.Grid(Grid(..), GridItem(..), Alignment(..), Name,
        buildGrid, setCellBox, enumerate,
        gridMinWidth, gridMinHeight, gridNatWidth, gridNatHeight,
        gridEstWidth, gridNatWidths, gridMinWidths, gridMaxWidths, gridWidths,
        gridNatHeights, gridMinHeights, gridMaxHeights, gridHeights,
        gridPosition, gridLayout) where


@@ 15,15 16,14 @@ import Debug.Trace (trace)
-- TODO implement subgrid support...
data Grid m n = Grid {
    rows :: [Either m Double],
    rowBounds :: [(Double, Double)],
    rowMins :: [Double],
    rowNats :: [Double],
    subgridRows :: Int,
    columns :: [Either n Double],
    colBounds :: [(Double, Double)],
    colMins :: [Double],
    colNats :: [Double],
    subgridColumns :: Int,
    gap :: Size m n,
    containerSize :: Size m n, -- wrap in a Flow box to get padding, etc.
    containerMin :: Size m n,
    containerMax :: Size m n
    gap :: Size m n
}
data GridItem m n = GridItem {
    startRow :: Int, endRow :: Int, startCol :: Int, endCol :: Int,


@@ 36,20 36,34 @@ type Name = Text

buildGrid rows columns = Grid {
    rows = rows,
    rowBounds = [],
    rowMins = [], rowNats = [],
    subgridRows = 0, -- disables
    columns = columns,
    colBounds = [],
    colMins = [], colNats = [],
    subgridColumns = 0, -- disables
    gap = Size (Pixels 0) (Pixels 0),
    containerSize = Size Auto Auto,
    containerMin = Size Auto Auto,
    containerMax = Size Auto Auto
    gap = Size (Pixels 0) (Pixels 0)
}
-- 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'

gridMinWidth :: (n -> Double) -> Grid m n -> Double
gridMinWidth cb self@Grid { colMins = [] } =
    sum $ intersperse (cb $ inline $ gap self) [cb x | Left x <- columns self]
gridMinWidth cb self = sum $ intersperse (cb $ inline $ gap self) $ colMins self
gridMinHeight :: (m -> Double) -> Grid m n -> Double
gridMinHeight cb self@Grid { rowMins = [] } =
    sum $ intersperse (cb $ block $ gap self) [cb x | Left x <- rows self]
gridMinHeight cb self = sum $ intersperse (cb $ block $ gap self) $ rowMins self
gridNatWidth :: (n -> Double) -> Grid m n -> Double
gridNatWidth cb self@Grid { colMins = [] } =
    sum $ intersperse (cb $ inline $ gap self) [cb x | Left x <- columns self]
gridNatWidth cb self = sum $ intersperse (cb $ inline $ gap self) $ colNats self
gridNatHeight :: (m -> Double) -> Grid m n -> Double
gridNatHeight cb self@Grid { rowNats = [] } =
    sum $ intersperse (cb $ block $ gap self) [cb x | Left x <- rows self]
gridNatHeight cb self = sum $ intersperse (cb $ block $ gap self) $ rowNats self

cellsForCol :: [GridItem y x] -> Int -> [GridItem y x]
cellsForCol cells ix =
    [cell | cell <- cells, startCol cell == ix, startCol cell == pred (endCol cell)]


@@ 66,7 80,7 @@ verifyGrid self childs = and [
    height = length $ rows self

gridEstWidth :: Grid b Length -> [GridItem y Double] -> Double
gridEstWidth self childs = fst $ gridMaxWidths zeroBox self $ zip mins nats
gridEstWidth self childs = fst $ gridMaxWidths zeroBox self mins nats
  where
    mins = snd $ gridMinWidths 0 self childs
    nats = snd $ gridNatWidths 0 self childs


@@ 92,10 106,11 @@ gridNatWidths parent self childs =
        maximum $ (0:) $ map (inline . B.min . gridItemBox) $ cellsForCol childs ix
    colNatWidth (ix, _) =
        maximum $ (0:) $ map (inline . size . gridItemBox) $ cellsForCol childs ix
gridMaxWidths :: PaddedBox b Double -> Grid y Length -> [(Double, Double)] -> (Double, [Double])
gridMaxWidths parent self subwidths =
gridMaxWidths :: PaddedBox b Double -> Grid y Length -> [Double] -> [Double] -> (Double, [Double])
gridMaxWidths parent self submins subnats =
    (sum $ intersperse (lowerLength outerwidth $ inline $ gap self) ret, ret)
  where
    subwidths = zip submins subnats
    ret = map (colMaxWidth fr) $ zip subwidths $ columns self
    fr = Prelude.max 0 fr'
    fr' = (outerwidth - estimate)/(countFRs $ columns self)


@@ 108,10 123,11 @@ gridMaxWidths parent self subwidths =
    colMaxWidth _ ((min, _), Left Min) = min
    colMaxWidth fr (_, Left Auto) = fr
    colMaxWidth fr (_, Right x) = x*fr
gridWidths :: PaddedBox b Double -> Grid y Length -> [(Double, Double)] -> (Double, [Double])
gridWidths parent self subwidths =
gridWidths :: PaddedBox b Double -> Grid y Length -> [Double] -> [Double] -> (Double, [Double])
gridWidths parent self submins subnats =
    (sum $ intersperse (lowerLength outerwidth $ inline $ gap self) ret, ret)
  where
    subwidths = zip submins subnats
    ret = map (colWidth fr) $ zip subwidths $ columns self
    fr = (outerwidth - estimate)/(countFRs $ columns self)
    outerwidth = inline $ size parent


@@ 148,9 164,10 @@ gridMinHeights parent self childs =
    rowMinHeight (ix, _) =
        maximum $ (0:) $ map (block . B.min . gridItemBox) $ cellsForCol childs ix
gridMaxHeights :: PaddedBox Double Double -> Grid Length Double ->
    [(Double, Double)] -> (Double, [Double])
gridMaxHeights parent self subheights = (sum $ intersperse (inline $ gap self) ret, ret)
    [Double] -> [Double] -> (Double, [Double])
gridMaxHeights parent self submins subnats = (sum $ intersperse (inline $ gap self) ret, ret)
  where
    subheights = zip submins subnats
    ret = map (colMaxHeight fr) $ zip subheights $ rows self
    fr = (outerheight - estimate)/(countFRs $ rows self)
    outerwidth = inline $ size parent


@@ 164,9 181,10 @@ gridMaxHeights parent self subheights = (sum $ intersperse (inline $ gap self) r
    colMaxHeight fr (_, Left Auto) = fr
    colMaxHeight fr (_, Right x) = x*fr
gridHeights :: PaddedBox Double Double -> Grid Length Double ->
    [(Double, Double)] -> (Double, [Double])
gridHeights parent self subheights = (sum $ intersperse (inline $ gap self) ret, ret)
    [Double] -> [Double] -> (Double, [Double])
gridHeights parent self submins subnats = (sum $ intersperse (inline $ gap self) ret, ret)
  where
    subheights = zip submins subnats
    ret = map (colHeight fr) $ zip subheights $ rows self
    fr = (outerheight - estimate)/(countFRs $ rows self)
    outerwidth = inline $ size parent


@@ 209,33 227,25 @@ gridLayout parent self childs paginate = (self', zip positions childs)
    positions = gridPosition self' childs
    self' = self {
        rows = map Left rows',
        rowBounds = rowBounds',
        rowMins = rowMins', rowNats = rowNats',
        columns = map Left cols',
        colBounds = colBounds',
        gap = Size (lowerLength width' gapX) (lowerLength width' gapY),
        containerSize = Size width' height',
        containerMin = Size width' height',
        containerMax = Size width' height'
        colMins = colMins', colNats = colNats',
        gap = Size (lowerLength width' gapX) (lowerLength width' gapY)
      }
    Size gapX gapY = gap self

    (height', rows') = gridHeights parent self0 rowBounds'
    rowBounds' = zip rowMins rowNats
    (_, rowMins) = gridMinHeights width' self0 childs
    (_, rowNats) = gridNatHeights width' self0 childs
    (height', rows') = gridHeights parent self0 rowMins' rowNats'
    (_, rowMins') = gridMinHeights width' self0 childs
    (_, rowNats') = gridNatHeights width' self0 childs

    self0 = self {
        columns = map Left cols',
        colBounds = colBounds',
        gap = Size (lowerLength width' gapX) gapY,
        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
        colMins = colMins', colNats = colNats',
        gap = Size (lowerLength width' gapX) gapY
      }
    (width', cols') = gridWidths parent self colBounds'
    colBounds' = zip colMins colNats
    (_, colMins) = gridMinWidths estWidth self childs
    (_, colNats) = gridNatWidths estWidth self childs
    (width', cols') = gridWidths parent self colMins' colNats'
    (_, colMins') = gridMinWidths estWidth self childs
    (_, colNats') = gridNatWidths estWidth self childs
    estWidth = gridEstWidth self childs

enumerate = zip [0..]

M Graphics/Layout/Grid/CSS.hs => Graphics/Layout/Grid/CSS.hs +3 -6
@@ 258,16 258,13 @@ finalizeGrid self@CSSGrid {
  where
    self' = Grid {
        rows = map finalizeFR $ map snd rows0,
        rowBounds = [],
        rowMins = [], rowNats = [],
        subgridRows = 0, -- disable
        columns = map finalizeFR $ map snd cols0,
        colBounds = [],
        colMins = [], colNats = [],
        subgridColumns = 0, -- disable
        gap = Size (finalizeLength (inline $ cssGap self) font)
            (finalizeLength (block $ cssGap self) font),
        containerSize = Size Auto Auto, -- Proper size is set on parent.
        containerMin = Size Auto Auto,
        containerMax = Size Auto Auto
            (finalizeLength (block $ cssGap self) font)
    }

    (cells', rows0, cols0) = finalizeCells cells rows' cols'