{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

-- |
-- Module      : FULE.Container.Layered
-- Description : The @Layered@ Container.
-- Copyright   : (c) Paul Schnapp, 2023
-- License     : BSD3
-- Maintainer  : Paul Schnapp <paul.schnapp@gmail.com>
--
-- A 'FULE.Container.Container' to layer multiple items within the same
-- 'FULE.Component.Bounds'.
module FULE.Container.Layered
 ( LayeredM
 , Layered
 , layered
 ) where

import Data.Functor.Identity
import Data.Maybe

import FULE.Container
import FULE.Container.Item
import FULE.Internal.Util
import FULE.LayoutOp


-- | This container layers multiple visual 'FULE.Container.Item.ItemM's within
--   the same bounding rectangle, one on top of the other. Z-ordering is not
--   really taken into account since that depends on how you are using the
--   layout output, but the @ItemM@s will appear in the output of
--   'FULE.Container.runLayoutOp' in the same order in which they're passed to
--   the 'layered' function.
newtype LayeredM m k = Layered [ItemM m k]

-- | Like 'LayeredM' but run in the 'Data.Functor.Identity.Identity' monad.
type Layered = LayeredM Identity

instance (Monad m) => Container (LayeredM m k) k m where
  minWidth :: LayeredM m k -> Proxy k -> m (Maybe Int)
minWidth (Layered [ItemM m k]
is) Proxy k
p = [Maybe Int] -> Maybe Int
getMaxSize ([Maybe Int] -> Maybe Int) -> m [Maybe Int] -> m (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ItemM m k -> m (Maybe Int)) -> [ItemM m k] -> m [Maybe Int]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (ItemM m k -> Proxy k -> m (Maybe Int)
forall c k (m :: * -> *).
Container c k m =>
c -> Proxy k -> m (Maybe Int)
`minWidth` Proxy k
p) [ItemM m k]
is
  minHeight :: LayeredM m k -> Proxy k -> m (Maybe Int)
minHeight (Layered [ItemM m k]
is) Proxy k
p = [Maybe Int] -> Maybe Int
getMaxSize ([Maybe Int] -> Maybe Int) -> m [Maybe Int] -> m (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ItemM m k -> m (Maybe Int)) -> [ItemM m k] -> m [Maybe Int]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (ItemM m k -> Proxy k -> m (Maybe Int)
forall c k (m :: * -> *).
Container c k m =>
c -> Proxy k -> m (Maybe Int)
`minHeight` Proxy k
p) [ItemM m k]
is
  addToLayout :: LayeredM m k -> Proxy k -> Bounds -> Maybe Int -> LayoutOp k m ()
addToLayout (Layered [ItemM m k]
is) Proxy k
proxy Bounds
bounds Maybe Int
renderGroup = do
    Maybe Int
renderGroup' <- Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int)
-> StateT LayoutOpState (WriterT [ComponentInfo k] m) Int
-> StateT LayoutOpState (WriterT [ComponentInfo k] m) (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT LayoutOpState (WriterT [ComponentInfo k] m) Int
-> (Int -> StateT LayoutOpState (WriterT [ComponentInfo k] m) Int)
-> Maybe Int
-> StateT LayoutOpState (WriterT [ComponentInfo k] m) Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe StateT LayoutOpState (WriterT [ComponentInfo k] m) Int
forall (m :: * -> *) k. Monad m => LayoutOp k m Int
nextRenderGroup Int -> StateT LayoutOpState (WriterT [ComponentInfo k] m) Int
forall a. a -> StateT LayoutOpState (WriterT [ComponentInfo k] m) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Int
renderGroup
    (ItemM m k -> LayoutOp k m ()) -> [ItemM m k] -> LayoutOp k m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\ItemM m k
i -> ItemM m k -> Proxy k -> Bounds -> Maybe Int -> LayoutOp k m ()
forall c k (m :: * -> *).
Container c k m =>
c -> Proxy k -> Bounds -> Maybe Int -> LayoutOp k m ()
addToLayout ItemM m k
i Proxy k
proxy Bounds
bounds Maybe Int
renderGroup') [ItemM m k]
is

-- | Layer 'FULE.Container.Item.ItemM's within the same bounding rectangle.
layered :: [ItemM m k] -> LayeredM m k
layered :: forall (m :: * -> *) k. [ItemM m k] -> LayeredM m k
layered = [ItemM m k] -> LayeredM m k
forall (m :: * -> *) k. [ItemM m k] -> LayeredM m k
Layered