--------------------------------------------------------- -- | -- Copyright : (c) 2006-2012, alpheccar.org -- License : BSD-style -- -- Maintainer : misc@NOSPAMalpheccar.org -- Stability : experimental -- Portability : portable -- -- Vertical mode --------------------------------------------------------- -- #hide module Graphics.PDF.Typesetting.Vertical ( mkVboxWithRatio , vglue , defaultVerState , ParagraphStyle(..) , VerState(..) , fillContainer , mkContainer , VBox(..) ) where import Graphics.PDF.LowLevel.Types import Graphics.PDF.Typesetting.Breaking import Graphics.PDF.Typesetting.Horizontal(horizontalPostProcess,HBox) import Graphics.PDF.Draw import Graphics.PDF.Typesetting.Box import Data.List(foldl') import Graphics.PDF.Typesetting.Layout -- | Default vertical state -- -- > Default values -- > baselineskip = (12,0.17,0.0) -- > lineskip = (3.0,0.33,0.0) -- > lineskiplimit = 2 -- defaultVerState :: s -> VerState s defaultVerState s = VerState { baselineskip = (12,0.17,0.0) , lineskip = (3.0,0.33,0.0) , lineskiplimit = 2 , currentParagraphStyle = s } -- | Pair of functions describing the shape of a text areas : horizontal position of each line, vertical top of the area, width of each line -- First line is 1 -- | A line of hboxes with an adjustement ratio required to display the text (generate the PDF command to increase space size) --data HLine = HLine !PDFFloat ![HBox] deriving(Show) mkVboxWithRatio :: PDFFloat -- ^ Adjustement ratio -> [VBox ps s] -> VBox ps s mkVboxWithRatio _ [] = error "Cannot make an empty vbox" mkVboxWithRatio r l = let w = foldl' (\x y -> x + glueSizeWithRatio y r) 0.0 l h = maximum . map boxHeight $ l d = maximum . map boxDescent $ l addBox (VGlue gw gh gdelta (Just(y,z)) s) (VBox w' h' d' l' s') = VBox w' h' d' (VGlue (glueSize gw y z r) gh gdelta Nothing s:l') s' addBox a (VBox w' h' d' l' s') = VBox w' h' d' (a:l') s' addBox _ _ = error "We can add boxes only to an horizontal list" in -- Add boxes and dilate glues when needing fixing their dimensions after dilatation foldr addBox (VBox w h d [] Nothing) l dilateVboxes :: PDFFloat -> VBox ps s -> VBox ps s dilateVboxes r g@(VGlue _ w l (Just(_,_)) s) = let h' = glueSizeWithRatio g r in VGlue h' w l Nothing s dilateVboxes _ g@(VGlue _ _ _ Nothing _) = g dilateVboxes _ a = a drawContainer :: ParagraphStyle ps s => Container ps s -- ^ Container -> Draw () drawContainer (Container px py _ maxh h y z _ oldl) = let l' = reverse oldl r = min (dilatationRatio maxh h y z) 2.0 l'' = map (dilateVboxes r) l' in strokeVBoxes l'' px py -- | Create a new paragraph from the remaining letters createPara :: Int -> Maybe ps -> BRState -> [Letter s] -> [VBox ps s] createPara _ _ _ [] = [] createPara lineOffset style paraSettings l = [Paragraph lineOffset (simplify l) style paraSettings] -- | Add paragraph lines to a container addParaLine :: (ParagraphStyle ps s, ComparableStyle ps) => VerState ps -> Maybe ps -> BRState -> Container ps s -- ^ Container -> [((HBox s,[Letter s]),Int)] -> Either (Draw (),Container ps s,[VBox ps s]) (Container ps s) addParaLine _ _ _ c [] = Right c addParaLine verstate style paraSettings c (((line,remainingPar),lineNb):l) = let c' = addTo verstate (toVBoxes style (containerWidth c) line lineNb) c in if isOverfull c' then Left (drawContainer c,c,createPara lineNb style paraSettings remainingPar) else addParaLine verstate style paraSettings c' l -- | Fill a container with lines fillContainer :: (ParagraphStyle ps s, ComparableStyle ps) => VerState ps -- ^ Vertical style for interline glues -> Container ps s -- ^ Container -> [VBox ps s] -- ^ VBox to add -> (Draw(),Container ps s,[VBox ps s]) -- ^ Component to draw, new container and remaining VBoxes due to overfull container fillContainer _ c [] = (drawContainer c,c,[]) fillContainer verstate c para@(Paragraph lineOffset l style paraSettings:l') = if containerContentHeight c > containerHeight c - containerParaTolerance c then (drawContainer c,c,para) else let (fl,newStyle) = case style of Nothing -> (formatList paraSettings (const $ containerWidth c) l,Nothing) Just aStyle -> let (style',nl) = paragraphChange aStyle lineOffset l in (formatList paraSettings (\nb -> (lineWidth style') (containerWidth c) (nb+lineOffset) ) nl,Just style') newLines = horizontalPostProcess fl r = addParaLine verstate newStyle paraSettings c (zip newLines [1..]) in case r of Left (d,c',remPara) -> (d,c',remPara ++ l') Right c' -> fillContainer verstate c' l' fillContainer verstate c oldl@(a:l) = let c' = addTo verstate a c in if isOverfull c' then (drawContainer c,c,oldl) else fillContainer verstate c' l -- | Convert pure lines to VBoxes toVBoxes :: (ParagraphStyle ps s) => Maybe ps -> PDFFloat -- ^ Max width -> HBox s -- ^ List of lines -> Int -- ^ Line number -> VBox ps s -- ^ List of VBoxes toVBoxes Nothing _ a _ = SomeVBox 0.0 (boxWidth a,boxHeight a,boxDescent a) (AnyBox a) Nothing toVBoxes s@(Just style) w a nb = let delta = (linePosition style) w nb in SomeVBox delta (boxWidth a,boxHeight a,boxDescent a) (AnyBox a) s