module Data.Text.ParagraphLayout.Internal.Paginable (PageOptions(..) ,Paginable ,paginate ) where import Data.Int (Int32) import Data.Text.ParagraphLayout.Internal.LinePagination import Data.Text.ParagraphLayout.Internal.ParagraphLayout import Data.Text.ParagraphLayout.Internal.ParagraphLine data PageOptions = PageOptions { pageCurrentHeight :: Int32 -- ^ Amount of vertical space available for the paragraph -- on the current page. , pageNextHeight :: Int32 -- ^ Expected amount of vertical space available for the paragraph -- on the next page. -- -- If this is greater than `pageCurrentHeight`, the paragraph may be pushed -- onto the next page in order to better satisfy orphan/widow constraints. , pageOrphans :: Word -- ^ If a page break is required inside the paragraph, this will be the -- minimum number of lines to keep at the bottom of this page, if possible. , pageWidows :: Word -- ^ If a page break is required inside the paragraph, this will be the -- minimum number of lines to keep at the top of the next page, if possible. } -- | Typeclass for layouts that can be broken into pages. class Paginable pl where -- | Break a chunk of content from the given layout, to be placed together -- on a page. -- -- Explanation of return values: -- -- * @(`Continue`, p, `Nothing`)@ -- means that @p@ is the entire layout and fits best on the current page. -- -- * @(`Break`, p, `Nothing`)@ -- means that @p@ is the entire layout and fits best on a new page. -- In other words, @p@ should be preceded by a page break. -- -- * @(`Continue`, p, `Just` rest)@ -- means that @p@ is a part of the layout that fits best on the current -- page, and @rest@ should be passed to this function again. -- In other words, @p@ should be followed by a page break. -- -- * @(`Break`, p, `Just` rest)@ -- means that @p@ is a part of the layout that fits best on a new page, -- and @rest@ should be passed to this function again. -- In other words, @p@ should be surrounded by page breaks -- on both sides. paginate :: PageOptions -> pl -> (PageContinuity, pl, Maybe pl) instance Line a => Paginable [a] where paginate opts ls = case paginateLines o w h1 h2 ls of (c, p, []) -> (c, p, Nothing) (c, p, rest) -> (c, p, Just rest) where o = pageOrphans opts w = pageWidows opts h1 = pageCurrentHeight opts h2 = pageNextHeight opts -- | Break a paragraph in order to fit the given pagination constraints. instance Paginable ParagraphLayout where paginate opts pl = case paginate opts (cutLines pl) of (c, p, Nothing) -> (c, mergeLines p, Nothing) (c, p, Just rest) -> (c, mergeLines p, Just (mergeLines rest))