    {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  XMonad.Layout.MultiColumns
    -- Description :  A layout that tiles windows in a growing number of columns.
    -- Copyright   :  (c) Anders Engstrom <ankaan@gmail.com>
    -- License     :  BSD3-style (see LICENSE)
    --
    -- Maintainer  :  Anders Engstrom <ankaan@gmail.com>
    -- Stability   :  unstable
    -- Portability :  unportable
    --
    -- This layout tiles windows in a growing number of columns. The number of
    -- windows in each column can be controlled by messages.
    -----------------------------------------------------------------------------

    module XMonad.Layout.MultiColumns (
                                  -- * Usage
                                  -- $usage

                                  multiCol,
                                  MultiCol,
                                 ) where

    import XMonad
    import qualified XMonad.StackSet as W

    import XMonad.Prelude

    -- $usage
    -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
    --
    -- > import XMonad.Layout.MultiColumns
    --
    -- Then edit your @layoutHook@ by adding the multiCol layout:
    --
    -- > myLayouts = multiCol [1] 4 0.01 0.5 ||| etc..
    -- > main = xmonad def { layoutHook = myLayouts }
    --
    -- Or alternatively:
    --
    -- > myLayouts = Mirror (multiCol [1] 2 0.01 (-0.25)) ||| etc..
    -- > main = xmonad def { layoutHook = myLayouts }
    --
    -- The maximum number of windows in a column can be controlled using the
    -- IncMasterN messages and the column containing the focused window will be
    -- modified. If the value is 0, all remaining windows will be placed in that
    -- column when all columns before that has been filled.
    --
    -- The size can be set to between 1 and -0.5. If the value is positive, the
    -- master column will be of that size. The rest of the screen is split among
    -- the other columns. But if the size is negative, it instead indicates the
    -- size of all non-master columns and the master column will cover the rest of
    -- the screen. If the master column would become smaller than the other
    -- columns, the screen is instead split equally among all columns. Therefore,
    -- if equal size among all columns are desired, set the size to -0.5.
    --
    -- For more detailed instructions on editing the layoutHook see:
    --
    -- "XMonad.Doc.Extending#Editing_the_layout_hook"

    -- | Layout constructor.
    multiCol
      :: [Int]    -- ^ Windows in each column, starting with master. Set to 0 to catch the rest.
      -> Int      -- ^ Default value for all following columns.
      -> Rational -- ^ How much to change size each time.
      -> Rational -- ^ Initial size of master area, or column area if the size is negative.
      -> MultiCol a
    multiCol :: forall a. [Int] -> Int -> Rational -> Rational -> MultiCol a
    multiCol [Int]
    n Int
    defn Rational
    ds Rational
    s = [Int] -> Int -> Rational -> Rational -> Int -> MultiCol a
    forall a. [Int] -> Int -> Rational -> Rational -> Int -> MultiCol a
    MultiCol ((Int -> Int) -> [Int] -> [Int]
    forall a b. (a -> b) -> [a] -> [b]
    map (Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    max Int
    0) [Int]
    n) (Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    max Int
    0 Int
    defn) Rational
    ds Rational
    s Int
    0

    data MultiCol a = MultiCol
      { forall a. MultiCol a -> [Int]
    multiColNWin      :: ![Int]
      , forall a. MultiCol a -> Int
    multiColDefWin    :: !Int
      , forall a. MultiCol a -> Rational
    multiColDeltaSize :: !Rational
      , forall a. MultiCol a -> Rational
    multiColSize      :: !Rational
      , forall a. MultiCol a -> Int
    multiColActive    :: !Int
      } deriving (Int -> MultiCol a -> ShowS
    [MultiCol a] -> ShowS
    MultiCol a -> String
    (Int -> MultiCol a -> ShowS)
    -> (MultiCol a -> String)
    -> ([MultiCol a] -> ShowS)
    -> Show (MultiCol a)
    forall a. Int -> MultiCol a -> ShowS
    forall a. [MultiCol a] -> ShowS
    forall a. MultiCol a -> String
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: forall a. Int -> MultiCol a -> ShowS
    showsPrec :: Int -> MultiCol a -> ShowS
    $cshow :: forall a. MultiCol a -> String
    show :: MultiCol a -> String
    $cshowList :: forall a. [MultiCol a] -> ShowS
    showList :: [MultiCol a] -> ShowS
    Show,ReadPrec [MultiCol a]
    ReadPrec (MultiCol a)
    Int -> ReadS (MultiCol a)
    ReadS [MultiCol a]
    (Int -> ReadS (MultiCol a))
    -> ReadS [MultiCol a]
    -> ReadPrec (MultiCol a)
    -> ReadPrec [MultiCol a]
    -> Read (MultiCol a)
    forall a. ReadPrec [MultiCol a]
    forall a. ReadPrec (MultiCol a)
    forall a. Int -> ReadS (MultiCol a)
    forall a. ReadS [MultiCol a]
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: forall a. Int -> ReadS (MultiCol a)
    readsPrec :: Int -> ReadS (MultiCol a)
    $creadList :: forall a. ReadS [MultiCol a]
    readList :: ReadS [MultiCol a]
    $creadPrec :: forall a. ReadPrec (MultiCol a)
    readPrec :: ReadPrec (MultiCol a)
    $creadListPrec :: forall a. ReadPrec [MultiCol a]
    readListPrec :: ReadPrec [MultiCol a]
    Read,MultiCol a -> MultiCol a -> Bool
    (MultiCol a -> MultiCol a -> Bool)
    -> (MultiCol a -> MultiCol a -> Bool) -> Eq (MultiCol a)
    forall a. MultiCol a -> MultiCol a -> Bool
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: forall a. MultiCol a -> MultiCol a -> Bool
    == :: MultiCol a -> MultiCol a -> Bool
    $c/= :: forall a. MultiCol a -> MultiCol a -> Bool
    /= :: MultiCol a -> MultiCol a -> Bool
    Eq)

    instance LayoutClass MultiCol a where
        doLayout :: MultiCol a
    -> Rectangle -> Stack a -> X ([(a, Rectangle)], Maybe (MultiCol a))
    doLayout MultiCol a
    l Rectangle
    r Stack a
    s = ([(a, Rectangle)], Maybe (MultiCol a))
    -> X ([(a, Rectangle)], Maybe (MultiCol a))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Stack a -> [Rectangle] -> [(a, Rectangle)]
    forall {a} {b}. Stack a -> [b] -> [(a, b)]
    combine Stack a
    s [Rectangle]
    rlist, Maybe (MultiCol a)
    forall {a}. Maybe (MultiCol a)
    resl)
            where rlist :: [Rectangle]
    rlist = [Int] -> Rational -> Rectangle -> Int -> [Rectangle]
    doL (MultiCol Any -> [Int]
    forall a. MultiCol a -> [Int]
    multiColNWin MultiCol Any
    forall {a}. MultiCol a
    l') (MultiCol Any -> Rational
    forall a. MultiCol a -> Rational
    multiColSize MultiCol Any
    forall {a}. MultiCol a
    l') Rectangle
    r Int
    wlen
                  wlen :: Int
    wlen = [a] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length ([a] -> Int) -> [a] -> Int
    forall a b. (a -> b) -> a -> b
    $ Stack a -> [a]
    forall a. Stack a -> [a]
    W.integrate Stack a
    s
                  -- Make sure the list of columns is big enough and update active column
                  nw :: [Int]
    nw = MultiCol a -> [Int]
    forall a. MultiCol a -> [Int]
    multiColNWin MultiCol a
    l [Int] -> [Int] -> [Int]
    forall a. [a] -> [a] -> [a]
    ++ Int -> [Int]
    forall a. a -> [a]
    repeat (MultiCol a -> Int
    forall a. MultiCol a -> Int
    multiColDefWin MultiCol a
    l)
                  l' :: MultiCol a
    l' = MultiCol a
    l { multiColNWin :: [Int]
    multiColNWin = Int -> [Int] -> [Int]
    forall a. Int -> [a] -> [a]
    take (Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    max ([Int] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length ([Int] -> Int) -> [Int] -> Int
    forall a b. (a -> b) -> a -> b
    $ MultiCol a -> [Int]
    forall a. MultiCol a -> [Int]
    multiColNWin MultiCol a
    l) (Int -> Int) -> Int -> Int
    forall a b. (a -> b) -> a -> b
    $ Int -> [Int] -> Int
    getCol (Int
    wlenInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    1) [Int]
    nw Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) [Int]
    nw
                         , multiColActive :: Int
    multiColActive = Int -> [Int] -> Int
    getCol ([a] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length ([a] -> Int) -> [a] -> Int
    forall a b. (a -> b) -> a -> b
    $ Stack a -> [a]
    forall a. Stack a -> [a]
    W.up Stack a
    s) [Int]
    nw
                         }
                  -- Only return new layout if it has been modified
                  resl :: Maybe (MultiCol a)
    resl = if MultiCol a
    forall {a}. MultiCol a
    l'MultiCol a -> MultiCol a -> Bool
    forall a. Eq a => a -> a -> Bool
    ==MultiCol a
    l
                         then Maybe (MultiCol a)
    forall a. Maybe a
    Nothing
                         else MultiCol a -> Maybe (MultiCol a)
    forall a. a -> Maybe a
    Just MultiCol a
    forall {a}. MultiCol a
    l'
                  combine :: Stack a -> [b] -> [(a, b)]
    combine (W.Stack a
    foc [a]
    left [a]
    right) [b]
    rs = [a] -> [b] -> [(a, b)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip (a
    foc a -> [a] -> [a]
    forall a. a -> [a] -> [a]
    : [a] -> [a]
    forall a. [a] -> [a]
    reverse [a]
    left [a] -> [a] -> [a]
    forall a. [a] -> [a] -> [a]
    ++ [a]
    right) ([b] -> [(a, b)]) -> [b] -> [(a, b)]
    forall a b. (a -> b) -> a -> b
    $ Int -> [b] -> [b]
    forall a. Int -> [a] -> [a]
    raiseFocused ([a] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [a]
    left) [b]
    rs
        handleMessage :: MultiCol a -> SomeMessage -> X (Maybe (MultiCol a))
    handleMessage MultiCol a
    l SomeMessage
    m =
            Maybe (MultiCol a) -> X (Maybe (MultiCol a))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe (MultiCol a) -> X (Maybe (MultiCol a)))
    -> Maybe (MultiCol a) -> X (Maybe (MultiCol a))
    forall a b. (a -> b) -> a -> b
    $ [Maybe (MultiCol a)] -> Maybe (MultiCol a)
    forall (t :: * -> *) (m :: * -> *) a.
    (Foldable t, MonadPlus m) =>
    t (m a) -> m a
    msum [(Resize -> MultiCol a) -> Maybe Resize -> Maybe (MultiCol a)
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Resize -> MultiCol a
    forall {a}. Resize -> MultiCol a
    resize     (SomeMessage -> Maybe Resize
    forall m. Message m => SomeMessage -> Maybe m
    fromMessage SomeMessage
    m)
                          ,(IncMasterN -> MultiCol a)
    -> Maybe IncMasterN -> Maybe (MultiCol a)
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap IncMasterN -> MultiCol a
    forall {a}. IncMasterN -> MultiCol a
    incmastern (SomeMessage -> Maybe IncMasterN
    forall m. Message m => SomeMessage -> Maybe m
    fromMessage SomeMessage
    m)]
                where resize :: Resize -> MultiCol a
    resize Resize
    Shrink = MultiCol a
    l { multiColSize :: Rational
    multiColSize = Rational -> Rational -> Rational
    forall a. Ord a => a -> a -> a
    max (-Rational
    0.5) (Rational -> Rational) -> Rational -> Rational
    forall a b. (a -> b) -> a -> b
    $ Rational
    sRational -> Rational -> Rational
    forall a. Num a => a -> a -> a
    -Rational
    ds }
                      resize Resize
    Expand = MultiCol a
    l { multiColSize :: Rational
    multiColSize = Rational -> Rational -> Rational
    forall a. Ord a => a -> a -> a
    min Rational
    1 (Rational -> Rational) -> Rational -> Rational
    forall a b. (a -> b) -> a -> b
    $ Rational
    sRational -> Rational -> Rational
    forall a. Num a => a -> a -> a
    +Rational
    ds }
                      incmastern :: IncMasterN -> MultiCol a
    incmastern (IncMasterN Int
    x) = MultiCol a
    l { multiColNWin :: [Int]
    multiColNWin = Int -> [Int] -> [Int]
    forall a. Int -> [a] -> [a]
    take Int
    a [Int]
    n [Int] -> [Int] -> [Int]
    forall a. [a] -> [a] -> [a]
    ++ [Int
    newval] [Int] -> [Int] -> [Int]
    forall a. [a] -> [a] -> [a]
    ++ [Int] -> [Int]
    forall a. HasCallStack => [a] -> [a]
    tail [Int]
    r }
                          where newval :: Int
    newval =  Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    max Int
    0 (Int -> Int) -> Int -> Int
    forall a b. (a -> b) -> a -> b
    $ [Int] -> Int
    forall a. HasCallStack => [a] -> a
    head [Int]
    r Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    x
                                r :: [Int]
    r = Int -> [Int] -> [Int]
    forall a. Int -> [a] -> [a]
    drop Int
    a [Int]
    n
                      n :: [Int]
    n = MultiCol a -> [Int]
    forall a. MultiCol a -> [Int]
    multiColNWin MultiCol a
    l
                      ds :: Rational
    ds = MultiCol a -> Rational
    forall a. MultiCol a -> Rational
    multiColDeltaSize MultiCol a
    l
                      s :: Rational
    s = MultiCol a -> Rational
    forall a. MultiCol a -> Rational
    multiColSize MultiCol a
    l
                      a :: Int
    a = MultiCol a -> Int
    forall a. MultiCol a -> Int
    multiColActive MultiCol a
    l
        description :: MultiCol a -> String
    description MultiCol a
    _ = String
    "MultiCol"

    raiseFocused :: Int -> [a] -> [a]
    raiseFocused :: forall a. Int -> [a] -> [a]
    raiseFocused Int
    n [a]
    xs = [a]
    actual [a] -> [a] -> [a]
    forall a. [a] -> [a] -> [a]
    ++ [a]
    before [a] -> [a] -> [a]
    forall a. [a] -> [a] -> [a]
    ++ [a]
    after
        where ([a]
    before,[a]
    rest) = Int -> [a] -> ([a], [a])
    forall a. Int -> [a] -> ([a], [a])
    splitAt Int
    n [a]
    xs
              ([a]
    actual,[a]
    after) = Int -> [a] -> ([a], [a])
    forall a. Int -> [a] -> ([a], [a])
    splitAt Int
    1 [a]
    rest

    -- | Get which column a window is in, starting at 0.
    getCol :: Int -> [Int] -> Int
    getCol :: Int -> [Int] -> Int
    getCol Int
    w (Int
    n:[Int]
    ns) = if Int
    nInt -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <Int
    1 Bool -> Bool -> Bool
    || Int
    w Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    n
                      then Int
    0
                      else Int
    1 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int -> [Int] -> Int
    getCol (Int
    wInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    n) [Int]
    ns
    -- Should never occur...
    getCol Int
    _ [Int]
    _ = -Int
    1

    doL :: [Int] -> Rational -> Rectangle -> Int -> [Rectangle]
    doL :: [Int] -> Rational -> Rectangle -> Int -> [Rectangle]
    doL [Int]
    nwin Rational
    s Rectangle
    r Int
    n = [Rectangle]
    rlist
        where -- Number of columns to tile
              ncol :: Int
    ncol = Int -> [Int] -> Int
    getCol (Int
    nInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    1) [Int]
    nwin Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1
              -- Compute the actual size
              size :: Int
    size = Rational -> Int
    forall b. Integral b => Rational -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    floor (Rational -> Int) -> Rational -> Int
    forall a b. (a -> b) -> a -> b
    $ Rational -> Rational
    forall a. Num a => a -> a
    abs Rational
    s Rational -> Rational -> Rational
    forall a. Num a => a -> a -> a
    * Dimension -> Rational
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Rectangle -> Dimension
    rect_width Rectangle
    r)
              -- Extract all but last column to tile
              c :: [Int]
    c = Int -> [Int] -> [Int]
    forall a. Int -> [a] -> [a]
    take (Int
    ncolInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    1) [Int]
    nwin
              -- Compute number of windows in last column and add it to the others
              col :: [Int]
    col = [Int]
    c [Int] -> [Int] -> [Int]
    forall a. [a] -> [a] -> [a]
    ++ [Int
    nInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -[Int] -> Int
    forall a. Num a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
    sum [Int]
    c]
              -- Compute width of columns
              width :: [Int]
    width
                | Rational
    sRational -> Rational -> Bool
    forall a. Ord a => a -> a -> Bool
    >Rational
    0 = if Int
    ncolInt -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    ==Int
    1
                        -- Only one window
                        then [Dimension -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Dimension -> Int) -> Dimension -> Int
    forall a b. (a -> b) -> a -> b
    $ Rectangle -> Dimension
    rect_width Rectangle
    r]
                        -- Give the master it's space and split the rest equally for the other columns
                        else Int
    sizeInt -> [Int] -> [Int]
    forall a. a -> [a] -> [a]
    :Int -> Int -> [Int]
    forall a. Int -> a -> [a]
    replicate (Int
    ncolInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    1) ((Dimension -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Rectangle -> Dimension
    rect_width Rectangle
    r) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    size) Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` (Int
    ncolInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    1))
                | Int -> Rational
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    ncol Rational -> Rational -> Rational
    forall a. Num a => a -> a -> a
    * Rational -> Rational
    forall a. Num a => a -> a
    abs Rational
    s Rational -> Rational -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Rational
    1 = Int -> Int -> [Int]
    forall a. Int -> a -> [a]
    replicate Int
    ncol (Int -> [Int]) -> Int -> [Int]
    forall a b. (a -> b) -> a -> b
    $ Dimension -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Rectangle -> Dimension
    rect_width Rectangle
    r) Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` Int
    ncol
                | Bool
    otherwise = (Dimension -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Rectangle -> Dimension
    rect_width Rectangle
    r) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - (Int
    ncolInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    1)Int -> Int -> Int
    forall a. Num a => a -> a -> a
    *Int
    size)Int -> [Int] -> [Int]
    forall a. a -> [a] -> [a]
    :Int -> Int -> [Int]
    forall a. Int -> a -> [a]
    replicate (Int
    ncolInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    1) Int
    size
              -- Compute the horizontal position of columns
              xpos :: [Int]
    xpos = Int -> [Int] -> [Int]
    forall {t}. Num t => t -> [t] -> [t]
    accumEx (Position -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Position -> Int) -> Position -> Int
    forall a b. (a -> b) -> a -> b
    $ Rectangle -> Position
    rect_x Rectangle
    r) [Int]
    width
              -- Exclusive accumulation
              accumEx :: t -> [t] -> [t]
    accumEx t
    a (t
    x:[t]
    xs) = t
    at -> [t] -> [t]
    forall a. a -> [a] -> [a]
    :t -> [t] -> [t]
    accumEx (t
    at -> t -> t
    forall a. Num a => a -> a -> a
    +t
    x) [t]
    xs
              accumEx t
    _ [t]
    _ = []
              -- Create a rectangle for each column
              cr :: [Rectangle]
    cr = (Int -> Int -> Rectangle) -> [Int] -> [Int] -> [Rectangle]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith (\Int
    x Int
    w -> Rectangle
    r { rect_x :: Position
    rect_x=Int -> Position
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    x, rect_width :: Dimension
    rect_width=Int -> Dimension
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    w }) [Int]
    xpos [Int]
    width
              -- Split the columns into the windows
              rlist :: [Rectangle]
    rlist = [[Rectangle]] -> [Rectangle]
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat ([[Rectangle]] -> [Rectangle]) -> [[Rectangle]] -> [Rectangle]
    forall a b. (a -> b) -> a -> b
    $ (Int -> Rectangle -> [Rectangle])
    -> [Int] -> [Rectangle] -> [[Rectangle]]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith Int -> Rectangle -> [Rectangle]
    splitVertically [Int]
    col [Rectangle]
    cr