    {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, DeriveDataTypeable, TypeSynonymInstances #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  XMonad.Layout.Reflect
    -- Copyright   :  (c) Brent Yorgey
    -- License     :  BSD-style (see LICENSE)
    --
    -- Maintainer  :  <byorgey@gmail.com>
    -- Stability   :  unstable
    -- Portability :  unportable
    --
    -- Reflect a layout horizontally or vertically.
    -----------------------------------------------------------------------------

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

                                   reflectHoriz, reflectVert,
                                   REFLECTX(..), REFLECTY(..),
                                   Reflect

                                 ) where

    import XMonad.Core
    import Graphics.X11 (Rectangle(..), Window)
    import Control.Arrow (second)

    import XMonad.Layout.LayoutModifier
    import XMonad.Layout.MultiToggle
    import XMonad.Util.XUtils (fi)

    -- $usage
    -- You can use this module by importing it into your @~\/.xmonad\/xmonad.hs@ file:
    --
    -- > import XMonad.Layout.Reflect
    --
    -- and modifying your layoutHook as follows (for example):
    --
    -- > layoutHook = reflectHoriz $ Tall 1 (3/100) (1/2)  -- put master pane on the right
    --
    -- 'reflectHoriz' and 'reflectVert' can be applied to any sort of
    -- layout (including Mirrored layouts) and will simply flip the
    -- physical layout of the windows vertically or horizontally.
    --
    -- "XMonad.Layout.MultiToggle" transformers are also provided for
    -- toggling layouts between reflected\/non-reflected with a keybinding.
    -- To use this feature, you will also need to import the MultiToggle
    -- module:
    --
    -- > import XMonad.Layout.MultiToggle
    --
    -- Next, add one or more toggles to your layout.  For example, to allow
    -- separate toggling of both vertical and horizontal reflection:
    --
    -- > layoutHook = mkToggle (single REFLECTX) $
    -- >              mkToggle (single REFLECTY) $
    -- >                (tiled ||| Mirror tiled ||| ...) -- whatever layouts you use
    --
    -- Finally, add some keybindings to do the toggling, for example:
    --
    -- > , ((modm .|. controlMask, xK_x), sendMessage $ Toggle REFLECTX)
    -- > , ((modm .|. controlMask, xK_y), sendMessage $ Toggle REFLECTY)
    --

    -- | Apply a horizontal reflection (left \<--\> right) to a
    --   layout.
    reflectHoriz :: l a -> ModifiedLayout Reflect l a
    reflectHoriz = ModifiedLayout (Reflect Horiz)

    -- | Apply a vertical reflection (top \<--\> bottom) to a
    --   layout.
    reflectVert :: l a -> ModifiedLayout Reflect l a
    reflectVert = ModifiedLayout (Reflect Vert)

    data ReflectDir = Horiz | Vert
      deriving (Read, Show)

    -- | Given an axis of reflection and the enclosing rectangle which
    --   contains all the laid out windows, transform a rectangle
    --   representing a window into its flipped counterpart.
    reflectRect :: ReflectDir -> Rectangle -> Rectangle -> Rectangle
    reflectRect Horiz (Rectangle sx _ sw _) (Rectangle rx ry rw rh) =
      Rectangle (2*sx + fi sw - rx - fi rw) ry rw rh
    reflectRect Vert (Rectangle _ sy _ sh) (Rectangle rx ry rw rh) =
      Rectangle rx (2*sy + fi sh - ry - fi rh) rw rh

    data Reflect a = Reflect ReflectDir deriving (Show, Read)

    instance LayoutModifier Reflect a where

        -- reflect all the generated Rectangles.
        pureModifier (Reflect d) r _ wrs = (map (second $ reflectRect d r) wrs, Just $ Reflect d)

        modifierDescription (Reflect d) = "Reflect" ++ xy
          where xy = case d of { Horiz -> "X" ; Vert -> "Y" }

    -------- instances for MultiToggle ------------------

    data REFLECTX = REFLECTX deriving (Read, Show, Eq, Typeable)
    data REFLECTY = REFLECTY deriving (Read, Show, Eq, Typeable)

    instance Transformer REFLECTX Window where
        transform REFLECTX x k = k (reflectHoriz x) (\(ModifiedLayout _ x') -> x')

    instance Transformer REFLECTY Window where
        transform REFLECTY x k = k (reflectVert x) (\(ModifiedLayout _ x') -> x')