{-# LANGUAGE TupleSections #-}
-- | Sizes inline text & extracts positioned children,
-- wraps Balkón for the actual logic.
module Graphics.Layout.Inline(inlineMinWidth, inlineMin, inlineNatWidth, inlineHeight,
    inlineSize, inlineChildren, layoutSize, layoutChildren,
    fragmentSize, fragmentSize', fragmentPos) where

import Data.Text.ParagraphLayout (Paragraph(..), ParagraphOptions(..),
                                    SpanLayout(..), Fragment(..),
                                    ParagraphLayout(..), layoutPlain, Span(..))
import Data.Text.ParagraphLayout.Rect (Rect(..), width, height, x_min, y_min)
import Data.Text.Internal (Text(..))
import qualified Data.Text as Txt
import Data.Char (isSpace)
import Data.Int (Int32)

import Graphics.Layout.Box (Size(..), CastDouble(..), fromDouble)
import Graphics.Layout.CSS.Font (Font', hbScale)

-- | Convert from Harfbuzz units to device pixels as a Double
hbScale' :: Font' -> a -> Double
hbScale' font :: Font'
font = (Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Font' -> Double
hbScale Font'
font) (Double -> Double) -> (a -> Double) -> a -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral
-- | Convert from Harfbuzz units to device pixels as a Double or Length.
c :: Font' -> a -> c
c font :: Font'
font = Double -> c
forall a. CastDouble a => Double -> a
fromDouble (Double -> c) -> (a -> Double) -> a -> c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Font' -> a -> Double
forall a. Integral a => Font' -> a -> Double
hbScale' Font'
font

-- | Compute minimum width for some richtext.
inlineMinWidth :: Font' -> Paragraph -> Double
inlineMinWidth :: Font' -> Paragraph -> Double
inlineMinWidth font :: Font'
font self :: Paragraph
self = Font' -> Int32 -> Double
forall a. Integral a => Font' -> a -> Double
hbScale' Font'
font (Int32 -> Double) -> Int32 -> Double
forall a b. (a -> b) -> a -> b
$ Rect Int32 -> Int32
forall a. Num a => Rect a -> a
width (Rect Int32 -> Int32) -> Rect Int32 -> Int32
forall a b. (a -> b) -> a -> b
$ Paragraph -> Int32 -> Rect Int32
layoutPlain' Paragraph
self 0
-- | Compute minimum width & height for some richtext.
inlineMin :: (CastDouble x, CastDouble y) => Font' -> Paragraph -> Size x y
inlineMin :: Font' -> Paragraph -> Size x y
inlineMin font :: Font'
font self :: Paragraph
self = y -> x -> Size x y
forall m n. n -> m -> Size m n
Size (Font' -> Int32 -> y
forall c a. (CastDouble c, Integral a) => Font' -> a -> c
c Font'
font (Int32 -> y) -> Int32 -> y
forall a b. (a -> b) -> a -> b
$ Rect Int32 -> Int32
forall a. Num a => Rect a -> a
width Rect Int32
rect) (Font' -> Int32 -> x
forall c a. (CastDouble c, Integral a) => Font' -> a -> c
c Font'
font (Int32 -> x) -> Int32 -> x
forall a b. (a -> b) -> a -> b
$ Rect Int32 -> Int32
forall a. Num a => Rect a -> a
height Rect Int32
rect)
    where rect :: Rect Int32
rect = Paragraph -> Int32 -> Rect Int32
layoutPlain' Paragraph
self 0
-- | Compute natural (single-line) width for some richtext.
inlineNatWidth :: Font' -> Paragraph -> Double
inlineNatWidth :: Font' -> Paragraph -> Double
inlineNatWidth font :: Font'
font self :: Paragraph
self = Font' -> Int32 -> Double
forall a. Integral a => Font' -> a -> Double
hbScale' Font'
font (Int32 -> Double) -> Int32 -> Double
forall a b. (a -> b) -> a -> b
$ Rect Int32 -> Int32
forall a. Num a => Rect a -> a
width (Rect Int32 -> Int32) -> Rect Int32 -> Int32
forall a b. (a -> b) -> a -> b
$ Paragraph -> Int32 -> Rect Int32
layoutPlain' Paragraph
self Int32
forall a. Bounded a => a
maxBound
-- | Compute height for rich text at given width.
inlineHeight :: Font' -> Double -> Paragraph -> Double
inlineHeight :: Font' -> Double -> Paragraph -> Double
inlineHeight font :: Font'
font width :: Double
width self :: Paragraph
self =
    Font' -> Int32 -> Double
forall a. Integral a => Font' -> a -> Double
hbScale' Font'
font (Int32 -> Double) -> Int32 -> Double
forall a b. (a -> b) -> a -> b
$ Rect Int32 -> Int32
forall a. Num a => Rect a -> a
height (Rect Int32 -> Int32) -> Rect Int32 -> Int32
forall a b. (a -> b) -> a -> b
$ Paragraph -> Int32 -> Rect Int32
layoutPlain' Paragraph
self (Int32 -> Rect Int32) -> Int32 -> Rect Int32
forall a b. (a -> b) -> a -> b
$ Double -> Int32
forall a b. (RealFrac a, Integral b) => a -> b
round (Font' -> Double
hbScale Font'
font Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
width)

-- | Compute width & height of some richtext at configured width.
inlineSize :: (CastDouble x, CastDouble y) => Font' -> Paragraph -> Size x y
inlineSize :: Font' -> Paragraph -> Size x y
inlineSize font :: Font'
font self :: Paragraph
self = Font' -> ParagraphLayout -> Size x y
forall x y.
(CastDouble x, CastDouble y) =>
Font' -> ParagraphLayout -> Size x y
layoutSize Font'
font (ParagraphLayout -> Size x y) -> ParagraphLayout -> Size x y
forall a b. (a -> b) -> a -> b
$ Paragraph -> ParagraphLayout
layoutPlain Paragraph
self
-- | Retrieve children out of some richtext,
-- associating given userdata with them.
inlineChildren :: [x] -> Paragraph -> [(x, Fragment)]
inlineChildren :: [x] -> Paragraph -> [(x, Fragment)]
inlineChildren vals :: [x]
vals self :: Paragraph
self = [x] -> ParagraphLayout -> [(x, Fragment)]
forall x. [x] -> ParagraphLayout -> [(x, Fragment)]
layoutChildren [x]
vals (ParagraphLayout -> [(x, Fragment)])
-> ParagraphLayout -> [(x, Fragment)]
forall a b. (a -> b) -> a -> b
$ Paragraph -> ParagraphLayout
layoutPlain Paragraph
self

-- | Retrieve a laid-out paragraph's rect & convert to CatTrap types.
layoutSize :: (CastDouble x, CastDouble y) => Font' -> ParagraphLayout -> Size x y
layoutSize :: Font' -> ParagraphLayout -> Size x y
layoutSize font :: Font'
font self :: ParagraphLayout
self = y -> x -> Size x y
forall m n. n -> m -> Size m n
Size (Font' -> Int32 -> y
forall c a. (CastDouble c, Integral a) => Font' -> a -> c
c Font'
font (Int32 -> y) -> Int32 -> y
forall a b. (a -> b) -> a -> b
$ Rect Int32 -> Int32
forall a. Num a => Rect a -> a
width Rect Int32
r) (Font' -> Int32 -> x
forall c a. (CastDouble c, Integral a) => Font' -> a -> c
c Font'
font (Int32 -> x) -> Int32 -> x
forall a b. (a -> b) -> a -> b
$ Rect Int32 -> Int32
forall a. Num a => Rect a -> a
height Rect Int32
r)
  where r :: Rect Int32
r = ParagraphLayout -> Rect Int32
paragraphRect ParagraphLayout
self
-- | Retrieve a laid-out paragraph's children & associate with given userdata.
layoutChildren :: [x] -> ParagraphLayout -> [(x, Fragment)]
layoutChildren :: [x] -> ParagraphLayout -> [(x, Fragment)]
layoutChildren vals :: [x]
vals self :: ParagraphLayout
self = [x] -> [Fragment] -> [(x, Fragment)]
forall a b. [a] -> [b] -> [(a, b)]
zip [x]
vals ([Fragment] -> [(x, Fragment)]) -> [Fragment] -> [(x, Fragment)]
forall a b. (a -> b) -> a -> b
$ [[Fragment]] -> [Fragment]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Fragment]] -> [Fragment]) -> [[Fragment]] -> [Fragment]
forall a b. (a -> b) -> a -> b
$ (SpanLayout -> [Fragment]) -> [SpanLayout] -> [[Fragment]]
forall a b. (a -> b) -> [a] -> [b]
map SpanLayout -> [Fragment]
inner ([SpanLayout] -> [[Fragment]]) -> [SpanLayout] -> [[Fragment]]
forall a b. (a -> b) -> a -> b
$ ParagraphLayout -> [SpanLayout]
spanLayouts ParagraphLayout
self
  where inner :: SpanLayout -> [Fragment]
inner (SpanLayout y :: [Fragment]
y) = [Fragment]
y

-- | Layout a paragraph at given width & retrieve resulting rect.
layoutPlain' :: Paragraph -> Int32 -> Rect Int32
layoutPlain' :: Paragraph -> Int32 -> Rect Int32
layoutPlain' (Paragraph a :: Array
a b :: Int
b c :: [Span]
c d :: ParagraphOptions
d) width :: Int32
width =
    ParagraphLayout -> Rect Int32
paragraphRect (ParagraphLayout -> Rect Int32) -> ParagraphLayout -> Rect Int32
forall a b. (a -> b) -> a -> b
$ Paragraph -> ParagraphLayout
layoutPlain (Paragraph -> ParagraphLayout) -> Paragraph -> ParagraphLayout
forall a b. (a -> b) -> a -> b
$ Array -> Int -> [Span] -> ParagraphOptions -> Paragraph
Paragraph Array
a Int
b [Span]
c ParagraphOptions
d { paragraphMaxWidth :: Int32
paragraphMaxWidth = Int32
width }

-- | Retrieve the rect for a fragment & convert to CatTrap types.
fragmentSize :: (CastDouble x, CastDouble y) => Font' -> Fragment -> Size x y
fragmentSize :: Font' -> Fragment -> Size x y
fragmentSize font :: Font'
font self :: Fragment
self = y -> x -> Size x y
forall m n. n -> m -> Size m n
Size (Font' -> Int32 -> y
forall c a. (CastDouble c, Integral a) => Font' -> a -> c
c Font'
font (Int32 -> y) -> Int32 -> y
forall a b. (a -> b) -> a -> b
$ Rect Int32 -> Int32
forall a. Num a => Rect a -> a
width Rect Int32
r) (Font' -> Int32 -> x
forall c a. (CastDouble c, Integral a) => Font' -> a -> c
c Font'
font (Int32 -> x) -> Int32 -> x
forall a b. (a -> b) -> a -> b
$ Rect Int32 -> Int32
forall a. Num a => Rect a -> a
height Rect Int32
r)
    where r :: Rect Int32
r = Fragment -> Rect Int32
fragmentRect Fragment
self
-- | Variant of `fragmentSize` asserting to the typesystem that both fields
-- of the resulting `Size` are of the same type.
fragmentSize' :: CastDouble x => Font' -> Fragment -> Size x x
fragmentSize' :: Font' -> Fragment -> Size x x
fragmentSize' = Font' -> Fragment -> Size x x
forall x y.
(CastDouble x, CastDouble y) =>
Font' -> Fragment -> Size x y
fragmentSize -- Work around for typesystem.
-- | Retrieve the position of a fragment.
fragmentPos :: Font' -> (Double, Double) -> Fragment -> (Double, Double)
fragmentPos :: Font' -> (Double, Double) -> Fragment -> (Double, Double)
fragmentPos font :: Font'
font (x :: Double
x, y :: Double
y) self :: Fragment
self =
        (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Font' -> Int32 -> Double
forall a. Integral a => Font' -> a -> Double
hbScale' Font'
font (Rect Int32 -> Int32
forall a. (Num a, Ord a) => Rect a -> a
x_min Rect Int32
r), Double
y Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Font' -> Int32 -> Double
forall a. Integral a => Font' -> a -> Double
hbScale' Font'
font (Rect Int32 -> Int32
forall a. (Num a, Ord a) => Rect a -> a
y_min Rect Int32
r))
    where r :: Rect Int32
r = Fragment -> Rect Int32
fragmentRect Fragment
self