mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-05-19 11:30:22 -07:00
This is a convenience module in order to have less import noise. It re-exports the following: a) Commonly used modules in full (Data.Foldable, Data.Applicative, and so on); though only those that play nicely with each other, so that XMonad.Prelude can be imported unqualified without any problems. This prevents things like `Prelude.(.)` and `Control.Category.(.)` fighting with each other. b) Helper functions that don't necessarily fit in any other module; e.g., the often used abbreviation `fi = fromIntegral`.
162 lines
6.4 KiB
Haskell
162 lines
6.4 KiB
Haskell
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- |
|
|
-- Module : XMonad.Layout.ResizableThreeColumns
|
|
-- Copyright : (c) Sam Tay <sam.chong.tay@gmail.com>
|
|
-- License : BSD3-style (see LICENSE)
|
|
--
|
|
-- Maintainer : ?
|
|
-- Stability : unstable
|
|
-- Portability : unportable
|
|
--
|
|
-- A layout similar to tall but with three columns. With 2560x1600 pixels this
|
|
-- layout can be used for a huge main window and up to six reasonable sized
|
|
-- resizable slave windows.
|
|
-----------------------------------------------------------------------------
|
|
|
|
module XMonad.Layout.ResizableThreeColumns (
|
|
-- * Usage
|
|
-- $usage
|
|
ResizableThreeCol(..), MirrorResize(..)
|
|
) where
|
|
|
|
import XMonad hiding (splitVertically)
|
|
import XMonad.Prelude
|
|
import XMonad.Layout.ResizableTile(MirrorResize(..))
|
|
import qualified XMonad.StackSet as W
|
|
|
|
import qualified Data.Map as M
|
|
import Data.Ratio
|
|
|
|
-- $usage
|
|
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
|
--
|
|
-- > import XMonad.Layout.ResizableThreeColumns
|
|
--
|
|
-- Then edit your @layoutHook@ by adding the ResizableThreeCol layout:
|
|
--
|
|
-- > myLayout = ResizableThreeCol 1 (3/100) (1/2) [] ||| ResizableThreeColMid 1 (3/100) (1/2) [] ||| etc..
|
|
-- > main = xmonad def { layoutHook = myLayout }
|
|
--
|
|
-- The first argument specifies how many windows initially appear in the main
|
|
-- window. The second argument argument specifies the amount to resize while
|
|
-- resizing and the third argument specifies the initial size of the columns.
|
|
-- A positive size designates the fraction of the screen that the main window
|
|
-- should occupy, but if the size is negative the absolute value designates the
|
|
-- fraction a slave column should occupy. If both slave columns are visible,
|
|
-- they always occupy the same amount of space.
|
|
--
|
|
-- You may also want to add the following key bindings:
|
|
--
|
|
-- > , ((modm, xK_a), sendMessage MirrorShrink)
|
|
-- > , ((modm, xK_z), sendMessage MirrorExpand)
|
|
--
|
|
-- The ResizableThreeColMid variant places the main window between the slave columns.
|
|
--
|
|
-- For more detailed instructions on editing the layoutHook see:
|
|
--
|
|
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
|
|
|
|
|
|
-- | Arguments are nmaster, delta, fraction
|
|
data ResizableThreeCol a
|
|
= ResizableThreeColMid
|
|
{ threeColNMaster :: !Int
|
|
, threeColDelta :: !Rational
|
|
, threeColFrac :: !Rational
|
|
, threeColSlaves :: [Rational]
|
|
}
|
|
| ResizableThreeCol
|
|
{ threeColNMaster :: !Int
|
|
, threeColDelta :: !Rational
|
|
, threeColFrac :: !Rational
|
|
, threeColSlaves :: [Rational]
|
|
} deriving (Show,Read)
|
|
|
|
instance LayoutClass ResizableThreeCol a where
|
|
doLayout (ResizableThreeCol n _ f mf) r = doL False n f mf r
|
|
doLayout (ResizableThreeColMid n _ f mf) r = doL True n f mf r
|
|
handleMessage l m = do
|
|
ms <- (W.stack . W.workspace . W.current) <$> gets windowset
|
|
fs <- (M.keys . W.floating) <$> gets windowset
|
|
return $ do
|
|
s <- ms
|
|
-- make sure current stack isn't floating
|
|
guard . not $ W.focus s `elem` fs
|
|
-- remove floating windows from stack
|
|
let s' = s { W.up = (W.up s) \\ fs, W.down = (W.down s) \\ fs }
|
|
-- handle messages
|
|
msum [ fmap resize (fromMessage m)
|
|
, fmap (mresize s') (fromMessage m)
|
|
, fmap incmastern (fromMessage m)
|
|
]
|
|
where
|
|
resize Shrink = l { threeColFrac = max (-0.5) $ frac-delta }
|
|
resize Expand = l { threeColFrac = min 1 $ frac+delta }
|
|
mresize s MirrorShrink = mresize' s delta
|
|
mresize s MirrorExpand = mresize' s (0-delta)
|
|
mresize' s delt =
|
|
let up = length $ W.up s
|
|
total = up + (length $ W.down s) + 1
|
|
pos = if up == (nmaster-1) || up == (total-1) then up-1 else up
|
|
mfrac' = modifymfrac (mfrac ++ repeat 1) delt pos
|
|
in l { threeColSlaves = take total mfrac'}
|
|
modifymfrac [] _ _ = []
|
|
modifymfrac (f:fx) d n
|
|
| n == 0 = f+d : fx
|
|
| otherwise = f : modifymfrac fx d (n-1)
|
|
incmastern (IncMasterN x) = l { threeColNMaster = max 0 (nmaster+x) }
|
|
nmaster = threeColNMaster l
|
|
delta = threeColDelta l
|
|
frac = threeColFrac l
|
|
mfrac = threeColSlaves l
|
|
description _ = "ResizableThreeCol"
|
|
|
|
doL :: Bool -> Int -> Rational -> [Rational] -> Rectangle
|
|
-> W.Stack a -> X ([(a, Rectangle)], Maybe (layout a))
|
|
doL middle nmaster f mf r =
|
|
return
|
|
. (\x -> (x, Nothing))
|
|
. ap zip (tile3 middle f (mf ++ repeat 1) r nmaster . length) . W.integrate
|
|
|
|
-- | tile3. Compute window positions using 3 panes
|
|
tile3 :: Bool -> Rational -> [Rational] -> Rectangle -> Int -> Int -> [Rectangle]
|
|
tile3 middle f mf r nmaster n
|
|
| n <= nmaster || nmaster == 0 = splitVertically mf n r
|
|
| n <= nmaster+1 = concat [ splitVertically mf nmaster s1
|
|
, splitVertically (drop nmaster mf) (n-nmaster) s2
|
|
]
|
|
| otherwise = concat [ splitVertically mf nmaster r1
|
|
, splitVertically (drop nmaster mf) nslave1 r2
|
|
, splitVertically (drop (nmaster + nslave1) mf) nslave2 r3
|
|
]
|
|
where
|
|
(r1, r2, r3) = split3HorizontallyBy middle (if f<0 then 1+2*f else f) r
|
|
(s1, s2) = splitHorizontallyBy (if f<0 then 1+f else f) r
|
|
nslave = (n - nmaster)
|
|
nslave1 = ceiling (nslave % 2)
|
|
nslave2 = (n - nmaster - nslave1)
|
|
|
|
splitVertically :: RealFrac r => [r] -> Int -> Rectangle -> [Rectangle]
|
|
splitVertically [] _ r = [r]
|
|
splitVertically _ n r | n < 2 = [r]
|
|
splitVertically (f:fx) n (Rectangle sx sy sw sh) =
|
|
let smallh = min sh (floor $ fromIntegral (sh `div` fromIntegral n) * f)
|
|
in Rectangle sx sy sw smallh :
|
|
splitVertically fx (n-1) (Rectangle sx (sy+fromIntegral smallh) sw (sh-smallh))
|
|
|
|
split3HorizontallyBy :: Bool -> Rational -> Rectangle -> (Rectangle, Rectangle, Rectangle)
|
|
split3HorizontallyBy middle f (Rectangle sx sy sw sh) =
|
|
if middle
|
|
then ( Rectangle (sx + fromIntegral r3w) sy r1w sh
|
|
, Rectangle (sx + fromIntegral r3w + fromIntegral r1w) sy r2w sh
|
|
, Rectangle sx sy r3w sh )
|
|
else ( Rectangle sx sy r1w sh
|
|
, Rectangle (sx + fromIntegral r1w) sy r2w sh
|
|
, Rectangle (sx + fromIntegral r1w + fromIntegral r2w) sy r3w sh )
|
|
where
|
|
r1w = ceiling $ fromIntegral sw * f
|
|
r2w = ceiling $ (sw - r1w) % 2
|
|
r3w = sw - r1w - r2w
|