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