-- | The document type, which expresses the intent of the user about -- what to render. -- -- We support general layouting \/ formatting, and also constructions -- specific to mathematical documents (similar to LaTeX). -- -- TODO: mathemetical accents, compound symbols, -- user-defined styles, squiggly underlines, etc -- {-# LANGUAGE OverloadedStrings, BangPatterns #-} module Graphics.Rendering.MiniTypeset.Document where -------------------------------------------------------------------------------- import Data.String -- import qualified Data.Text as T ; import Data.Text (Text) import Graphics.Rendering.MiniTypeset.Common import Graphics.Rendering.MiniTypeset.Box ( WhichQuad(..) ) -------------------------------------------------------------------------------- -- * The document data type -- | This data type describes what the user want to render. -- -- The type parameter @ident@ is used when the user want to know positions (bounding boxes) of -- different parts of the rendered text. It must have an 'Ord' instance. -- data Document ident = Symbol !Char -- ^ a single character or symbol | String !String -- ^ a string | Space -- ^ a space character (do we need this to be separate?) | HorzCat !VAlign [Document ident] -- ^ horizontal concatenation | VertCat !HAlign [Document ident] -- ^ vertical concatenation | Overlay !(HAlign,VAlign) [Document ident] -- ^ overlaying on the top of each other | SubSupScript !(SubSup ident) !(Document ident) -- ^ add subscript and\/or superscript | Delimited !Delimiter [Document ident] -- ^ automatically sized (when possible) delimiters | Fraction !Bool !(Document ident) !(Document ident) -- ^ fractions (the Bool signifies whether to draw the line) | AboveBelow !(AboveBelow ident) !(Document ident) -- ^ above\/below (like in a summation or limit) | WithColor !Col !(Document ident) -- ^ change color | WithStyle !BasicStyle !(Document ident) -- ^ change font family | Decorated !TextDecoration !(Document ident) -- ^ add text decoration | AddMargin !Margin !(Document ident) -- ^ an extra margin around the document fragment | Realign !WhichQuad !(Document ident) -- ^ change the alignment box | Trim !(Document ident) -- ^ trim the outer \& gap boxes to the bounding box | RePosition !Pos !(Document ident) -- ^ offset (mostly for internal usage) | UnsafeResize !(Double,Double) !(Document ident) -- ^ temporary hack for internal usage, DO NOT USE IT! | Identified !ident !(Document ident) -- ^ user identifier so that the layout engine can return position information | EmptyDoc -- ^ the empty document deriving (Eq,Ord,Show) -------------------------------------------------------------------------------- -- | A text decoration data TextDecoration = Underline | Overline | StrikeThrough -- | SquigglyUnderline deriving (Eq,Ord,Show) -------------------------------------------------------------------------------- -- | A subscript or a superscript, or both data SubSup ident = Subscript !(Document ident) | Superscript !(Document ident) | SubAndSupscript !(Document ident) !(Document ident) -- ^ first is the subscript, second the superscript deriving (Eq,Ord,Show) subSupDocs :: SubSup ident -> (Document ident, Document ident) subSupDocs subsup = case subsup of Subscript sub -> (sub , EmptyDoc) Superscript sup -> (EmptyDoc , sup ) SubAndSupscript sub sup -> (sub , sup ) -------------------------------------------------------------------------------- -- | Limits of summations and similar things. data AboveBelow ident = Above !(Document ident) | Below !(Document ident) | AboveAndBelow !(Document ident) !(Document ident) -- ^ first is the above, second is below deriving (Eq,Ord,Show) aboveBelowDocs :: AboveBelow ident -> (Document ident, Document ident) aboveBelowDocs abelow = case abelow of Above ab -> (ab , EmptyDoc) Below be -> (EmptyDoc , be ) AboveAndBelow ab be -> (ab , be ) -------------------------------------------------------------------------------- -- * Atomic documents instance IsString (Document ident) where fromString = String -- text :: Text -> Document a -- text = String . T.unpack string :: String -> Document a string = String char :: Char -> Document a char = Symbol -- | A normal space space :: Document a space = Space -- | A zero-width space (hopefully your chosen unicode font supports it) zeroWidthSpace :: Document a zeroWidthSpace = Symbol '\x200B' -------------------------------------------------------------------------------- -- * Document combinators -- | Horizontal concatenation (<|>) :: Document a -> Document a -> Document a (<|>) x y = hcat [x,y] -- | Vertical concatenation (<->) :: Document a -> Document a -> Document a (<->) x y = vcat [x,y] -- | Overlay (<#>) :: Document a -> Document a -> Document a (<#>) x y = overlay [x,y] -- | Horizontal concatenation of several document fragments hcat :: [Document a] -> Document a hcat = hcatB -- | Vertical concatenation of several document fragments vcat :: [Document a] -> Document a vcat = vcatL -- | Overlay of several document fragments on top of each other overlay :: [Document a] -> Document a overlay = Overlay (AlignLeft,AlignBottom) hcatB :: [Document a] -> Document a hcatB = HorzCat AlignBottom hcatT :: [Document a] -> Document a hcatT = HorzCat AlignTop vcatL :: [Document a] -> Document a vcatL = VertCat AlignLeft vcatR :: [Document a] -> Document a vcatR = VertCat AlignRight -- ** Subscript and superscript subscript :: Document a -> Document a -> Document a subscript doc sub = SubSupScript (Subscript sub) doc supscript :: Document a -> Document a -> Document a supscript doc sup = SubSupScript (Superscript sup) doc subSup :: Document a -> (Document a, Document a) -> Document a subSup doc (sub,sup) = SubSupScript (SubAndSupscript sub sup) doc -- ** Above and below -- | Used for \"big\" mathematical operators (like summation) above :: Document a -> Document a -> Document a above doc ab = AboveBelow (Above ab) doc below :: Document a -> Document a -> Document a below doc be = AboveBelow (Below be) doc aboveBelow :: Document a -> (Document a, Document a) -> Document a aboveBelow doc (ab,be) = AboveBelow (AboveAndBelow ab be) doc -- ** Fractions and delimiters fraction :: Document a -> Document a -> Document a fraction = Fraction True -- | \"n choose k\" notation choose :: Document a -> Document a -> Document a choose = choose' Paren choose' :: Delimiter -> Document a -> Document a -> Document a choose' delim above below = delimited delim (Fraction False above below) delimited :: Delimiter -> Document a -> Document a delimited delim doc = Delimited delim [doc] -- | Puts a matched vertical line between the parts delimiteds :: Delimiter -> [Document a] -> Document a delimiteds delim docs = Delimited delim docs -- ** Text decoration underline, overline, strike :: Document a -> Document a underline = Decorated Underline overline = Decorated Overline strike = Decorated StrikeThrough -- ** Font variations regular, bold, italic, boldItalic :: Document a -> Document a regular = WithStyle Regular bold = WithStyle Bold italic = WithStyle Italic boldItalic = WithStyle BoldItalic -- ** Colors white, black, red, green, blue :: Document a -> Document a white = WithColor (Col 1 1 1) black = WithColor (Col 0 0 0) red = WithColor (Col 1 0 0) green = WithColor (Col 0 1 0) blue = WithColor (Col 0 0 1) rgb :: Float -> Float -> Float -> Document a -> Document a rgb r g b = WithColor (Col r g b) -- ** Margins margin :: Double -> Document a -> Document a margin x = AddMargin (Margin x x x x) hmargin :: Double -> Document a -> Document a hmargin x = AddMargin (Margin x x 0 0) vmargin :: Double -> Document a -> Document a vmargin x = AddMargin (Margin 0 0 x x) margin' :: Double -> Double -> Double -> Double -> Document a -> Document a margin' l r t b = AddMargin (Margin l r t b) --------------------------------------------------------------------------------