~alcinnz/CatTrap

4afd3f9a625475d017e8353c1596d58c5691f731 — Adrian Cochrane 1 year, 1 month ago 66067a7
Draft flexbox layout
2 files changed, 84 insertions(+), 1 deletions(-)

A Graphics/Layout/Flex.hs
M cattrap.cabal
A Graphics/Layout/Flex.hs => Graphics/Layout/Flex.hs +83 -0
@@ 0,0 1,83 @@
module Graphics.Layout.Flex(FlexParent(..), FlexChild(..),
    Direction(..), FlexWrapping(..), Justification(..), Alignment(..),
    flexMaxBasis, flexSumBasis, flexWrap) where

import Graphics.Layout.Box (Length, lowerLength)
import Data.List (intersperse)

data FlexParent a b = FlexParent {
    direction :: Direction,
    reverseRows :: Bool,
    wrap :: FlexWrapping,
    justify :: Justification,
    alignLines :: Maybe Justification, -- `Nothing` is "stretch"
    baseGap :: b,
    crossGap :: b,
    children :: [[FlexChild a b]] -- 2D list to store lines once split.
}
data FlexChild a b = FlexChild {
    grow :: Double,
    shrink :: Double,
    basis :: b,
    alignment :: Alignment,
    flexInner :: a
}

data Direction = Row | Column
data FlexWrapping = NoWrap | Wrap | WrapReverse
data Justification = JLeft | JRight | JCenter | JSpaceBetween | JSpaceAround | JSpaceEvenly
data Alignment = AlStretch | AlStart | AlEnd | AlCenter | AlBaseline

flexMaxBasis :: FlexParent a Length -> Double -> Double
flexMaxBasis self outersize = maximum [lowerLength outersize $ basis child |
        row <- children self, child <- row]
flexSumBasis :: FlexParent a Length -> Double -> Double
flexSumBasis self size = maximum [Prelude.sum $ map (lowerLength size) $
        intersperse (baseGap self) $ map basis row | row <- children self]

flexWrap :: FlexParent a Length -> Double -> FlexParent a Double
flexWrap self size
    | NoWrap <- wrap self = post self'
    | Wrap <- wrap self = post wrapped
    | WrapReverse <- wrap self = post wrapped {children=reverse$children wrapped}
  where
    self' = FlexParent {
        direction = direction self,
        reverseRows = reverseRows self,
        wrap = wrap self,
        justify = justify self,
        alignLines = alignLines self,
        baseGap = lowerLength size $ baseGap self,
        crossGap = lowerLength size $ crossGap self,
        children = map (map $ child' size) $ children self
      }
    child' size x = FlexChild {
        grow = grow x, shrink = shrink x,
        basis = lowerLength size $ basis x,
        alignment = alignment x, flexInner = flexInner x
      }
    wrapped = self' {
        children = concatMap wrapRow $ children self'
    }
    wrapRow :: [FlexChild a Double] -> [[FlexChild a Double]]
    wrapRow [] = []
    wrapRow kids@(kid:_) = let (row, rest) = splitRow kids $ basis kid
        in (row):wrapRow rest
    splitRow (kid:kids) end
        | end > size = ([], kid:kids)
        | otherwise = let (kids', rest) = splitRow kids (end + baseGap self' + basis kid)
            in (kid:kids', rest)
    splitRow [] _ = ([], [])

    post flex
        | reverseRows self = post' flex { children = map reverse $ children flex }
        | otherwise = post' flex
    post' flex = flex { children = map resizeRow $ children flex }
    resizeRow row
        | rowSize > size = [kid { basis = basis kid - shrink kid * sfr } | kid <- row]
        | rowSize < size = [kid { basis = basis kid + grow kid * 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)

M cattrap.cabal => cattrap.cabal +1 -1
@@ 27,7 27,7 @@ library
                        Graphics.Layout.Box, Graphics.Layout.Arithmetic,
                        Graphics.Layout.CSS.Length, Graphics.Layout.CSS.Font,
                        Graphics.Layout.Inline, Graphics.Layout.Inline.CSS,
                        Graphics.Layout.Grid.Table
                        Graphics.Layout.Grid.Table, Graphics.Layout.Flex
  other-modules:        Graphics.Layout.CSS.Parse
  -- other-extensions:
  build-depends:       base >=4.12 && <5, containers >= 0.6 && < 1, parallel >= 3 && <4,