{-# LANGUAGE RecordWildCards #-}
-- | Datastructures representing the CSS box model,
-- & utilities for operating on them.
module Graphics.Layout.Box(Border(..), mapX, mapY,
        Size(..), mapSizeX, mapSizeY,
        PaddedBox(..), zeroBox, lengthBox, mapX', mapY',
        width, height, minWidth, minHeight, maxWidth, maxHeight,
        Length(..), mapAuto, lowerLength, Zero(..), CastDouble(..)) where

-- | Amount of space surrounding the box.
data Border m n = Border {
    Border m n -> m
top :: m, Border m n -> m
bottom :: m, Border m n -> n
left :: n, Border m n -> n
right :: n
}
-- | Convert horizontal spacing via given callback.
mapX :: (n -> nn) -> Border m n -> Border m nn
-- | Convert vertical spacing via given callback.
mapY :: (m -> mm) -> Border m n -> Border mm n
mapX :: (n -> nn) -> Border m n -> Border m nn
mapX cb :: n -> nn
cb self :: Border m n
self = Border m n
self { left :: nn
left = n -> nn
cb (n -> nn) -> n -> nn
forall a b. (a -> b) -> a -> b
$ Border m n -> n
forall m n. Border m n -> n
left Border m n
self, right :: nn
right = n -> nn
cb (n -> nn) -> n -> nn
forall a b. (a -> b) -> a -> b
$ Border m n -> n
forall m n. Border m n -> n
right Border m n
self }
mapY :: (m -> mm) -> Border m n -> Border mm n
mapY cb :: m -> mm
cb self :: Border m n
self = Border m n
self { top :: mm
top = m -> mm
cb (m -> mm) -> m -> mm
forall a b. (a -> b) -> a -> b
$ Border m n -> m
forall m n. Border m n -> m
top Border m n
self, bottom :: mm
bottom = m -> mm
cb (m -> mm) -> m -> mm
forall a b. (a -> b) -> a -> b
$ Border m n -> m
forall m n. Border m n -> m
bottom Border m n
self }

-- | 2D size of a box. Typically inline is width & block is height.
-- This may change as support for vertical layout is added.
data Size m n = Size {Size m n -> n
inline :: n, Size m n -> m
block :: m} deriving (Size m n -> Size m n -> Bool
(Size m n -> Size m n -> Bool)
-> (Size m n -> Size m n -> Bool) -> Eq (Size m n)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall m n. (Eq n, Eq m) => Size m n -> Size m n -> Bool
/= :: Size m n -> Size m n -> Bool
$c/= :: forall m n. (Eq n, Eq m) => Size m n -> Size m n -> Bool
== :: Size m n -> Size m n -> Bool
$c== :: forall m n. (Eq n, Eq m) => Size m n -> Size m n -> Bool
Eq, Int -> Size m n -> ShowS
[Size m n] -> ShowS
Size m n -> String
(Int -> Size m n -> ShowS)
-> (Size m n -> String) -> ([Size m n] -> ShowS) -> Show (Size m n)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall m n. (Show n, Show m) => Int -> Size m n -> ShowS
forall m n. (Show n, Show m) => [Size m n] -> ShowS
forall m n. (Show n, Show m) => Size m n -> String
showList :: [Size m n] -> ShowS
$cshowList :: forall m n. (Show n, Show m) => [Size m n] -> ShowS
show :: Size m n -> String
$cshow :: forall m n. (Show n, Show m) => Size m n -> String
showsPrec :: Int -> Size m n -> ShowS
$cshowsPrec :: forall m n. (Show n, Show m) => Int -> Size m n -> ShowS
Show)
-- | Convert inline size via given callback
mapSizeY :: (m -> mm) -> Size m n -> Size mm n
mapSizeY :: (m -> mm) -> Size m n -> Size mm n
mapSizeY cb :: m -> mm
cb self :: Size m n
self = n -> mm -> Size mm n
forall m n. n -> m -> Size m n
Size (Size m n -> n
forall m n. Size m n -> n
inline Size m n
self) (m -> mm
cb (m -> mm) -> m -> mm
forall a b. (a -> b) -> a -> b
$ Size m n -> m
forall m n. Size m n -> m
block Size m n
self)
-- | Convert block size via given callback
mapSizeX :: (n -> nn) -> Size m n -> Size m nn
mapSizeX :: (n -> nn) -> Size m n -> Size m nn
mapSizeX cb :: n -> nn
cb self :: Size m n
self = nn -> m -> Size m nn
forall m n. n -> m -> Size m n
Size (n -> nn
cb (n -> nn) -> n -> nn
forall a b. (a -> b) -> a -> b
$ Size m n -> n
forall m n. Size m n -> n
inline Size m n
self) (Size m n -> m
forall m n. Size m n -> m
block Size m n
self)

-- | A box with min & max bounds & surrounding borders. The CSS Box Model.
data PaddedBox m n = PaddedBox {
    -- | The minimum amount of pixels this box should take.
    PaddedBox m n -> Size m n
min :: Size m n,
    -- | The maximum amount of pixels this box should take.
    PaddedBox m n -> Size m n
max :: Size m n,
    -- | The ideal number of pixels this box should take.
    PaddedBox m n -> Size Double Double
nat :: Size Double Double,
    -- | The amount of pixels this box should take.
    PaddedBox m n -> Size m n
size :: Size m n,
    -- | The amount of space between the box & the border.
    PaddedBox m n -> Border m n
padding :: Border m n,
    -- | The amount of space for the border.
    PaddedBox m n -> Border m n
border :: Border m n,
    -- | The amount of space between the border & anything else.
    PaddedBox m n -> Border m n
margin :: Border m n
}
-- | An empty box, takes up nospace onscreen.
zeroBox :: PaddedBox Double Double
zeroBox :: PaddedBox Double Double
zeroBox = PaddedBox :: forall m n.
Size m n
-> Size m n
-> Size Double Double
-> Size m n
-> Border m n
-> Border m n
-> Border m n
-> PaddedBox m n
PaddedBox {
    min :: Size Double Double
min = Double -> Double -> Size Double Double
forall m n. n -> m -> Size m n
Size 0 0,
    max :: Size Double Double
max = Double -> Double -> Size Double Double
forall m n. n -> m -> Size m n
Size 0 0,
    nat :: Size Double Double
nat = Double -> Double -> Size Double Double
forall m n. n -> m -> Size m n
Size 0 0,
    size :: Size Double Double
size = Double -> Double -> Size Double Double
forall m n. n -> m -> Size m n
Size 0 0,
    padding :: Border Double Double
padding = Double -> Double -> Double -> Double -> Border Double Double
forall m n. m -> m -> n -> n -> Border m n
Border 0 0 0 0,
    border :: Border Double Double
border = Double -> Double -> Double -> Double -> Border Double Double
forall m n. m -> m -> n -> n -> Border m n
Border 0 0 0 0,
    margin :: Border Double Double
margin = Double -> Double -> Double -> Double -> Border Double Double
forall m n. m -> m -> n -> n -> Border m n
Border 0 0 0 0
  }
-- | A box which takes up all available space with no borders.
lengthBox :: PaddedBox Length Length
lengthBox :: PaddedBox Length Length
lengthBox = PaddedBox :: forall m n.
Size m n
-> Size m n
-> Size Double Double
-> Size m n
-> Border m n
-> Border m n
-> Border m n
-> PaddedBox m n
PaddedBox {
    min :: Size Length Length
min = Length -> Length -> Size Length Length
forall m n. n -> m -> Size m n
Size Length
Auto Length
Auto,
    max :: Size Length Length
max = Length -> Length -> Size Length Length
forall m n. n -> m -> Size m n
Size Length
Auto Length
Auto,
    nat :: Size Double Double
nat = Double -> Double -> Size Double Double
forall m n. n -> m -> Size m n
Size 0 0,
    size :: Size Length Length
size = Length -> Length -> Size Length Length
forall m n. n -> m -> Size m n
Size Length
Auto Length
Auto,
    padding :: Border Length Length
padding = Length -> Length -> Length -> Length -> Border Length Length
forall m n. m -> m -> n -> n -> Border m n
Border Length
forall a. Zero a => a
zero Length
forall a. Zero a => a
zero Length
forall a. Zero a => a
zero Length
forall a. Zero a => a
zero,
    border :: Border Length Length
border = Length -> Length -> Length -> Length -> Border Length Length
forall m n. m -> m -> n -> n -> Border m n
Border Length
forall a. Zero a => a
zero Length
forall a. Zero a => a
zero Length
forall a. Zero a => a
zero Length
forall a. Zero a => a
zero,
    margin :: Border Length Length
margin = Length -> Length -> Length -> Length -> Border Length Length
forall m n. m -> m -> n -> n -> Border m n
Border Length
forall a. Zero a => a
zero Length
forall a. Zero a => a
zero Length
forall a. Zero a => a
zero Length
forall a. Zero a => a
zero
  }

-- | Convert all sizes along the inline axis via given callback.
mapX' :: (n -> nn) -> PaddedBox m n -> PaddedBox m nn
mapX' :: (n -> nn) -> PaddedBox m n -> PaddedBox m nn
mapX' cb :: n -> nn
cb PaddedBox {..} = PaddedBox :: forall m n.
Size m n
-> Size m n
-> Size Double Double
-> Size m n
-> Border m n
-> Border m n
-> Border m n
-> PaddedBox m n
PaddedBox {
    min :: Size m nn
min = nn -> m -> Size m nn
forall m n. n -> m -> Size m n
Size (n -> nn
cb (n -> nn) -> n -> nn
forall a b. (a -> b) -> a -> b
$ Size m n -> n
forall m n. Size m n -> n
inline Size m n
min) (Size m n -> m
forall m n. Size m n -> m
block Size m n
min),
    size :: Size m nn
size = nn -> m -> Size m nn
forall m n. n -> m -> Size m n
Size (n -> nn
cb (n -> nn) -> n -> nn
forall a b. (a -> b) -> a -> b
$ Size m n -> n
forall m n. Size m n -> n
inline Size m n
size) (Size m n -> m
forall m n. Size m n -> m
block Size m n
size),
    nat :: Size Double Double
nat = Double -> Double -> Size Double Double
forall m n. n -> m -> Size m n
Size 0 0,
    max :: Size m nn
max = nn -> m -> Size m nn
forall m n. n -> m -> Size m n
Size (n -> nn
cb (n -> nn) -> n -> nn
forall a b. (a -> b) -> a -> b
$ Size m n -> n
forall m n. Size m n -> n
inline Size m n
max) (Size m n -> m
forall m n. Size m n -> m
block Size m n
max),
    padding :: Border m nn
padding = (n -> nn) -> Border m n -> Border m nn
forall n nn m. (n -> nn) -> Border m n -> Border m nn
mapX n -> nn
cb Border m n
padding,
    border :: Border m nn
border = (n -> nn) -> Border m n -> Border m nn
forall n nn m. (n -> nn) -> Border m n -> Border m nn
mapX n -> nn
cb Border m n
border,
    margin :: Border m nn
margin = (n -> nn) -> Border m n -> Border m nn
forall n nn m. (n -> nn) -> Border m n -> Border m nn
mapX n -> nn
cb Border m n
margin
  }
-- | Convert all sizes along the block axis via given callback.
mapY' :: (m -> mm) -> PaddedBox m n -> PaddedBox mm n
mapY' :: (m -> mm) -> PaddedBox m n -> PaddedBox mm n
mapY' cb :: m -> mm
cb PaddedBox {..} = PaddedBox :: forall m n.
Size m n
-> Size m n
-> Size Double Double
-> Size m n
-> Border m n
-> Border m n
-> Border m n
-> PaddedBox m n
PaddedBox {
    min :: Size mm n
min = n -> mm -> Size mm n
forall m n. n -> m -> Size m n
Size (Size m n -> n
forall m n. Size m n -> n
inline Size m n
min) (m -> mm
cb (m -> mm) -> m -> mm
forall a b. (a -> b) -> a -> b
$ Size m n -> m
forall m n. Size m n -> m
block Size m n
min),
    size :: Size mm n
size = n -> mm -> Size mm n
forall m n. n -> m -> Size m n
Size (Size m n -> n
forall m n. Size m n -> n
inline Size m n
size) (m -> mm
cb (m -> mm) -> m -> mm
forall a b. (a -> b) -> a -> b
$ Size m n -> m
forall m n. Size m n -> m
block Size m n
size),
    nat :: Size Double Double
nat = Double -> Double -> Size Double Double
forall m n. n -> m -> Size m n
Size 0 0,
    max :: Size mm n
max = n -> mm -> Size mm n
forall m n. n -> m -> Size m n
Size (Size m n -> n
forall m n. Size m n -> n
inline Size m n
max) (m -> mm
cb (m -> mm) -> m -> mm
forall a b. (a -> b) -> a -> b
$ Size m n -> m
forall m n. Size m n -> m
block Size m n
max),
    padding :: Border mm n
padding = (m -> mm) -> Border m n -> Border mm n
forall m mm n. (m -> mm) -> Border m n -> Border mm n
mapY m -> mm
cb Border m n
padding,
    border :: Border mm n
border = (m -> mm) -> Border m n -> Border mm n
forall m mm n. (m -> mm) -> Border m n -> Border mm n
mapY m -> mm
cb Border m n
border,
    margin :: Border mm n
margin = (m -> mm) -> Border m n -> Border mm n
forall m mm n. (m -> mm) -> Border m n -> Border mm n
mapY m -> mm
cb Border m n
margin
  }

-- | The total size along the inline axis including borders, etc.
width :: PaddedBox m n -> n
width PaddedBox {..} = Border m n -> n
forall m n. Border m n -> n
left Border m n
margin n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
left Border m n
border n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
left Border m n
padding n -> n -> n
forall a. Num a => a -> a -> a
+
    Size m n -> n
forall m n. Size m n -> n
inline Size m n
size n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
right Border m n
padding n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
right Border m n
border n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
right Border m n
margin
-- | The total size along the block axis, including borders, etc.
height :: PaddedBox m n -> m
height PaddedBox {..} = Border m n -> m
forall m n. Border m n -> m
top Border m n
margin m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
top Border m n
border m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
top Border m n
padding m -> m -> m
forall a. Num a => a -> a -> a
+
    Size m n -> m
forall m n. Size m n -> m
block Size m n
size m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
bottom Border m n
padding m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
bottom Border m n
border m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
bottom Border m n
margin
-- | The total minimum size along the inline axis.
minWidth :: PaddedBox m n -> n
minWidth PaddedBox {..} = Border m n -> n
forall m n. Border m n -> n
left Border m n
margin n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
left Border m n
border n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
left Border m n
padding n -> n -> n
forall a. Num a => a -> a -> a
+
    Size m n -> n
forall m n. Size m n -> n
inline Size m n
min n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
right Border m n
padding n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
right Border m n
border n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
right Border m n
margin
-- | The total minimum size along the block axis.
minHeight :: PaddedBox m n -> m
minHeight PaddedBox {..} = Border m n -> m
forall m n. Border m n -> m
top Border m n
margin m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
top Border m n
border m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
top Border m n
padding m -> m -> m
forall a. Num a => a -> a -> a
+
    Size m n -> m
forall m n. Size m n -> m
block Size m n
min m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
bottom Border m n
padding m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
bottom Border m n
border m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
bottom Border m n
margin
-- | The total maximum size along the inline axis.
maxWidth :: PaddedBox m n -> n
maxWidth PaddedBox {..} = Border m n -> n
forall m n. Border m n -> n
left Border m n
margin n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
left Border m n
border n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
left Border m n
padding n -> n -> n
forall a. Num a => a -> a -> a
+
    Size m n -> n
forall m n. Size m n -> n
inline Size m n
max n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
right Border m n
padding n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
right Border m n
border n -> n -> n
forall a. Num a => a -> a -> a
+ Border m n -> n
forall m n. Border m n -> n
right Border m n
margin
-- | The total maximum size along the block axis.
maxHeight :: PaddedBox m n -> m
maxHeight PaddedBox {..} = Border m n -> m
forall m n. Border m n -> m
top Border m n
margin m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
top Border m n
border m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
top Border m n
padding m -> m -> m
forall a. Num a => a -> a -> a
+
    Size m n -> m
forall m n. Size m n -> m
block Size m n
max m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
bottom Border m n
padding m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
bottom Border m n
border m -> m -> m
forall a. Num a => a -> a -> a
+ Border m n -> m
forall m n. Border m n -> m
bottom Border m n
margin

-- | A partially-computed length value.
data Length = Pixels Double -- ^ Absolute number of device pixels.
        | Percent Double -- ^ Multiplier by container width.
        | Auto -- ^ Use normal layout computations.
        | Preferred -- ^ Use computed preferred width.
        | Min -- ^ Use minimum legible width.
        deriving Length -> Length -> Bool
(Length -> Length -> Bool)
-> (Length -> Length -> Bool) -> Eq Length
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Length -> Length -> Bool
$c/= :: Length -> Length -> Bool
== :: Length -> Length -> Bool
$c== :: Length -> Length -> Bool
Eq

-- | Convert a length given the container's width. Filling in 0 for keywords.
-- If you wish for keywords to be handled differently, callers need to compute
-- that themselves.
lowerLength :: Double -> Length -> Double
lowerLength :: Double -> Length -> Double
lowerLength _ (Pixels x :: Double
x) = Double
x
lowerLength outerwidth :: Double
outerwidth (Percent x :: Double
x) = Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
outerwidth
lowerLength _ _ = 0

-- | Replace keywords with a given number of pixels.
-- Useful for avoiding messing up percentage calculations in later processing.
mapAuto :: Double -> Length -> Length
mapAuto x :: Double
x Auto = Double -> Length
Pixels Double
x
mapAuto x :: Double
x Preferred = Double -> Length
Pixels Double
x
mapAuto x :: Double
x Min = Double -> Length
Pixels Double
x
mapAuto _ x :: Length
x = Length
x

class Zero a where
    -- | Return the empty (or zero) value for a CatTrap geometric type.
    zero :: a

instance Zero Double where zero :: Double
zero = 0
instance Zero Length where zero :: Length
zero = Double -> Length
Pixels 0
instance (Zero m, Zero n) => Zero (PaddedBox m n) where
    zero :: PaddedBox m n
zero = PaddedBox :: forall m n.
Size m n
-> Size m n
-> Size Double Double
-> Size m n
-> Border m n
-> Border m n
-> Border m n
-> PaddedBox m n
PaddedBox {
        min :: Size m n
min = n -> m -> Size m n
forall m n. n -> m -> Size m n
Size n
forall a. Zero a => a
zero m
forall a. Zero a => a
zero,
        max :: Size m n
max = n -> m -> Size m n
forall m n. n -> m -> Size m n
Size n
forall a. Zero a => a
zero m
forall a. Zero a => a
zero,
        nat :: Size Double Double
nat = Double -> Double -> Size Double Double
forall m n. n -> m -> Size m n
Size 0 0,
        size :: Size m n
size = n -> m -> Size m n
forall m n. n -> m -> Size m n
Size n
forall a. Zero a => a
zero m
forall a. Zero a => a
zero,
        padding :: Border m n
padding = m -> m -> n -> n -> Border m n
forall m n. m -> m -> n -> n -> Border m n
Border m
forall a. Zero a => a
zero m
forall a. Zero a => a
zero n
forall a. Zero a => a
zero n
forall a. Zero a => a
zero,
        border :: Border m n
border = m -> m -> n -> n -> Border m n
forall m n. m -> m -> n -> n -> Border m n
Border m
forall a. Zero a => a
zero m
forall a. Zero a => a
zero n
forall a. Zero a => a
zero n
forall a. Zero a => a
zero,
        margin :: Border m n
margin = m -> m -> n -> n -> Border m n
forall m n. m -> m -> n -> n -> Border m n
Border m
forall a. Zero a => a
zero m
forall a. Zero a => a
zero n
forall a. Zero a => a
zero n
forall a. Zero a => a
zero
    }

class CastDouble a where
    -- | Convert a double to a double or length.
    fromDouble :: Double -> a
    -- | Convert a double or length to a double.
    toDouble :: a -> Double

instance CastDouble Double where
    fromDouble :: Double -> Double
fromDouble = Double -> Double
forall a. a -> a
id
    toDouble :: Double -> Double
toDouble = Double -> Double
forall a. a -> a
id
instance CastDouble Length where
    fromDouble :: Double -> Length
fromDouble = Double -> Length
Pixels
    toDouble :: Length -> Double
toDouble = Double -> Length -> Double
lowerLength 0