-- | Represents the contents of a paragraph as a tree. -- -- The tree is a hierarchy of boxes, with one box always present as the root. -- Each box may contain any combination of text sequences and other boxes. module Data.Text.ParagraphLayout.Internal.Tree ( RootNode (..) , InnerNode (..) , Box (..) , Leaf (..) , flatten ) where import Data.Text.ParagraphLayout.Internal.BoxOptions import Data.Text.ParagraphLayout.Internal.ResolvedBox import Data.Text.ParagraphLayout.Internal.TextOptions -- | Root of the paragraph tree. data RootNode d = RootBox -- ^ The root inline box. Always present in a paragraph. -- -- Cannot be styled directly, but can still set options for formatting -- text sequences directly descending from this box. (Box d) -- ^ Contents of the box. -- | Non-root node of the paragraph tree. data InnerNode d = InlineBox -- ^ An inline box, nested in another box. d -- ^ User-defined data associated with the box. (Box d) -- ^ Contents of the box. BoxOptions -- ^ Style options to apply to the inline box. | TextSequence -- ^ A leaf node containing text. d -- ^ User-defined data associated with the text node. Int -- ^ Byte offset to the next text node or the end of the paragraph text. -- | A box with content and a defined format. Corresponds to a DOM element. data Box d = Box [InnerNode d] -- ^ Text nodes and other boxes contained by this box. TextOptions -- ^ Style options to apply to text sequences directly contained -- by this box. type BoxPath d = [ResolvedBox d] -- | Representation of a leaf node of the tree after flattening. data Leaf d = TextLeaf d -- ^ User-defined data associated with the text node. Int -- ^ Byte offset to the next text node or the end of the paragraph text. TextOptions -- ^ Style options to apply to this text sequence. (BoxPath d) -- ^ Inline boxes found on the path from this text sequence to the root -- of the original tree. -- | Convert the tree to a flat list of its leaf nodes (text sequences). flatten :: RootNode d -> [Leaf d] flatten (RootBox (Box ns textOpts)) = snd $ flattenNodes 0 [] textOpts ns flattenNodes :: Int -> BoxPath d -> TextOptions -> [InnerNode d] -> (Int, [Leaf d]) flattenNodes idx _ _ [] = (idx, []) flattenNodes idx path textOpts (n : ns) = (idx'', flat1 ++ flat2) where (idx', flat1) = flattenNode idx path textOpts n (idx'', flat2) = flattenNodes idx' path textOpts ns flattenNode :: Int -> BoxPath d -> TextOptions -> InnerNode d -> (Int, [Leaf d]) flattenNode idx path textOpts (TextSequence d len) = (idx, [TextLeaf d len textOpts path]) flattenNode idx path _ (InlineBox d (Box ns textOpts) boxOpts) = flattenNodes (idx + 1) (ResolvedBox d idx boxOpts dir : path) textOpts ns where dir = textDirection textOpts