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)