~alcinnz/CatTrap

e8a4642ae31d8fe00225961e96817c5538972e41 — Adrian Cochrane 1 year, 5 months ago b07f5dc
Reconstruct inline tree.
M Graphics/Layout.hs => Graphics/Layout.hs +4 -5
@@ 30,7 30,7 @@ import qualified Data.Text.Glyphize as Hb
import Graphics.Text.Font.Choose (Pattern)

-- | Additional data routed through Balkon.
type UserData x = (Font', PaddedBox Length Length, x)
type UserData x = ((Font', Int), PaddedBox Length Length, x)

-- | A tree of different layout algorithms.
-- More to come...


@@ 45,7 45,7 @@ data LayoutItem m n x =
    -- Generated from `LayoutInline` for the sake of pagination.
    | LayoutInline' x (ParagraphLayout (UserData x)) PageOptions
    -- | Children of a `LayoutInline` or `LayoutInline'`.
    | LayoutSpan (Fragment (UserData x))
    | LayoutSpan (FragmentTree (UserData x))
-- | An empty box.
nullLayout :: (PropertyParser x, Zero m, Zero n) => LayoutItem m n x
nullLayout = LayoutFlow temp zero []


@@ 82,7 82,7 @@ layoutGetInner (LayoutFlow ret _ _) = ret
layoutGetInner (LayoutGrid ret _ _ _) = ret
layoutGetInner (LayoutInline ret _ _) = ret
layoutGetInner (LayoutInline' ret _ _) = ret
layoutGetInner (LayoutSpan Fragment { fragmentUserData = (_, _, ret) }) = ret
layoutGetInner (LayoutSpan x) = subtreeInner x

-- | map-ready wrapper around `setCellBox` sourcing from a child node.
setCellBox' (child, cell) = setCellBox cell $ layoutGetBox child


@@ 334,8 334,7 @@ boxPosition pos@(x, y) (LayoutInline val self paging) =
    boxPosition pos $ LayoutInline' val (layoutRich self) paging
boxPosition pos@(x, y) (LayoutInline' val self paging) =
    LayoutInline' (pos, val) (positionChildren pos self) paging
boxPosition pos (LayoutSpan self@(Fragment (a, b, c) d _ f g h)) =
    LayoutSpan $ Fragment (a, b, (pos, c)) d [] f g h -- No children...
boxPosition pos (LayoutSpan self) = LayoutSpan $ positionSubtree pos self
-- | Compute sizes & position information for all nodes in the (sub)tree.
boxLayout :: PropertyParser x => PaddedBox Double Double -> LayoutItem Length Length x ->
        Bool -> [LayoutItem Double Double ((Double, Double), x)]

M Graphics/Layout/Box.hs => Graphics/Layout/Box.hs +2 -2
@@ 10,7 10,7 @@ module Graphics.Layout.Box(Border(..), mapX, mapY,
-- | Amount of space surrounding the box.
data Border m n = Border {
    top :: m, bottom :: m, left :: n, right :: n
}
} deriving Eq
-- | Convert horizontal spacing via given callback.
mapX :: (n -> nn) -> Border m n -> Border m nn
-- | Convert vertical spacing via given callback.


@@ 44,7 44,7 @@ data PaddedBox m n = PaddedBox {
    border :: Border m n,
    -- | The amount of space between the border & anything else.
    margin :: Border m n
}
} deriving Eq
-- | An empty box, takes up nospace onscreen.
zeroBox :: PaddedBox Double Double
zeroBox = PaddedBox {

M Graphics/Layout/CSS.hs => Graphics/Layout/CSS.hs +9 -8
@@ 475,17 475,17 @@ finalizeChilds root parent style' childs@(child:childs')
          }:blocks)) -> let (inlines', blocks') = spanInlines tail
            in (inlines ++ inlines', blocks' ++ blocks)
        ret -> ret
    flattenTree0 childs = RootBox $ Box (map (flattenTree parent) childs) $
        flip applyFontInline parent $ txtOpts style'
    flattenTree p StyleTree { children = child@(_:_), style = self } =
        InlineBox (f, finalizeBox self f, inner self)
            (Box (map (flattenTree f) child)
    flattenTree0 childs = RootBox $ Box (map (flattenTree parent) $
        enumerate childs) $ flip applyFontInline parent $ txtOpts style'
    flattenTree p (i, StyleTree { children = child@(_:_), style = self }) =
        InlineBox ((f, i), finalizeBox self f, inner self)
            (Box (map (flattenTree f) $ enumerate child)
                $ flip applyFontInline f $ txtOpts self)
            defaultBoxOptions -- Fill in during layout.
          where f = pattern2font (font self) (font' self) p root
    flattenTree f StyleTree {style=self@CSSBox {inlineStyles=CSSInline txt _}} =
        InlineBox (f, finalizeBox self f, inner self)
            (Box [TextSequence (f, zero, inherit $ inner self) txt] $
    flattenTree f (i,StyleTree {style=self@CSSBox {inlineStyles=CSSInline txt _}})
        = InlineBox ((f, i), finalizeBox self f, inner self)
            (Box [TextSequence ((f, 0), zero, inherit $ inner self) txt] $
                flip applyFontInline f $ txtOpts self)
            defaultBoxOptions -- Fill in during layout.
    finalizeParagraph (RootBox (Box [TextSequence _ txt] _))


@@ 495,6 495,7 @@ finalizeChilds root parent style' childs@(child:childs')
            paragraphLineHeight = Absolute $ toEnum $ fromEnum
                    (lineheight parent * hbUnit)
          }
    enumerate = zip $ enumFrom 0
finalizeChilds _ _ _ [] = []

-- | Desugar most units, possibly in reference to given font.

M Graphics/Layout/CSS/Length.hs => Graphics/Layout/CSS/Length.hs +3 -0
@@ 106,3 106,6 @@ data Font' = Font' {
    -- | How many device pixels in a CSS px?
    scale :: Double
}

instance Eq Font' where
    a == b = pattern a == pattern b

M Graphics/Layout/Inline.hs => Graphics/Layout/Inline.hs +43 -8
@@ 3,10 3,12 @@
-- wraps Balkón for the actual logic.
module Graphics.Layout.Inline(inlineMinWidth, inlineMin, inlineNatWidth, inlineHeight,
    inlineSize, inlineChildren, layoutSize, layoutChildren, positionChildren,
    fragmentSize, fragmentSize', fragmentPos) where
    fragmentSize, fragmentSize', fragmentPos, FragmentTree(..),
    positionSubtree, subtreeInner) where

import Data.Text.ParagraphLayout.Rich (Paragraph(..), ParagraphOptions(..),
                                Fragment(..), ParagraphLayout(..), layoutRich)
                                Fragment(..), ParagraphLayout(..), AncestorBox(..),
                                layoutRich)
import Data.Text.ParagraphLayout.Rect (Rect(..), width, height, x_min, y_min)
import Data.Text.Internal (Text(..))
import qualified Data.Text as Txt


@@ 42,7 44,7 @@ inlineSize :: (CastDouble x, CastDouble y) => Paragraph a -> Size x y
inlineSize self = layoutSize $ layoutRich self
-- | Retrieve children out of some richtext,
-- associating given userdata with them.
inlineChildren :: Paragraph a -> [Fragment a]
inlineChildren :: Eq a => Paragraph a -> [FragmentTree a]
inlineChildren self = layoutChildren $ layoutRich self

-- | Retrieve a laid-out paragraph's rect & convert to CatTrap types.


@@ 50,8 52,8 @@ layoutSize :: (CastDouble x, CastDouble y) => ParagraphLayout a -> Size x y
layoutSize self = Size (c $ width r) (c $ height r)
  where r = paragraphRect self
-- | Retrieve a laid-out paragraph's children & associate with given userdata.
layoutChildren :: ParagraphLayout a -> [Fragment a]
layoutChildren self = paragraphFragments self -- TODO: Extract tree...
layoutChildren :: Eq a => ParagraphLayout a -> [FragmentTree a]
layoutChildren self = reconstructTree self

-- | Layout a paragraph at given width & retrieve resulting rect.
layoutRich' :: Paragraph a -> Int32 -> Rect Int32


@@ 59,12 61,13 @@ layoutRich' (Paragraph a b c d) width =
    paragraphRect $ layoutRich $ Paragraph a b c d { paragraphMaxWidth = width }

-- | Retrieve the rect for a fragment & convert to CatTrap types.
fragmentSize :: (CastDouble x, CastDouble y) => Fragment a -> Size x y
fragmentSize self = Size (c $ width r) (c $ height r)
fragmentSize :: (CastDouble x, CastDouble y) => FragmentTree a -> Size x y
fragmentSize (Branch _ _) = Size (c 0) (c 0) -- FIXME
fragmentSize (Leaf self) = Size (c $ width r) (c $ height r)
    where r = fragmentRect self
-- | Variant of `fragmentSize` asserting to the typesystem that both fields
-- of the resulting `Size` are of the same type.
fragmentSize' :: CastDouble x => Fragment a -> Size x x
fragmentSize' :: CastDouble x => FragmentTree a -> Size x x
fragmentSize' = fragmentSize -- Work around for typesystem.
-- | Retrieve the position of a fragment.
fragmentPos :: (Double, Double) -> Fragment a -> (Double, Double)


@@ 79,3 82,35 @@ positionChildren pos self = self {
    paragraphFragments = [Fragment (a, b, (fragmentPos pos frag, c)) d [] f g h
            | frag@(Fragment (a, b, c) d _ f g h) <- paragraphFragments self]
  }

data FragmentTree x = Branch (AncestorBox x) [FragmentTree x]
    | Leaf (Fragment x)

reconstructTree :: Eq x => ParagraphLayout x -> [FragmentTree x]
reconstructTree ParagraphLayout { paragraphFragments = frags } =
    reconstructTree' [frag {
            fragmentAncestorBoxes = reverse $ fragmentAncestorBoxes frag
        } | frag <- frags]
reconstructTree' :: Eq x => [Fragment x] -> [FragmentTree x]
reconstructTree' (self@Fragment { fragmentAncestorBoxes = [] }:frags) =
    Leaf self:reconstructTree' frags
reconstructTree' frags@(Fragment { fragmentAncestorBoxes = branch:_ }:_) =
    Branch branch (reconstructTree' [ child { fragmentAncestorBoxes = ancestors }
            | child@Fragment { fragmentAncestorBoxes = _:ancestors } <- childs])
        :reconstructTree' sibs
  where
    (childs, sibs) = span sameBranch frags
    sameBranch Fragment { fragmentAncestorBoxes = branch':_ } = branch == branch'
    sameBranch Fragment { fragmentAncestorBoxes = [] } = False
reconstructTree' [] = []

positionSubtree :: (Double, Double) -> FragmentTree (a, b, c) ->
        FragmentTree (a, b, ((Double, Double), c))
positionSubtree pos (Branch (AncestorBox (a, b, c) d e f g) childs) =
    Branch (AncestorBox (a, b, (pos, c)) d e f g) $
        map (positionSubtree pos) childs
positionSubtree pos (Leaf (Fragment (a, b, c) d _ f g h)) =
    Leaf (Fragment (a, b, (pos, c)) d [] f g h)
subtreeInner :: FragmentTree (a, b, c) -> c
subtreeInner (Branch AncestorBox { boxUserData = (_, _, ret) } _) = ret
subtreeInner (Leaf Fragment { fragmentUserData = (_, _, ret) }) = ret

M app/Main.hs => app/Main.hs +3 -2
@@ 72,13 72,14 @@ applyStyle parent style (X.Attr (X.QName name _ _) val) =
    fromMaybe style $ longhand parent style (Txt.pack name) $
        filter (/= Whitespace) $ tokenize $ Txt.pack val

data Nil = Nil
data Nil = Nil deriving Eq
instance PropertyParser Nil where
    temp = Nil
    inherit _ = Nil
    longhand _ _ _ _ = Nothing

renderDisplay :: GLuint -> LayoutItem Double Double ((Double, Double), a) -> IO ()
renderDisplay :: Eq a => GLuint -> LayoutItem Double Double ((Double, Double), a)
        -> IO ()
renderDisplay shader display = do
    let ((x, y), _) = layoutGetInner display
    let box = layoutGetBox display