mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-05-19 03:20:21 -07:00
Added new messages the layout understands to allow changing the grid aspect ratio and setting the fraction of the master to a given value rather than changing it relative to the current value.
258 lines
11 KiB
Haskell
258 lines
11 KiB
Haskell
{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses #-}
|
|
|
|
----------------------------------------------------------------------
|
|
-- |
|
|
-- Module : XMonad.Layout.GridVariants
|
|
-- Copyright : (c) Norbert Zeh
|
|
-- License : BSD-style (see LICENSE)
|
|
--
|
|
-- Maintainer : nzeh@cs.dal.ca
|
|
-- Stability : unstable
|
|
-- Portability : unportable
|
|
--
|
|
-- Two layouts: one is a variant of the Grid layout that allows the
|
|
-- desired aspect ratio of windows to be specified. The other is like
|
|
-- Tall but places a grid with fixed number of rows and columns in the
|
|
-- master area and uses an aspect-ratio-specified layout for the
|
|
-- slaves.
|
|
----------------------------------------------------------------------
|
|
|
|
module XMonad.Layout.GridVariants ( -- * Usage
|
|
-- $usage
|
|
ChangeMasterGridGeom(..)
|
|
, ChangeGridGeom(..)
|
|
, Grid(..)
|
|
, TallGrid(..)
|
|
, SplitGrid(..)
|
|
, Orientation(..)
|
|
) where
|
|
|
|
import Control.Monad
|
|
import XMonad
|
|
import qualified XMonad.StackSet as W
|
|
|
|
-- $usage
|
|
-- This module can be used as follows:
|
|
--
|
|
-- > import XMonad.Layout.GridVariants
|
|
--
|
|
-- Then add something like this to your layouts:
|
|
--
|
|
-- > Grid (16/10)
|
|
--
|
|
-- for a 16:10 aspect ratio grid, or
|
|
--
|
|
-- > SplitGrid L 2 3 (2/3) (16/10) (5/100)
|
|
--
|
|
-- for a layout with a 2x3 master grid that uses 2/3 of the screen,
|
|
-- and a 16:10 aspect ratio slave grid to its right. The last
|
|
-- parameter is again the percentage by which the split between master
|
|
-- and slave area changes in response to Expand/Shrink messages.
|
|
--
|
|
-- To be able to change the geometry of the master grid, add something
|
|
-- like this to your keybindings:
|
|
--
|
|
-- > ((modm .|. shiftMask, xK_equal), sendMessage $ IncMasterCols 1),
|
|
-- > ((modm .|. shiftMask, xK_minus), sendMessage $ IncMasterCols (-1)),
|
|
-- > ((modm .|. controlMask, xK_equal), sendMessage $ IncMasterRows 1),
|
|
-- > ((modm .|. controlMask, xK_minus), sendMessage $ IncMasterRows (-1))
|
|
|
|
-- | Grid layout. The parameter is the desired x:y aspect ratio of windows
|
|
data Grid a = Grid !Rational
|
|
deriving (Read, Show)
|
|
|
|
instance LayoutClass Grid a where
|
|
|
|
pureLayout (Grid aspect) rect st = zip wins rects
|
|
where
|
|
wins = W.integrate st
|
|
nwins = length wins
|
|
rects = arrangeAspectGrid rect nwins aspect
|
|
|
|
pureMessage layout msg = fmap (changeGridAspect layout) (fromMessage msg)
|
|
|
|
description _ = "Grid"
|
|
|
|
changeGridAspect :: Grid a -> ChangeGridGeom -> Grid a
|
|
changeGridAspect (Grid _) (SetGridAspect aspect) = Grid aspect
|
|
changeGridAspect (Grid aspect) (ChangeGridAspect delta) =
|
|
Grid (max 0.00001 (aspect + delta))
|
|
|
|
-- |Geometry change messages understood by Grid and SplitGrid
|
|
data ChangeGridGeom
|
|
= SetGridAspect !Rational
|
|
| ChangeGridAspect !Rational
|
|
deriving Typeable
|
|
|
|
instance Message ChangeGridGeom
|
|
|
|
-- |SplitGrid layout. Parameters are
|
|
--
|
|
-- - side where the master is
|
|
-- - number of master rows
|
|
-- - number of master columns
|
|
-- - portion of screen used for master grid
|
|
-- - x:y aspect ratio of slave windows
|
|
-- - increment for resize messages
|
|
data SplitGrid a = SplitGrid Orientation !Int !Int !Rational !Rational !Rational
|
|
deriving (Read, Show)
|
|
|
|
-- |Type to specify the side of the screen that holds
|
|
-- the master area of a SplitGrid.
|
|
data Orientation = T | B | L | R
|
|
deriving (Eq, Read, Show)
|
|
|
|
instance LayoutClass SplitGrid a where
|
|
|
|
pureLayout (SplitGrid o mrows mcols mfrac saspect _) rect st = zip wins rects
|
|
where
|
|
wins = W.integrate st
|
|
nwins = length wins
|
|
rects = arrangeSplitGrid rect o nwins mrows mcols mfrac saspect
|
|
|
|
pureMessage layout msg =
|
|
msum [ fmap (resizeMaster layout) (fromMessage msg)
|
|
, fmap (changeMasterGrid layout) (fromMessage msg)
|
|
, fmap (changeSlaveGridAspect layout) (fromMessage msg)
|
|
]
|
|
|
|
description _ = "SplitGrid"
|
|
|
|
-- |The geometry change message understood by the master grid
|
|
data ChangeMasterGridGeom
|
|
= IncMasterRows !Int -- ^Change the number of master rows
|
|
| IncMasterCols !Int -- ^Change the number of master columns
|
|
| SetMasterRows !Int -- ^Set the number of master rows to absolute value
|
|
| SetMasterCols !Int -- ^Set the number of master columns to absolute value
|
|
| SetMasterFraction !Rational -- ^Set the fraction of the screen used by the master grid
|
|
deriving Typeable
|
|
|
|
instance Message ChangeMasterGridGeom
|
|
|
|
arrangeSplitGrid :: Rectangle -> Orientation -> Int -> Int -> Int -> Rational -> Rational -> [Rectangle]
|
|
arrangeSplitGrid rect@(Rectangle rx ry rw rh) o nwins mrows mcols mfrac saspect
|
|
| nwins <= mwins = arrangeMasterGrid rect nwins mcols
|
|
| mwins == 0 = arrangeAspectGrid rect nwins saspect
|
|
| otherwise = (arrangeMasterGrid mrect mwins mcols) ++
|
|
(arrangeAspectGrid srect swins saspect)
|
|
where
|
|
mwins = mrows * mcols
|
|
swins = nwins - mwins
|
|
mrect = Rectangle mx my mw mh
|
|
srect = Rectangle sx sy sw sh
|
|
(mh, sh, mw, sw) = if o `elem` [T, B] then
|
|
(ceiling (fromIntegral rh * mfrac), rh - mh, rw, rw)
|
|
else
|
|
(rh, rh, ceiling (fromIntegral rw * mfrac), rw - mw)
|
|
mx = fromIntegral rx + if o == R then fromIntegral sw else 0
|
|
my = fromIntegral ry + if o == B then fromIntegral sh else 0
|
|
sx = fromIntegral rx + if o == L then fromIntegral mw else 0
|
|
sy = fromIntegral ry + if o == T then fromIntegral mh else 0
|
|
|
|
arrangeMasterGrid :: Rectangle -> Int -> Int -> [Rectangle]
|
|
arrangeMasterGrid rect nwins mcols = arrangeGrid rect nwins (min nwins mcols)
|
|
|
|
arrangeAspectGrid :: Rectangle -> Int -> Rational -> [Rectangle]
|
|
arrangeAspectGrid rect@(Rectangle _ _ rw rh) nwins aspect =
|
|
arrangeGrid rect nwins (min nwins ncols)
|
|
where
|
|
scr_a = fromIntegral rw / fromIntegral rh
|
|
fcols = sqrt ( fromRational $ scr_a * fromIntegral nwins / aspect ) :: Double
|
|
cols1 = floor fcols :: Int
|
|
cols2 = ceiling fcols :: Int
|
|
rows1 = ceiling ( fromIntegral nwins / fromIntegral cols1 :: Rational ) :: Int
|
|
rows2 = floor ( fromIntegral nwins / fromIntegral cols2 :: Rational ) :: Int
|
|
a1 = scr_a * fromIntegral rows1 / fromIntegral cols1
|
|
a2 = scr_a * fromIntegral rows2 / fromIntegral cols2
|
|
ncols | cols1 == 0 = cols2
|
|
| rows2 == 0 = cols1
|
|
| a1 / aspect < aspect / a2 = cols1
|
|
| otherwise = cols2
|
|
|
|
arrangeGrid :: Rectangle -> Int -> Int -> [Rectangle]
|
|
arrangeGrid (Rectangle rx ry rw rh) nwins ncols =
|
|
[Rectangle (fromIntegral x + rx) (fromIntegral y + ry) (fromIntegral w) (fromIntegral h)
|
|
| (x, y, w, h) <- rects]
|
|
where
|
|
nrows_in_cols = listDifference $ splitEvenly nwins ncols
|
|
x_slabs = splitIntoSlabs (fromIntegral rw) ncols
|
|
y_slabs = [splitIntoSlabs (fromIntegral rh) nrows | nrows <- nrows_in_cols]
|
|
rects_in_cols = [[(x, y, w, h) | (y, h) <- lst]
|
|
| ((x, w), lst) <- zip x_slabs y_slabs]
|
|
rects = foldr (++) [] rects_in_cols
|
|
|
|
splitIntoSlabs :: Int -> Int -> [(Int, Int)]
|
|
splitIntoSlabs width nslabs = zip (0:xs) widths
|
|
where
|
|
xs = splitEvenly width nslabs
|
|
widths = listDifference xs
|
|
|
|
listDifference :: [Int] -> [Int]
|
|
listDifference lst = [cur-pre | (cur,pre) <- zip lst (0:lst)]
|
|
|
|
splitEvenly :: Int -> Int -> [Int]
|
|
splitEvenly n parts = [ sz-off | (sz,off) <- zip sizes offsets]
|
|
where
|
|
size = ceiling ( (fromIntegral n / fromIntegral parts) :: Double )
|
|
extra = size*parts - n
|
|
sizes = [i*size | i <- [1..parts]]
|
|
offsets = (take (fromIntegral extra) [1..]) ++ [extra,extra..]
|
|
|
|
resizeMaster :: SplitGrid a -> Resize -> SplitGrid a
|
|
resizeMaster (SplitGrid o mrows mcols mfrac saspect delta) Shrink =
|
|
SplitGrid o mrows mcols (max 0 (mfrac - delta)) saspect delta
|
|
resizeMaster (SplitGrid o mrows mcols mfrac saspect delta) Expand =
|
|
SplitGrid o mrows mcols (min 1 (mfrac + delta)) saspect delta
|
|
|
|
changeMasterGrid :: SplitGrid a -> ChangeMasterGridGeom -> SplitGrid a
|
|
changeMasterGrid (SplitGrid o mrows mcols mfrac saspect delta) (IncMasterRows d) =
|
|
SplitGrid o (max 0 (mrows + d)) mcols mfrac saspect delta
|
|
changeMasterGrid (SplitGrid o mrows mcols mfrac saspect delta) (IncMasterCols d) =
|
|
SplitGrid o mrows (max 0 (mcols + d)) mfrac saspect delta
|
|
changeMasterGrid (SplitGrid o _ mcols mfrac saspect delta) (SetMasterRows mrows) =
|
|
SplitGrid o (max 0 mrows) mcols mfrac saspect delta
|
|
changeMasterGrid (SplitGrid o mrows _ mfrac saspect delta) (SetMasterCols mcols) =
|
|
SplitGrid o mrows (max 0 mcols) mfrac saspect delta
|
|
changeMasterGrid (SplitGrid o mrows mcols _ saspect delta) (SetMasterFraction mfrac) =
|
|
SplitGrid o mrows mcols mfrac saspect delta
|
|
|
|
changeSlaveGridAspect :: SplitGrid a -> ChangeGridGeom -> SplitGrid a
|
|
changeSlaveGridAspect (SplitGrid o mrows mcols mfrac _ delta) (SetGridAspect saspect) =
|
|
SplitGrid o mrows mcols mfrac saspect delta
|
|
changeSlaveGridAspect (SplitGrid o mrows mcols mfrac saspect delta) (ChangeGridAspect sdelta) =
|
|
SplitGrid o mrows mcols mfrac (max 0.00001 (saspect + sdelta)) delta
|
|
|
|
-- | TallGrid layout. Parameters are
|
|
--
|
|
-- - number of master rows
|
|
-- - number of master columns
|
|
-- - portion of screen used for master grid
|
|
-- - x:y aspect ratio of slave windows
|
|
-- - increment for resize messages
|
|
--
|
|
-- This exists mostly because it was introduced in an earlier version.
|
|
-- It's a fairly thin wrapper around "SplitGrid L".
|
|
data TallGrid a = TallGrid !Int !Int !Rational !Rational !Rational
|
|
deriving (Read, Show)
|
|
|
|
instance LayoutClass TallGrid a where
|
|
|
|
pureLayout (TallGrid mrows mcols mfrac saspect _) rect st = zip wins rects
|
|
where
|
|
wins = W.integrate st
|
|
nwins = length wins
|
|
rects = arrangeSplitGrid rect L nwins mrows mcols mfrac saspect
|
|
|
|
pureMessage layout msg =
|
|
msum [ fmap ((tallGridAdapter resizeMaster) layout) (fromMessage msg)
|
|
, fmap ((tallGridAdapter changeMasterGrid) layout) (fromMessage msg) ]
|
|
|
|
description _ = "TallGrid"
|
|
|
|
tallGridAdapter :: (SplitGrid a -> b -> SplitGrid a) -> TallGrid a -> b -> TallGrid a
|
|
tallGridAdapter f (TallGrid mrows mcols mfrac saspect delta) msg =
|
|
TallGrid mrows' mcols' mfrac' saspect' delta'
|
|
where
|
|
SplitGrid _ mrows' mcols' mfrac' saspect' delta' =
|
|
f (SplitGrid L mrows mcols mfrac saspect delta) msg
|