{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE ExistentialQuantification #-} module Diagrams.Backend.Pdf.Specific( LabelStyle(..) , PdfTextBox(..) , drawStringLabel , getTextBoundingBox , TextOrigin(..) , LabelSize , PdfImage(..) , PdfURL(..) , PdfShadingData(..) , getShadingData , pdfAxialShading , pdfRadialShading , AnyFormattedParagraph(..) , CanBeFormatted(..) ) where import Graphics.PDF hiding(translate) import qualified Graphics.PDF as P import Diagrams.Prelude import Data.Typeable --import qualified Debug.Trace as T --debug a = T.trace (show a) a data TextOrigin = Center | LeftSide | RightSide | TopSide | BottomSide | TopLeftCorner | TopRightCorner | BottomLeftCorner | BottomRightCorner deriving(Eq) type LabelSize = Int -- | Style for a label. -- It is not considered as an attribute but as a different primitive -- because internaly it is a complex text which can support several styles -- in the same paragraph. -- Label is just a convenience wrapper when the full features are not needed data LabelStyle = LabelStyle FontName LabelSize Justification TextOrigin (Colour Double) data PdfTextBox = PdfTextBox { _transform :: T2 , _suggestedWidth :: Double , _suggestedHeight :: Double , _paragraph :: AnyFormattedParagraph } type instance V PdfTextBox = R2 instance Transformable PdfTextBox where transform t (PdfTextBox tt sw sh para) = PdfTextBox (t <> tt) sw sh para instance IsPrim PdfTextBox instance HasOrigin PdfTextBox where moveOriginTo p = translate (origin .-. p) instance Renderable PdfTextBox NullBackend where render _ _ = mempty data PdfImage = PdfImage T2 (PDFReference PDFJpeg) type instance V PdfImage = R2 instance Transformable PdfImage where transform t (PdfImage tt ref) = PdfImage (t <> tt) ref instance IsPrim PdfImage instance HasOrigin PdfImage where moveOriginTo p = translate (origin .-. p) instance Renderable PdfImage NullBackend where render _ _ = mempty data PdfURL = PdfURL T2 String Double Double type instance V PdfURL = R2 instance Transformable PdfURL where transform t (PdfURL tt s w h) = PdfURL (t <> tt) s w h instance IsPrim PdfURL instance HasOrigin PdfURL where moveOriginTo p = translate (origin .-. p) instance Renderable PdfURL NullBackend where render _ _ = mempty drawStringLabel :: PDFFloat -> PDFFloat -> AnyFormattedParagraph -> Draw () drawStringLabel w h para = typesetText w h para data AnyFormattedParagraph = forall s ps. (ParagraphStyle ps s, P.Style s) => AFP ps s (TM ps s ()) class CanBeFormatted m where putIntoContainer :: Double -> Double -> m -> Draw () matchingContainerSize :: Double -> Double -> m -> Rectangle instance CanBeFormatted AnyFormattedParagraph where putIntoContainer w h (AFP ps p t) = let b = getBoxes ps p t sh = styleHeight p c = mkContainer 0 0 w h sh (d,_,_) = fillContainer (defaultVerState ps) c b in d matchingContainerSize w h (AFP ps p t) = let b = getBoxes ps p t sh = styleHeight p c = mkContainer 0 0 w h sh (_,c',_) = fillContainer (defaultVerState ps) c b in containerContentRectangle c' typesetText :: PDFFloat -- ^ width limit -> PDFFloat -- ^ height limit -> AnyFormattedParagraph -> P.Draw () typesetText w h para = putIntoContainer w h para getTextBoundingBox :: PDFFloat -- ^ width limit -> PDFFloat -- ^ height limit -> AnyFormattedParagraph -> Rectangle getTextBoundingBox w h para = matchingContainerSize w h para data PdfShadingData = PdfAxialShadingData P2 P2 (Colour Double) (Colour Double) | PdfRadialShadingData P2 Double P2 Double (Colour Double) (Colour Double) deriving (Show,Typeable) newtype PdfShading = PdfShading (Last PdfShadingData) deriving (Typeable, Semigroup) instance AttributeClass PdfShading getShadingData :: PdfShading -> PdfShadingData getShadingData (PdfShading (Last c)) = c addshading :: (HasStyle a) => PdfShadingData -> a -> a addshading s = applyAttr (PdfShading . Last $ s) -- | Define Axial shading for a diagram pdfAxialShading :: HasStyle a => P2 -> P2 -> Colour Double -> Colour Double -> a -> a pdfAxialShading pa pb ca cb = addshading (PdfAxialShadingData pa pb ca cb) -- | Define Radial shading for a diagram pdfRadialShading :: HasStyle a => P2 -- ^ Center of inner circle -> Double -- ^ Radius of inner circle -> P2 -- ^ Center of outer circle -> Double -- ^ Radius of outer circle -> Colour Double -- ^ Inner colour -> Colour Double -- ^ Outer colour -> a -> a pdfRadialShading pa ra pb rb ca cb = addshading (PdfRadialShadingData pa ra pb rb ca cb)