content: {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances #-}
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  XMonad.Layout.Column
  -- Copyright   :  (c) 2009 Ilya Portnov
  -- License     :  BSD3-style (see LICENSE)
  --
  -- Maintainer  :  Ilya Portnov <portnov84@rambler.ru>
  -- Stability   :  unstable
  -- Portability :  unportable
  --
  -- Provides Column layout that places all windows in one column. Windows
  -- heights are calculated from equation: H1/H2 = H2/H3 = ... = q, where q is
  -- given. With Shrink/Expand messages you can change the q value.
  --
  -----------------------------------------------------------------------------
  
  module XMonad.Layout.Column (
                               -- * Usage
                               -- $usage
                               Column (..)
                              ) where
  import XMonad
  import qualified XMonad.StackSet as W
  
  -- $usage
  -- This module defines layot named Column. It places all windows in one
  -- column. Windows heights are calculated from equation: H1/H2 = H2/H3 = ... =
  -- q, where `q' is given (thus, windows heights are members of geometric
  -- progression). With Shrink/Expand messages one can change the `q' value.
  --
  -- You can use this module by adding folowing in your @xmonad.hs@:
  --
  -- > import XMonad.Layout.Column
  --
  -- Then add layouts to your layoutHook:
  --
  -- > myLayoutHook = Column 1.6 ||| ...
  --
  -- In this example, each next window will have height 1.6 times less then
  -- previous window.
  
  data Column a = Column Float deriving (Read,Show)
  
  instance LayoutClass Column a where
      pureLayout = columnLayout
      pureMessage = columnMessage
  
  columnMessage :: Column a -> SomeMessage -> Maybe (Column a)
  columnMessage (Column q) m = fmap resize (fromMessage m)
      where resize Shrink = Column (q-0.1)
            resize Expand = Column (q+0.1)
  
  columnLayout :: Column a -> Rectangle -> W.Stack a -> [(a,Rectangle)]
  columnLayout (Column q) rect stack = zip ws rects
      where ws = W.integrate stack
            n = length ws
            heights = map (xn n rect q) [1..n]
            ys = [fromIntegral $ sum $ take k heights | k <- [0..n-1]]
            rects = map (mkRect rect) $ zip heights ys
  
  mkRect :: Rectangle -> (Dimension,Position) -> Rectangle
  mkRect (Rectangle xs ys ws _) (h,y) = Rectangle xs (ys+fromIntegral y) ws h
  
  xn :: Int -> Rectangle -> Float -> Int -> Dimension
  xn n (Rectangle _ _ _ h) q k = if q==1 then
                                    h `div` (fromIntegral n)
                                 else
                                    round ((fromIntegral h)*q^(n-k)*(1-q)/(1-q^n))
  
  
  