    {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}

    -- |
    -- Module      :  XMonad.Layout.Cross
    -- Copyright   :  (c) Luis Cabellos <zhen.sydow@gmail.com>
    -- License     :  BSD3-style (see LICENSE)
    --
    -- Maintainer  :  Luis Cabellos <zhen.sydow@gmail.com>
    -- Stability   :  stable
    -- Portability :  portable
    --
    -- A Cross Layout with the main window in the center.
    --
    module XMonad.Layout.Cross(
                              -- * Usage
                              -- $usage
                              simpleCross
                              , Cross(..) ) where

    import XMonad( Dimension, Rectangle(..), LayoutClass(..), Resize(..), fromMessage )
    import XMonad.StackSet( focus, up, down )
    import Control.Monad( msum )

    -- $usage
    -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
    --
    -- > import XMonad.Layout.Cross
    --
    -- Then edit your @layoutHook@ by adding one of the Cross layouts:
    --
    -- > myLayout =  simpleCross ||| etc..
    -- > main = xmonad defaultConfig { layoutHook = myLayout }
    --

    -- apply a factor to a Rectangle Dimension
    (<%>) :: Dimension -> Rational -> Dimension
    d <%> f = floor $ f * (fromIntegral d)

    -- | The Cross Layout draws the focused window in the center of the screen
    --   and part of the other windows on the sides. The 'Shrink' and 'Expand'
    --   messages increment the size of the main window.
    --
    --   The focus keybindings change the center window, while other windows
    --   cycle through the side positions. With the Cross layout only four
    --   windows are shown around the focused window, two ups and two downs,
    --   no matter how many are in the current stack. I.e. focus down cycles the
    --   window below focused into the center; focus up cycles the window above.
    data Cross a = Cross {
          crossProp :: !Rational, -- ^ Proportion of screen occupied by the main window.
          crossInc  :: !Rational  -- ^ Percent of main window to increment by when resizing.
        }
        deriving( Show, Read )

    -- | A simple Cross Layout. It places the focused window in the center.
    --   The proportion of the screen used by the main window is 4\/5.
    simpleCross :: Cross a
    simpleCross = Cross (4/5) (1/100)

    instance LayoutClass Cross a where
        pureLayout (Cross f _) r s = [(focus s, mainRect r f)] ++
                                     (zip winCycle (upRects r f)) ++
                                     (zip (reverse winCycle) (downRects r f))
            where winCycle = (up s) ++ (reverse (down s))

        pureMessage (Cross f d) m = msum [fmap resize (fromMessage m)]
            where resize Shrink = Cross (max (1/100) $ f - d) d
                  resize Expand = Cross (min 1 $ f + d) d

        description _ = "Cross"

    -- get the Rectangle for the focused window
    mainRect :: Rectangle -> Rational -> Rectangle
    mainRect (Rectangle rx ry rw rh) f = Rectangle
                                         (rx + (fromIntegral (rw <%> invf)))
                                         (ry + (fromIntegral (rh <%> invf)))
                                         (rw <%> f) (rh <%> f)
        where invf = (1/2) * (1-f)

    -- get the rectangles for the up windows
    upRects :: Rectangle -> Rational -> [Rectangle]
    upRects r f = [topRectangle r nf, rightRectangle r nf]
        where nf = f * (8/10)

    -- get the rectangles for the down windows
    downRects :: Rectangle -> Rational -> [Rectangle]
    downRects r f = [bottomRectangle r nf, leftRectangle r nf]
        where nf = f * (8/10)

    topRectangle :: Rectangle -> Rational -> Rectangle
    topRectangle (Rectangle rx ry rw rh) f = Rectangle
                                             (rx + (fromIntegral (rw <%> ((1-f)*(1/2)))))
                                             ry
                                             (rw <%> f) (rh <%> ((1-f)*(1/2)))

    rightRectangle :: Rectangle -> Rational -> Rectangle
    rightRectangle (Rectangle rx ry rw rh) f = Rectangle
                                               (rx + (fromIntegral (rw - (rw <%> (1/2)))))
                                               (ry + (fromIntegral (rh <%> ((1-f)*(1/2)))))
                                               (rw <%> (1/2)) (rh <%> f)

    bottomRectangle :: Rectangle -> Rational -> Rectangle
    bottomRectangle (Rectangle rx ry rw rh) f = Rectangle
                                                (rx + (fromIntegral (rw <%> ((1-f)*(1/2)))))
                                                (ry + (fromIntegral (rh - (rh <%> ((1-f)*(1/2))))))
                                                (rw <%> f) (rh <%> ((1-f)*(1/2)))

    leftRectangle :: Rectangle -> Rational -> Rectangle
    leftRectangle (Rectangle rx ry rw rh) f = Rectangle
                                              rx
                                               (ry + (fromIntegral (rh <%> ((1-f)*(1/2)))))
                                               (rw <%> (1/2)) (rh <%> f)