M Graphics/Layout.hs => Graphics/Layout.hs +2 -2
@@ 8,7 8,7 @@ data LayoutItem m n x =
| LayoutGrid x (Grid m n) [(GridItem m n, LayoutItem m n x)]
-- More to come...
-boxMinWidth :: Double -> LayoutItem y Length x -> (Double, LayoutItem y Length x)
+{-boxMinWidth :: Double -> LayoutItem y Length x -> (Double, LayoutItem y Length x)
boxNatWidth :: Double -> LayoutItem y Length x -> (Double, LayoutItem y Length x)
boxMaxWidth :: PaddedBox y Length -> LayoutItem y Length x -> (Double, LayoutItem y Length x)
boxWidth :: PaddedBox y Length -> LayoutItem y Length x -> (Double, LayoutItem y Double x)
@@ 18,4 18,4 @@ boxMaxHeight :: Double -> LayoutItem Length Double x -> (Double, LayoutItem Leng
boxHeight :: Double -> LayoutItem Length Double x -> (Double, LayoutItem Length Length x)
boxPosition :: LayoutItem Double Double x -> LayoutItem Double Double x
boxLayout :: PaddedBox Double Double -> LayoutItem Length Length x -> Bool ->
- LayoutItem Double Double x
+ LayoutItem Double Double x-}
M Graphics/Layout/Box.hs => Graphics/Layout/Box.hs +23 -1
@@ 19,6 19,24 @@ data PaddedBox m n = PaddedBox {
border :: Border m n,
margin :: Border m n
}
+zeroBox :: PaddedBox Double Double
+zeroBox = PaddedBox {
+ min = Size 0 0,
+ max = Size 0 0,
+ size = Size 0 0,
+ padding = Border 0 0 0 0,
+ border = Border 0 0 0 0,
+ margin = Border 0 0 0 0
+ }
+lengthBox = PaddedBox {
+ min = Size Auto Auto,
+ max = Size Auto Auto,
+ size = Size Auto Auto,
+ padding = Border zero zero zero zero,
+ border = Border zero zero zero zero,
+ margin = Border zero zero zero zero
+ } where zero = Pixels 0
+
width PaddedBox {..} = left margin + left border + left padding +
inline size + right padding + right border + right margin
height PaddedBox {..} = top margin + top border + top padding +
@@ 27,5 45,9 @@ minWidth PaddedBox {..} = left margin + left border + left padding +
inline min + right padding + right border + right margin
minHeight PaddedBox {..} = top margin + top border + top padding +
block min + bottom padding + bottom border + bottom margin
+maxWidth PaddedBox {..} = left margin + left border + left padding +
+ inline max + right padding + right border + right margin
+maxHeight PaddedBox {..} = top margin + top border + top padding +
+ block max + bottom padding + bottom border + bottom margin
-data Length = Pixels Double | Percent Double | Auto | Preferred | Min
+data Length = Pixels Double | Percent Double | Auto | Preferred | Min deriving Eq
M Graphics/Layout/CSS.hs => Graphics/Layout/CSS.hs +2 -1
@@ 5,11 5,12 @@ import Graphics.Layout
data CSSBox = CSSBox {
boxSizing :: BoxSizing,
- cssBox :: PaddedBox (Double, String) -- Some units need to be resolved per font. calc()?
+ cssBox :: PaddedBox Unitted Unitted -- Some units need to be resolved per font. calc()?
-- Other layout-mode specific properties?
-- Resolve font here so we can resolve those units?
}
data BoxSizing = BorderBox | ContentBox
+type Unitted = (Double, String)
{-instance PropertyParser CSSBox where
...
M Graphics/Layout/Flow.hs => Graphics/Layout/Flow.hs +36 -31
@@ 2,40 2,41 @@ module Graphics.Layout.Flow where
import Graphics.Layout.Box as B
-flowMinWidth :: Double -> PaddedBox _ Length -> [PaddedBox _ Length] -> Double
+flowMinWidth :: Double -> PaddedBox a Length -> [PaddedBox b Double] -> Double
flowMinWidth _ PaddedBox {B.min = Size (Pixels x) _} _ = x
flowMinWidth parent PaddedBox {B.min = Size (Percent x) _} _ = x * parent
flowMinWidth parent self@PaddedBox {B.min = Size Preferred _} childs =
flowNatWidth parent self childs
-flowMinWidth _ _ childs = Prelude.max [
- minWidth $ child {B.min = flowMinWidth 0 child []} | child <- childs
- ]
-flowNatWidth :: Double -> PaddedBox _ Length -> [PaddedBox _ Length] -> Double
+flowMinWidth _ _ childs = maximum $ (0:) $ map minWidth childs
+flowNatWidth :: Double -> PaddedBox a Length -> [PaddedBox b Double] -> Double
flowNatWidth _ PaddedBox {size = Size (Pixels x) _} _ = x
flowNatWidth parent PaddedBox {size = Size (Percent x) _} _ = x * parent
flowNatWidth parent self@PaddedBox {size = Size Min _, B.min = Size x _} childs
-- Avoid infinite loops!
- | x /= Preferred = flowMinWidth parent self child
-flowNatWidth parent _ childs = Prelude.max [
- width $ child {B.width = flowNatWidth 0 child []} | child <- childs
- ]
-flowMaxWidth :: PaddedBox _ Double -> PaddedBox _ Length -> Double
+ | x /= Preferred = flowMinWidth parent self childs
+flowNatWidth parent _ childs = maximum $ (0:) $ map maxWidth childs
+flowMaxWidth :: PaddedBox a Double -> PaddedBox b Length -> Double
flowMaxWidth _ PaddedBox {B.max = Size (Pixels x) _} = x
-flowMaxWidth parent PaddedBox {B.max = Size (Percent x) _} = x * parent
-flowMaxWidth parent PaddedBox {B.max = Size Auto _} = inline $ size parent
+flowMaxWidth parent PaddedBox {B.max = Size (Percent x) _} = x * (inline $ size parent)
+flowMaxWidth parent self@PaddedBox {B.max = Size Auto _} = inline (size parent) - ws
+ where
+ ws = l2d (left $ margin self) + l2d (left $ border self) + l2d (left $ padding self) +
+ l2d (right $ padding self) + l2d (right $ border self) + l2d (right $ margin self)
+ l2d = lowerLength $ inline $ size parent
flowMaxWidth parent self@PaddedBox {B.max = Size Preferred _} =
flowNatWidth (inline $ size parent) self []
flowMaxWidth parent self@PaddedBox {B.max = Size Min _} =
flowMinWidth (inline $ B.min parent) self []
-flowWidth :: PaddedBox _ Double -> PaddedBox _ Length -> Double
+flowWidth :: PaddedBox a Double -> PaddedBox b Length -> Double
flowWidth parent self
| small > large = small
| natural > large = large
+ | inline (size self) == Auto = large -- specialcase
| natural >= small = natural
| otherwise = small
where
small = flowMinWidth (inline $ B.min parent) self []
- natural = flowNatWidth (inline $ width parent) self []
+ natural = flowNatWidth (inline $ size parent) self []
large = flowMaxWidth parent self
flowNatHeight :: Double -> PaddedBox Length Double -> [PaddedBox Double Double] -> Double
@@ 44,16 45,16 @@ flowNatHeight parent PaddedBox {size = Size _ (Percent y)} _ = y * parent
flowNatHeight _ PaddedBox {size = Size _ Min} childs =
sum $ map minHeight $ marginCollapse childs
flowNatHeight _ PaddedBox {size = Size owidth _} childs =
- sum $ map height $ marginCollapse (lowerLength owidth) childs
+ sum $ map height $ marginCollapse childs
flowMinHeight :: Double -> PaddedBox Length Double -> Double
flowMinHeight _ PaddedBox {B.min = Size _ (Pixels y)} = y
flowMinHeight parent PaddedBox {B.min = Size _ (Percent y)} = y * parent
-flowMinHeight _ self = flowNatHeight self []
+flowMinHeight parent self = flowNatHeight parent self []
flowMaxHeight :: Double -> PaddedBox Length Double -> Double
flowMaxHeight _ PaddedBox {B.max = Size _ (Pixels y)} = y
flowMaxHeight parent PaddedBox {B.max = Size _ (Percent y)} = y * parent
flowMaxHeight parent PaddedBox {B.max = Size _ Auto} = parent
-flowMaxHeight _ self@PaddedBox {B.max = Size _ Preferred} = flowNatHeight self []
+flowMaxHeight parent self@PaddedBox {B.max = Size _ Preferred} = flowNatHeight parent self []
flowMaxHeight parent self@PaddedBox {B.max = Size _ Min} = flowMinHeight parent self
flowHeight :: PaddedBox Double Double -> PaddedBox Length Double -> Double
flowHeight parent self
@@ 64,21 65,21 @@ flowHeight parent self
where
small = flowMinHeight (block $ B.min parent) self
natural = flowNatHeight (block $ size parent) self []
- large = flowMaxWidth (block $ B.max parent) self
+ large = flowMaxHeight (block $ B.max parent) self
positionFlow :: [PaddedBox Double Double] -> [Size Double Double]
-positionFlow childs = scanl inner (Size 0 0) $ marginCollapse id childs
+positionFlow childs = scanl inner (Size 0 0) $ marginCollapse childs
where inner (Size x y) self = Size x $ height self
layoutFlow :: PaddedBox Double Double -> PaddedBox Length Length ->
- [PaddedBox Length Length] -> Bool ->
- [(PaddedBox Double Double, [(Size Double Double, PaddedBox Double Double)])]
+ [PaddedBox Length Double] -> Bool ->
+ (PaddedBox Double Double, [(Size Double Double, PaddedBox Double Double)])
layoutFlow parent self childs paginate = (self', zip positions' childs')
where
positions' = positionFlow childs'
childs' = map layoutZooko childs
self' = self0 {
B.min = (B.min self0) { block = flowMinHeight (block $ B.min parent) self0 },
- size = (size self0) { block = flowHeight oheight self0 },
+ size = (size self0) { block = flowHeight parent self0 },
B.max = (B.max self0) { block = flowMaxHeight (block $ B.max parent) self0 },
padding = mapY (lowerLength owidth) $ padding self0,
border = mapY (lowerLength owidth) $ border self0,
@@ 91,28 92,32 @@ layoutFlow parent self childs paginate = (self', zip positions' childs')
size = (size self2) { inline = width' },
B.max = (B.max self2) { inline = flowMaxWidth parent self2 },
B.min = (B.min self2) { inline = flowMinWidth owidth self2 [] },
- padding = mapX (lowerLength owdith) $ padding self2,
+ padding = mapX (lowerLength owidth) $ padding self2,
border = mapX (lowerLength owidth) $ border self2,
margin = lowerMargin owidth (owidth - width') $ margin self2
}
- width' = flowWidth parent self2
+ width' = flowWidth parent self
self2 = self {
- size = (size self) { inline = Pixels $ flowNatWidth owidth self childs }
+ size = (size self) { inline = Pixels $ flowNatWidth owidth self childs },
B.min = (B.min self) { inline = Pixels $ flowMinWidth owidth self childs }
}
owidth = inline $ size parent
oheight = block $ size parent
layoutZooko child = child {
- B.min = Size (flowMinWidth (inline $ B.min self') child [])
- (flowMinHeight (block $ B.min self') child),
- size = Size (flowWidth self' child) (flowHeight (block $ size self') child),
- B.max = Size (flowMaxWidth self' child) (flowMaxHeight (block $ size self') child),
+ B.min = Size (inline $ B.min child) (flowMinHeight (block $ B.min self') child),
+ size = Size (inline $ size child) (flowHeight self' child),
+ B.max = Size (inline $ B.max child) (flowMaxHeight (block $ size self') child),
+ padding = mapY (lowerLength owidth) $ padding child,
+ border = mapY (lowerLength owidth) $ border child,
+ margin = mapY (lowerLength owidth) $ margin child
}
-marginCollapse cb (x'@PaddedBox {margin = xm@Border { bottom = x }}:
+marginCollapse :: [PaddedBox Double n] -> [PaddedBox Double n]
+marginCollapse (x'@PaddedBox {margin = xm@Border { bottom = x }}:
y'@PaddedBox {margin = ym@Border { top = y}}:rest)
- | cb x > cb y = x':marginCollapse (y' {margin = ym { top = 0 }}:rest)
+ | x > y = x':marginCollapse (y' {margin = ym { top = 0 }}:rest)
| otherwise = x' { margin = xm { bottom = 0 }}:marginCollapse (y':rest)
+marginCollapse rest = rest
lowerLength :: Double -> Length -> Double
lowerLength _ (Pixels x) = x
M Graphics/Layout/Grid.hs => Graphics/Layout/Grid.hs +2 -2
@@ 16,7 16,7 @@ data GridItem m n = GridItem {
type Name = Text
-gridMinWidths :: Double -> Grid y Length -> [GridItem y Length] -> (Double, [Double])
+{-gridMinWidths :: Double -> Grid y Length -> [GridItem y Length] -> (Double, [Double])
gridNatWidths :: Double -> Grid y Length -> [GridItem y Length] -> (Double, [Double])
gridMaxWidths :: PaddedBox y Double -> Grid y Length -> (Double, [Double])
gridWidths :: PaddedBox y Double -> Grid y Length -> (Double, [Double])
@@ 27,4 27,4 @@ gridHeights :: Double -> Grid Length Double -> (Double, [Double])
gridPosition :: GridLength Double Double -> [GridItem Double Double] -> [Size Double Double]
gridLayout :: PaddedBox Double Double -> Grid Length Length ->
[GridItem Length Length] -> Bool ->
- (Grid Double Double, [(Size Double Double, GridItem Double Double)])
+ (Grid Double Double, [(Size Double Double, GridItem Double Double)])-}
M test/Test.hs => test/Test.hs +74 -5
@@ 5,7 5,8 @@ import Test.Hspec
import Graphics.Layout.Arithmetic
import Data.CSS.Syntax.Tokens (tokenize, Token(..))
-import Debug.Trace (traceShowId)
+import Graphics.Layout.Box as B
+import Graphics.Layout.Flow
main :: IO ()
main = hspec spec
@@ 19,9 20,77 @@ spec = do
it "Can perform basic arithmatic" $ do
runMath "42" `shouldBe` 42
runMath "6 * 9" `shouldBe` 54
--- runMath "6 * 9 - 42" `shouldBe` 12
--- runMath "6 * (9 - 42)" `shouldBe` -198
--- runMath "6 * calc(9 - 42)" `shouldBe` -198
--- runMath "6 * abs(9 - 42)" `shouldBe` 198
+ runMath "6 * 9 - 42" `shouldBe` 12
+ runMath "6 * (9 - 42)" `shouldBe` -198
+ runMath "6 * calc(9 - 42)" `shouldBe` -198
+ runMath "6 * abs(9 - 42)" `shouldBe` 198
+ describe "Width sizing" $ do
+ -- Based on http://hixie.ch/tests/adhoc/css/box/block/
+ it "Can overflow parent" $ do
+ width (fst $ layoutFlow zeroBox {
+ size = Size 3 1
+ } lengthBox {
+ border = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2)
+ } [] False) `shouldBe` 4
+ width (fst $ layoutFlow zeroBox {
+ size = Size 3 1
+ } lengthBox {
+ padding = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2)
+ } [] False) `shouldBe` 4
+ width (fst $ layoutFlow zeroBox {
+ size = Size 3 1
+ } lengthBox {
+ margin = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2)
+ } [] False) `shouldBe` 4
+ it "Fits to parent" $ do
+ width (fst $ layoutFlow zeroBox {
+ size = Size 5 1
+ } lengthBox {
+ border = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2),
+ size = Size Auto $ Pixels 1
+ } [] False) `shouldBe` 5
+ width (fst $ layoutFlow zeroBox {
+ size = Size 5 1
+ } lengthBox {
+ padding = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2),
+ size = Size Auto $ Pixels 1
+ } [] False) `shouldBe` 5
+ width (fst $ layoutFlow zeroBox {
+ size = Size 5 1
+ } lengthBox {
+ margin = Border (Pixels 0) (Pixels 0) (Pixels 2) (Pixels 2),
+ size = Size Auto $ Pixels 1
+ } [] False) `shouldBe` 5
+ it "Collapses margins" $ do
+ let a :: PaddedBox Length Double
+ a = PaddedBox {
+ B.min = Size 0 Auto,
+ size = Size 0 Auto,
+ B.max = Size 0 Auto,
+ padding = Border (Pixels 0) (Pixels 0) 0 0,
+ border = Border (Pixels 0) (Pixels 0) 0 0,
+ margin = Border (Pixels 5) (Pixels 10) 0 0
+ }
+ b :: PaddedBox Length Double
+ b = PaddedBox {
+ B.min = Size 0 Auto,
+ size = Size 0 Auto,
+ B.max = Size 0 Auto,
+ padding = Border (Pixels 0) (Pixels 0) 0 0,
+ border = Border (Pixels 0) (Pixels 0) 0 0,
+ margin = Border (Pixels 10) (Pixels 5) 0 0
+ }
+ height (fst $ layoutFlow zeroBox {
+ size = Size 100 100
+ } lengthBox [a, a] False) `shouldBe` 25
+ height (fst $ layoutFlow zeroBox {
+ size = Size 100 100
+ } lengthBox [b, b] False) `shouldBe` 25
+ height (fst $ layoutFlow zeroBox {
+ size = Size 100 100
+ } lengthBox [a, b] False) `shouldBe` 20
+ height (fst $ layoutFlow zeroBox {
+ size = Size 100 100
+ } lengthBox [b, a] False) `shouldBe` 25
runMath = flip evalCalc [] . mapCalc fst . flip parseCalc [] . filter (/= Whitespace) . tokenize