aboutsummaryrefslogtreecommitdiffstats
path: root/XMonad/Layout/Mosaic.hs
diff options
context:
space:
mode:
Diffstat (limited to 'XMonad/Layout/Mosaic.hs')
-rw-r--r--XMonad/Layout/Mosaic.hs141
1 files changed, 141 insertions, 0 deletions
diff --git a/XMonad/Layout/Mosaic.hs b/XMonad/Layout/Mosaic.hs
new file mode 100644
index 0000000..46b8fed
--- /dev/null
+++ b/XMonad/Layout/Mosaic.hs
@@ -0,0 +1,141 @@
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, DeriveDataTypeable #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module : XMonad.Layout.Mosaic
+-- Copyright : (c) 2009 Adam Vogt, 2007 James Webb
+-- License : BSD-style (see xmonad/LICENSE)
+--
+-- Maintainer : vogt.adam<at>gmail.com
+-- Stability : unstable
+-- Portability : unportable
+--
+-- Based on MosaicAlt, but aspect ratio messages allways change the aspect
+-- ratios, and rearranging the window stack changes the window sizes.
+--
+-----------------------------------------------------------------------------
+
+module XMonad.Layout.Mosaic (
+ Mosaic(..)
+ ,Aspect(..)
+ )
+ where
+
+import Prelude hiding (sum)
+
+import XMonad(Typeable,
+ LayoutClass(pureLayout, pureMessage, description), Message,
+ fromMessage, splitHorizontallyBy, splitVerticallyBy, Rectangle)
+import XMonad.StackSet(integrate)
+import Data.Foldable(Foldable(foldMap), sum)
+import Data.Monoid(Monoid(mappend, mempty))
+
+-- $usage
+-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
+--
+-- > import XMonad.Layout.Mosaic
+--
+-- Then edit your @layoutHook@ by adding the Mosaic layout:
+--
+-- > myLayouts = Mosaic 0 [1..10] ||| Full ||| etc..
+-- > main = xmonad defaultConfig { layoutHook = myLayouts }
+--
+-- The numbers are directly proportional to the area given, with the
+-- master window getting the most if you have an ascending list.
+--
+-- Unfortunately, infinite lists break serialization, so
+-- don't use them
+--
+-- The position of a window in the stack determines its size.
+--
+-- To change the choice in aspect ratio, add to your keybindings:
+--
+-- , ((modMask, xK_a), sendMessage Taller)
+-- , ((modMask, xK_z), sendMessage Wider)
+-- , ((modMask, xK_s), sendMessage (SlopeMod (zipWith (*) [1..])))
+-- , ((modMask, xK_d), sendMessage (SlopeMod (zipWith (flip (/)) [1..])))
+--
+-- For more detailed instructions on editing the layoutHook see:
+--
+-- "XMonad.Doc.Extending#Editing_the_layout_hook"
+
+data Aspect
+ = Taller
+ | Wider
+ | Reset
+ | SlopeMod ([Rational] -> [Rational])
+ deriving (Typeable)
+
+instance Message Aspect
+
+data Mosaic a
+ = Mosaic Int [Rational]
+ deriving (Read, Show)
+
+instance LayoutClass Mosaic a where
+ description = const "Mosaic"
+
+ pureMessage (Mosaic i ss) msg = ixMod $ fromMessage msg
+ where ixMod (Just Wider) = Just $ Mosaic (succ i) ss
+ ixMod (Just Taller) = if i <= 1 then Nothing else Just $ Mosaic (pred i) ss
+ ixMod (Just Reset) = Just $ Mosaic 0 ss
+ ixMod (Just (SlopeMod f)) = Just $ Mosaic i (f ss)
+ ixMod _ = Nothing
+
+ pureLayout (Mosaic i ss) r st = zip (integrate st) (rect i)
+ where rects = splits (length $ integrate st) r ss
+ rect 0 = rects !! (length rects `div` 2)
+ rect n = if length rects < n then last rects else rects !! pred n
+
+splits :: Int -> Rectangle -> [Rational] -> [[Rectangle]]
+splits num rect sz = splitsL rect $ makeTree $ normalize $ take num sz
+-- where --fas = normalize $ map (fromIntegral (sum fas')/) $ map fromIntegral fas'
+
+normalize :: Fractional a => [a] -> [a]
+normalize x = let s = sum x
+ in map (/s) x
+
+-- recursively enumerate splits
+splitsL :: Rectangle -> Tree Rational -> [[Rectangle]]
+splitsL _rect Empty = []
+splitsL rect (Leaf _) = [[rect]]
+splitsL rect (Branch l r) = do
+ let mkSplit f = f (sum l / (sum l + sum r)) rect
+ (rl,rr) <- map mkSplit [splitHorizontallyBy,splitVerticallyBy]
+ splitsL rl l `interleave` splitsL rr r
+
+interleave :: [[a]] -> [[a]] -> [[a]]
+interleave xs ys | lx > ly = zc xs (extend lx ys)
+ | otherwise = zc (extend ly xs) ys
+ where lx = length xs
+ ly = length ys
+ zc = zipWith (++)
+
+extend :: Int -> [a] -> [a]
+extend n pat = do
+ (p,e') <- zip pat $ take m (repeat True) ++ repeat False
+ let e = if e' then [p] else []
+ (e++) $ take d $ repeat p
+ where (d,m) = n `divMod` length pat
+
+data Tree a = Branch (Tree a) (Tree a) | Leaf a | Empty
+ deriving (Show)
+
+instance Foldable Tree where
+ foldMap _f Empty = mempty
+ foldMap f (Leaf x) = f x
+ foldMap f (Branch l r) = foldMap f l `mappend` foldMap f r
+
+instance Monoid (Tree a) where
+ mempty = Empty
+ mappend Empty x = x
+ mappend x Empty = x
+ mappend x y = Branch x y
+
+makeTree :: [Rational] -> Tree Rational
+makeTree [] = Empty
+makeTree [x] = Leaf x
+makeTree xs = Branch (makeTree a) (makeTree b)
+ where ((a,b),_) = foldr w (([],[]),(0,0)) xs
+ w n ((ls,rs),(l,r)) = if l > r then ((ls,n:rs),(l,n+r))
+ else ((n:ls,rs),(n+l,r))
+