    {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  XMonad.Layout.MultiDishes
    -- Description :  A layout stacking groups of extra windows underneath the master windows.
    -- Copyright   :  (c) Jeremy Apthorp, Nathan Fairhurst
    -- License     :  BSD-style (see LICENSE)
    --
    -- Maintainer  :  Nathan Fairhurst <nathan.p3pictures@gmail.com>
    -- Stability   :  unstable
    -- Portability :  portable
    --
    -- MultiDishes is a layout that stacks groups of extra windows underneath
    -- the master windows.
    --
    -----------------------------------------------------------------------------

    module XMonad.Layout.MultiDishes (
                                  -- * Usage
                                  -- $usage
                                  MultiDishes (..)
                                ) where

    import XMonad
    import XMonad.StackSet (integrate)
    import XMonad.Prelude (ap)

    -- $usage
    -- You can use this module with the following in your @xmonad.hs@:
    --
    -- > import XMonad.Layout.MultiDishes
    --
    -- Then edit your @layoutHook@ by adding the MultiDishes layout:
    --
    -- > myLayout = MultiDishes 2 3 (1/6) ||| Full ||| etc..
    -- > main = xmonad def { layoutHook = myLayout }
    --
    -- This is based on the Layout Dishes, but accepts another parameter for
    -- the maximum number of dishes allowed within a stack.
    --
    -- > MultiDishes x 1 y
    -- is equivalent to
    -- > Dishes x y
    --
    -- The stack with the fewest dishes is always on top, so 4 windows
    -- with the layout `MultiDishes 1 2 (1/5)` would look like this:
    --
    -- > _________
    -- > |       |
    -- > |   M   |
    -- > |_______|
    -- > |_______|
    -- > |___|___|
    --
    -- For more detailed instructions on editing the layoutHook see
    -- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and
    -- "XMonad.Doc.Extending#Editing_the_layout_hook".

    data MultiDishes a = MultiDishes Int Int Rational deriving (Int -> MultiDishes a -> ShowS
    [MultiDishes a] -> ShowS
    MultiDishes a -> String
    (Int -> MultiDishes a -> ShowS)
    -> (MultiDishes a -> String)
    -> ([MultiDishes a] -> ShowS)
    -> Show (MultiDishes a)
    forall a. Int -> MultiDishes a -> ShowS
    forall a. [MultiDishes a] -> ShowS
    forall a. MultiDishes a -> String
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: forall a. Int -> MultiDishes a -> ShowS
    showsPrec :: Int -> MultiDishes a -> ShowS
    $cshow :: forall a. MultiDishes a -> String
    show :: MultiDishes a -> String
    $cshowList :: forall a. [MultiDishes a] -> ShowS
    showList :: [MultiDishes a] -> ShowS
    Show, ReadPrec [MultiDishes a]
    ReadPrec (MultiDishes a)
    Int -> ReadS (MultiDishes a)
    ReadS [MultiDishes a]
    (Int -> ReadS (MultiDishes a))
    -> ReadS [MultiDishes a]
    -> ReadPrec (MultiDishes a)
    -> ReadPrec [MultiDishes a]
    -> Read (MultiDishes a)
    forall a. ReadPrec [MultiDishes a]
    forall a. ReadPrec (MultiDishes a)
    forall a. Int -> ReadS (MultiDishes a)
    forall a. ReadS [MultiDishes a]
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: forall a. Int -> ReadS (MultiDishes a)
    readsPrec :: Int -> ReadS (MultiDishes a)
    $creadList :: forall a. ReadS [MultiDishes a]
    readList :: ReadS [MultiDishes a]
    $creadPrec :: forall a. ReadPrec (MultiDishes a)
    readPrec :: ReadPrec (MultiDishes a)
    $creadListPrec :: forall a. ReadPrec [MultiDishes a]
    readListPrec :: ReadPrec [MultiDishes a]
    Read)
    instance LayoutClass MultiDishes a where
        pureLayout :: MultiDishes a -> Rectangle -> Stack a -> [(a, Rectangle)]
    pureLayout (MultiDishes Int
    nmaster Int
    dishesPerStack Rational
    h) Rectangle
    r =
            ([a] -> [Rectangle] -> [(a, Rectangle)])
    -> ([a] -> [Rectangle]) -> [a] -> [(a, Rectangle)]
    forall (m :: * -> *) a b. Monad m => m (a -> b) -> m a -> m b
    ap [a] -> [Rectangle] -> [(a, Rectangle)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip (Rational -> Rectangle -> Int -> Int -> Int -> [Rectangle]
    multiDishes Rational
    h Rectangle
    r Int
    nmaster Int
    dishesPerStack (Int -> [Rectangle]) -> ([a] -> Int) -> [a] -> [Rectangle]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [a] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length) ([a] -> [(a, Rectangle)])
    -> (Stack a -> [a]) -> Stack a -> [(a, Rectangle)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Stack a -> [a]
    forall a. Stack a -> [a]
    integrate
        pureMessage :: MultiDishes a -> SomeMessage -> Maybe (MultiDishes a)
    pureMessage (MultiDishes Int
    nmaster Int
    dishesPerStack Rational
    h) SomeMessage
    m = (IncMasterN -> MultiDishes a)
    -> Maybe IncMasterN -> Maybe (MultiDishes a)
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap IncMasterN -> MultiDishes a
    forall {a}. IncMasterN -> MultiDishes a
    incmastern (SomeMessage -> Maybe IncMasterN
    forall m. Message m => SomeMessage -> Maybe m
    fromMessage SomeMessage
    m)
            where incmastern :: IncMasterN -> MultiDishes a
    incmastern (IncMasterN Int
    d) = Int -> Int -> Rational -> MultiDishes a
    forall a. Int -> Int -> Rational -> MultiDishes a
    MultiDishes (Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    max Int
    0 (Int
    nmasterInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    d)) Int
    dishesPerStack Rational
    h

    multiDishes :: Rational -> Rectangle -> Int -> Int -> Int -> [Rectangle]
    multiDishes :: Rational -> Rectangle -> Int -> Int -> Int -> [Rectangle]
    multiDishes Rational
    h Rectangle
    s Int
    nmaster Int
    dishesPerStack Int
    n = if Int
    n Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    nmaster
                            then Int -> Rectangle -> [Rectangle]
    splitHorizontally Int
    n Rectangle
    s
                            else [Rectangle]
    ws
     where
        (Int
    filledDishStackCount, Int
    remainder) =
          (Int
    n Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    nmaster) Int -> Int -> (Int, Int)
    forall a. Integral a => a -> a -> (a, a)
    `quotRem` Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    max Int
    1 Int
    dishesPerStack

        (Int
    firstDepth, Int
    dishStackCount) =
          if Int
    remainder Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    0 then
            (Int
    dishesPerStack, Int
    filledDishStackCount)
          else
            (Int
    remainder, Int
    filledDishStackCount Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1)

        (Rectangle
    masterRect, Rectangle
    dishesRect) =
          Rational -> Rectangle -> (Rectangle, Rectangle)
    forall r. RealFrac r => r -> Rectangle -> (Rectangle, Rectangle)
    splitVerticallyBy (Rational
    1 Rational -> Rational -> Rational
    forall a. Num a => a -> a -> a
    - Int -> Rational
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dishStackCount Rational -> Rational -> Rational
    forall a. Num a => a -> a -> a
    * Rational
    h) Rectangle
    s

        dishStackRects :: [Rectangle]
    dishStackRects =
          Int -> Rectangle -> [Rectangle]
    splitVertically Int
    dishStackCount Rectangle
    dishesRect

        allDishRects :: [Rectangle]
    allDishRects = case [Rectangle]
    dishStackRects of
          (Rectangle
    firstStack:[Rectangle]
    bottomDishStacks) ->
            Int -> Rectangle -> [Rectangle]
    splitHorizontally Int
    firstDepth Rectangle
    firstStack [Rectangle] -> [Rectangle] -> [Rectangle]
    forall a. [a] -> [a] -> [a]
    ++ ([Rectangle]
    bottomDishStacks [Rectangle] -> (Rectangle -> [Rectangle]) -> [Rectangle]
    forall a b. [a] -> (a -> [b]) -> [b]
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Int -> Rectangle -> [Rectangle]
    splitHorizontally Int
    dishesPerStack)
          [] -> []

        ws :: [Rectangle]
    ws =
          Int -> Rectangle -> [Rectangle]
    splitHorizontally Int
    nmaster Rectangle
    masterRect [Rectangle] -> [Rectangle] -> [Rectangle]
    forall a. [a] -> [a] -> [a]
    ++ [Rectangle]
    allDishRects