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)