module Text.Layout.Table.Primitives.ColumnModifier where
import Control.Arrow ((&&&))
import Data.List
import Text.Layout.Table.Cell
import Text.Layout.Table.Primitives.AlignInfo
import Text.Layout.Table.Spec.AlignSpec
import Text.Layout.Table.Spec.ColSpec
import Text.Layout.Table.Spec.CutMark
import Text.Layout.Table.Spec.LenSpec
import Text.Layout.Table.Spec.OccSpec
import Text.Layout.Table.Spec.Position
import Text.Layout.Table.Spec.Util
import Text.Layout.Table.StringBuilder
data ColModInfo
= FillAligned OccSpec AlignInfo
| FillTo Int
| FitTo Int (Maybe (OccSpec, AlignInfo))
showCMI :: ColModInfo -> String
showCMI cmi = case cmi of
FillAligned _ ai -> "FillAligned .. " ++ showAI ai
FillTo i -> "FillTo " ++ show i
FitTo i _ -> "FitTo " ++ show i ++ ".."
widthCMI :: ColModInfo -> Int
widthCMI cmi = case cmi of
FillAligned _ ai -> widthAI ai
FillTo maxLen -> maxLen
FitTo lim _ -> lim
unalignedCMI :: ColModInfo -> ColModInfo
unalignedCMI cmi = case cmi of
FillAligned _ ai -> FillTo $ widthAI ai
FitTo i _ -> FitTo i Nothing
_ -> cmi
ensureWidthCMI :: Int -> Position H -> ColModInfo -> ColModInfo
ensureWidthCMI w pos cmi = case cmi of
FillAligned oS ai@(AlignInfo lw optRW)
->
let neededW = w - widthAI ai
in if neededW <= 0
then cmi
else FillAligned oS $ case pos of
Start -> case optRW of
Just rw -> AlignInfo lw $ Just (rw + neededW)
Nothing -> AlignInfo (lw + neededW) optRW
End -> AlignInfo (lw + neededW) optRW
Center -> case optRW of
Just _ -> let (q, r) = w `divMod` 2
in AlignInfo q $ Just (q + r)
Nothing -> AlignInfo (lw + neededW) optRW
FillTo maxLen -> FillTo (max maxLen w)
_ -> cmi
ensureWidthOfCMI :: String -> Position H -> ColModInfo -> ColModInfo
ensureWidthOfCMI = ensureWidthCMI . visibleLength
fitTitlesCMI :: [String] -> [Position H] -> [ColModInfo] -> [ColModInfo]
fitTitlesCMI = zipWith3 ensureWidthOfCMI
columnModifier
:: (Cell a, StringBuilder b)
=> Position H
-> CutMark
-> ColModInfo
-> (a -> b)
columnModifier pos cms colModInfo = case colModInfo of
FillAligned oS ai -> align oS ai
FillTo maxLen -> pad pos maxLen
FitTo lim mT ->
maybe (trimOrPad pos cms lim) (uncurry $ alignFixed pos cms lim) mT
deriveColModInfos :: Cell a => [(LenSpec, AlignSpec)] -> [Row a] -> [ColModInfo]
deriveColModInfos specs = zipWith ($) (fmap fSel specs) . transpose
where
fSel (lenS, alignS) = case alignS of
NoAlign -> let fitTo i = const $ FitTo i Nothing
expandUntil' f i max' = if f (max' <= i)
then FillTo max'
else fitTo i max'
fun = case lenS of
Expand -> FillTo
Fixed i -> fitTo i
ExpandUntil i -> expandUntil' id i
FixedUntil i -> expandUntil' not i
in fun . maximum . map visibleLength
AlignOcc oS -> let fitToAligned i = FitTo i . Just . (,) oS
fillAligned = FillAligned oS
expandUntil' f i ai = if f (widthAI ai <= i)
then fillAligned ai
else fitToAligned i ai
fun = case lenS of
Expand -> fillAligned
Fixed i -> fitToAligned i
ExpandUntil i -> expandUntil' id i
FixedUntil i -> expandUntil' not i
in fun . foldMap (deriveAlignInfo oS)
deriveColModInfos' :: Cell a => [ColSpec] -> [Row a] -> [ColModInfo]
deriveColModInfos' = deriveColModInfos . fmap (lenSpec &&& alignSpec)
deriveColMods
:: (Cell a, StringBuilder b)
=> [ColSpec]
-> [Row a]
-> [a -> b]
deriveColMods specs tab =
zipWith (uncurry columnModifier) (map (position &&& cutMark) specs) cmis
where
cmis = deriveColModInfos' specs tab
deriveAlignInfo :: Cell a => OccSpec -> a -> AlignInfo
deriveAlignInfo occSpec = measureAlignment (predicate occSpec)