{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}

----------------------------------------------------------------------
-- |
-- Module      : XMonad.Layout.GridVariants
-- Description : Two grid layouts.
-- 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 XMonad.Prelude
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
newtype Grid a = Grid Rational
              deriving (ReadPrec [Grid a]
ReadPrec (Grid a)
Int -> ReadS (Grid a)
ReadS [Grid a]
(Int -> ReadS (Grid a))
-> ReadS [Grid a]
-> ReadPrec (Grid a)
-> ReadPrec [Grid a]
-> Read (Grid a)
forall a. ReadPrec [Grid a]
forall a. ReadPrec (Grid a)
forall a. Int -> ReadS (Grid a)
forall a. ReadS [Grid a]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: forall a. Int -> ReadS (Grid a)
readsPrec :: Int -> ReadS (Grid a)
$creadList :: forall a. ReadS [Grid a]
readList :: ReadS [Grid a]
$creadPrec :: forall a. ReadPrec (Grid a)
readPrec :: ReadPrec (Grid a)
$creadListPrec :: forall a. ReadPrec [Grid a]
readListPrec :: ReadPrec [Grid a]
Read, Int -> Grid a -> ShowS
[Grid a] -> ShowS
Grid a -> String
(Int -> Grid a -> ShowS)
-> (Grid a -> String) -> ([Grid a] -> ShowS) -> Show (Grid a)
forall a. Int -> Grid a -> ShowS
forall a. [Grid a] -> ShowS
forall a. Grid a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Int -> Grid a -> ShowS
showsPrec :: Int -> Grid a -> ShowS
$cshow :: forall a. Grid a -> String
show :: Grid a -> String
$cshowList :: forall a. [Grid a] -> ShowS
showList :: [Grid a] -> ShowS
Show)

instance LayoutClass Grid a where

    pureLayout :: Grid a -> Rectangle -> Stack a -> [(a, Rectangle)]
pureLayout (Grid Rational
aspect) Rectangle
rect Stack a
st = [a] -> [Rectangle] -> [(a, Rectangle)]
forall a b. [a] -> [b] -> [(a, b)]
zip [a]
wins [Rectangle]
rects
        where
          wins :: [a]
wins  = Stack a -> [a]
forall a. Stack a -> [a]
W.integrate Stack a
st
          nwins :: Int
nwins = [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
wins
          rects :: [Rectangle]
rects = Rectangle -> Int -> Rational -> [Rectangle]
arrangeAspectGrid Rectangle
rect Int
nwins Rational
aspect

    pureMessage :: Grid a -> SomeMessage -> Maybe (Grid a)
pureMessage Grid a
layout SomeMessage
msg = (ChangeGridGeom -> Grid a)
-> Maybe ChangeGridGeom -> Maybe (Grid a)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Grid a -> ChangeGridGeom -> Grid a
forall a. Grid a -> ChangeGridGeom -> Grid a
changeGridAspect Grid a
layout) (SomeMessage -> Maybe ChangeGridGeom
forall m. Message m => SomeMessage -> Maybe m
fromMessage SomeMessage
msg)

    description :: Grid a -> String
description Grid a
_ = String
"Grid"

changeGridAspect :: Grid a -> ChangeGridGeom -> Grid a
changeGridAspect :: forall a. Grid a -> ChangeGridGeom -> Grid a
changeGridAspect (Grid Rational
_) (SetGridAspect Rational
aspect) = Rational -> Grid a
forall a. Rational -> Grid a
Grid Rational
aspect
changeGridAspect (Grid Rational
aspect) (ChangeGridAspect Rational
delta) =
    Rational -> Grid a
forall a. Rational -> Grid a
Grid (Rational -> Rational -> Rational
forall a. Ord a => a -> a -> a
max Rational
0.00001 (Rational
aspect Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Rational
delta))

-- |Geometry change messages understood by Grid and SplitGrid
data ChangeGridGeom
    = SetGridAspect !Rational
    | ChangeGridAspect !Rational

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 (ReadPrec [SplitGrid a]
ReadPrec (SplitGrid a)
Int -> ReadS (SplitGrid a)
ReadS [SplitGrid a]
(Int -> ReadS (SplitGrid a))
-> ReadS [SplitGrid a]
-> ReadPrec (SplitGrid a)
-> ReadPrec [SplitGrid a]
-> Read (SplitGrid a)
forall a. ReadPrec [SplitGrid a]
forall a. ReadPrec (SplitGrid a)
forall a. Int -> ReadS (SplitGrid a)
forall a. ReadS [SplitGrid a]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: forall a. Int -> ReadS (SplitGrid a)
readsPrec :: Int -> ReadS (SplitGrid a)
$creadList :: forall a. ReadS [SplitGrid a]
readList :: ReadS [SplitGrid a]
$creadPrec :: forall a. ReadPrec (SplitGrid a)
readPrec :: ReadPrec (SplitGrid a)
$creadListPrec :: forall a. ReadPrec [SplitGrid a]
readListPrec :: ReadPrec [SplitGrid a]
Read, Int -> SplitGrid a -> ShowS
[SplitGrid a] -> ShowS
SplitGrid a -> String
(Int -> SplitGrid a -> ShowS)
-> (SplitGrid a -> String)
-> ([SplitGrid a] -> ShowS)
-> Show (SplitGrid a)
forall a. Int -> SplitGrid a -> ShowS
forall a. [SplitGrid a] -> ShowS
forall a. SplitGrid a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Int -> SplitGrid a -> ShowS
showsPrec :: Int -> SplitGrid a -> ShowS
$cshow :: forall a. SplitGrid a -> String
show :: SplitGrid a -> String
$cshowList :: forall a. [SplitGrid a] -> ShowS
showList :: [SplitGrid a] -> ShowS
Show)

-- |Type to specify the side of the screen that holds
--  the master area of a SplitGrid.
data Orientation = T | B | L | R
                   deriving (Orientation -> Orientation -> Bool
(Orientation -> Orientation -> Bool)
-> (Orientation -> Orientation -> Bool) -> Eq Orientation
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Orientation -> Orientation -> Bool
== :: Orientation -> Orientation -> Bool
$c/= :: Orientation -> Orientation -> Bool
/= :: Orientation -> Orientation -> Bool
Eq, ReadPrec [Orientation]
ReadPrec Orientation
Int -> ReadS Orientation
ReadS [Orientation]
(Int -> ReadS Orientation)
-> ReadS [Orientation]
-> ReadPrec Orientation
-> ReadPrec [Orientation]
-> Read Orientation
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS Orientation
readsPrec :: Int -> ReadS Orientation
$creadList :: ReadS [Orientation]
readList :: ReadS [Orientation]
$creadPrec :: ReadPrec Orientation
readPrec :: ReadPrec Orientation
$creadListPrec :: ReadPrec [Orientation]
readListPrec :: ReadPrec [Orientation]
Read, Int -> Orientation -> ShowS
[Orientation] -> ShowS
Orientation -> String
(Int -> Orientation -> ShowS)
-> (Orientation -> String)
-> ([Orientation] -> ShowS)
-> Show Orientation
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Orientation -> ShowS
showsPrec :: Int -> Orientation -> ShowS
$cshow :: Orientation -> String
show :: Orientation -> String
$cshowList :: [Orientation] -> ShowS
showList :: [Orientation] -> ShowS
Show)

instance LayoutClass SplitGrid a where

    pureLayout :: SplitGrid a -> Rectangle -> Stack a -> [(a, Rectangle)]
pureLayout (SplitGrid Orientation
o Int
mrows Int
mcols Rational
mfrac Rational
saspect Rational
_) Rectangle
rect Stack a
st = [a] -> [Rectangle] -> [(a, Rectangle)]
forall a b. [a] -> [b] -> [(a, b)]
zip [a]
wins [Rectangle]
rects
        where
          wins :: [a]
wins  = Stack a -> [a]
forall a. Stack a -> [a]
W.integrate Stack a
st
          nwins :: Int
nwins = [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
wins
          rects :: [Rectangle]
rects = Rectangle
-> Orientation
-> Int
-> Int
-> Int
-> Rational
-> Rational
-> [Rectangle]
arrangeSplitGrid Rectangle
rect Orientation
o Int
nwins Int
mrows Int
mcols Rational
mfrac Rational
saspect

    pureMessage :: SplitGrid a -> SomeMessage -> Maybe (SplitGrid a)
pureMessage SplitGrid a
layout SomeMessage
msg =
        [Maybe (SplitGrid a)] -> Maybe (SplitGrid a)
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum [ (Resize -> SplitGrid a) -> Maybe Resize -> Maybe (SplitGrid a)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (SplitGrid a -> Resize -> SplitGrid a
forall a. SplitGrid a -> Resize -> SplitGrid a
resizeMaster SplitGrid a
layout)          (SomeMessage -> Maybe Resize
forall m. Message m => SomeMessage -> Maybe m
fromMessage SomeMessage
msg)
             , (ChangeMasterGridGeom -> SplitGrid a)
-> Maybe ChangeMasterGridGeom -> Maybe (SplitGrid a)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (SplitGrid a -> ChangeMasterGridGeom -> SplitGrid a
forall a. SplitGrid a -> ChangeMasterGridGeom -> SplitGrid a
changeMasterGrid SplitGrid a
layout)      (SomeMessage -> Maybe ChangeMasterGridGeom
forall m. Message m => SomeMessage -> Maybe m
fromMessage SomeMessage
msg)
             , (ChangeGridGeom -> SplitGrid a)
-> Maybe ChangeGridGeom -> Maybe (SplitGrid a)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (SplitGrid a -> ChangeGridGeom -> SplitGrid a
forall a. SplitGrid a -> ChangeGridGeom -> SplitGrid a
changeSlaveGridAspect SplitGrid a
layout) (SomeMessage -> Maybe ChangeGridGeom
forall m. Message m => SomeMessage -> Maybe m
fromMessage SomeMessage
msg)
             ]

    description :: SplitGrid a -> String
description SplitGrid a
_ = String
"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

instance Message ChangeMasterGridGeom

arrangeSplitGrid :: Rectangle -> Orientation -> Int -> Int -> Int -> Rational -> Rational -> [Rectangle]
arrangeSplitGrid :: Rectangle
-> Orientation
-> Int
-> Int
-> Int
-> Rational
-> Rational
-> [Rectangle]
arrangeSplitGrid rect :: Rectangle
rect@(Rectangle Position
rx Position
ry Dimension
rw Dimension
rh) Orientation
o Int
nwins Int
mrows Int
mcols Rational
mfrac Rational
saspect
    | Int
nwins Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
mwins = Rectangle -> Int -> Int -> [Rectangle]
arrangeMasterGrid Rectangle
rect Int
nwins Int
mcols
    | Int
mwins Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0     = Rectangle -> Int -> Rational -> [Rectangle]
arrangeAspectGrid Rectangle
rect Int
nwins Rational
saspect
    | Bool
otherwise      = Rectangle -> Int -> Int -> [Rectangle]
arrangeMasterGrid Rectangle
mrect Int
mwins Int
mcols [Rectangle] -> [Rectangle] -> [Rectangle]
forall a. [a] -> [a] -> [a]
++
                       Rectangle -> Int -> Rational -> [Rectangle]
arrangeAspectGrid Rectangle
srect Int
swins Rational
saspect
    where
      mwins :: Int
mwins            = Int
mrows Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
mcols
      swins :: Int
swins            = Int
nwins Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
mwins
      mrect :: Rectangle
mrect            = Position -> Position -> Dimension -> Dimension -> Rectangle
Rectangle Position
mx Position
my Dimension
mw Dimension
mh
      srect :: Rectangle
srect            = Position -> Position -> Dimension -> Dimension -> Rectangle
Rectangle Position
sx Position
sy Dimension
sw Dimension
sh
      (Dimension
mh, Dimension
sh, Dimension
mw, Dimension
sw) = if Orientation
o Orientation -> [Orientation] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Orientation
T, Orientation
B] then
                             (Rational -> Dimension
forall b. Integral b => Rational -> b
forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Dimension -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Dimension
rh Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Rational
mfrac), Dimension
rh Dimension -> Dimension -> Dimension
forall a. Num a => a -> a -> a
- Dimension
mh, Dimension
rw, Dimension
rw)
                         else
                             (Dimension
rh, Dimension
rh, Rational -> Dimension
forall b. Integral b => Rational -> b
forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Dimension -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Dimension
rw Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Rational
mfrac), Dimension
rw Dimension -> Dimension -> Dimension
forall a. Num a => a -> a -> a
- Dimension
mw)
      mx :: Position
mx               = Position -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral Position
rx Position -> Position -> Position
forall a. Num a => a -> a -> a
+ if Orientation
o Orientation -> Orientation -> Bool
forall a. Eq a => a -> a -> Bool
== Orientation
R then Dimension -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral Dimension
sw else Position
0
      my :: Position
my               = Position -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral Position
ry Position -> Position -> Position
forall a. Num a => a -> a -> a
+ if Orientation
o Orientation -> Orientation -> Bool
forall a. Eq a => a -> a -> Bool
== Orientation
B then Dimension -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral Dimension
sh else Position
0
      sx :: Position
sx               = Position -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral Position
rx Position -> Position -> Position
forall a. Num a => a -> a -> a
+ if Orientation
o Orientation -> Orientation -> Bool
forall a. Eq a => a -> a -> Bool
== Orientation
L then Dimension -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral Dimension
mw else Position
0
      sy :: Position
sy               = Position -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral Position
ry Position -> Position -> Position
forall a. Num a => a -> a -> a
+ if Orientation
o Orientation -> Orientation -> Bool
forall a. Eq a => a -> a -> Bool
== Orientation
T then Dimension -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral Dimension
mh else Position
0

arrangeMasterGrid :: Rectangle -> Int -> Int -> [Rectangle]
arrangeMasterGrid :: Rectangle -> Int -> Int -> [Rectangle]
arrangeMasterGrid Rectangle
rect Int
nwins Int
mcols = Rectangle -> Int -> Int -> [Rectangle]
arrangeGrid Rectangle
rect Int
nwins (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
nwins Int
mcols)

arrangeAspectGrid :: Rectangle -> Int -> Rational -> [Rectangle]
arrangeAspectGrid :: Rectangle -> Int -> Rational -> [Rectangle]
arrangeAspectGrid rect :: Rectangle
rect@(Rectangle Position
_ Position
_ Dimension
rw Dimension
rh) Int
nwins Rational
aspect =
    Rectangle -> Int -> Int -> [Rectangle]
arrangeGrid Rectangle
rect Int
nwins (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
nwins Int
ncols)
    where
      scr_a :: Rational
scr_a = Dimension -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Dimension
rw Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Dimension -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Dimension
rh
      fcols :: Double
fcols = Double -> Double
forall a. Floating a => a -> a
sqrt ( Rational -> Double
forall a. Fractional a => Rational -> a
fromRational (Rational -> Double) -> Rational -> Double
forall a b. (a -> b) -> a -> b
$ Rational
scr_a Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Int -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nwins Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Rational
aspect ) :: Double
      cols1 :: Int
cols1 = Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor Double
fcols :: Int
      cols2 :: Int
cols2 = Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
ceiling Double
fcols :: Int
      rows1 :: Int
rows1 = Rational -> Int
forall b. Integral b => Rational -> b
forall a b. (RealFrac a, Integral b) => a -> b
ceiling ( Int -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nwins Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Int -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
cols1 :: Rational ) :: Int
      rows2 :: Int
rows2 = Rational -> Int
forall b. Integral b => Rational -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor ( Int -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nwins Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Int -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
cols2 :: Rational ) :: Int
      a1 :: Rational
a1    = Rational
scr_a Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Int -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
rows1 Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Int -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
cols1
      a2 :: Rational
a2    = Rational
scr_a Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Int -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
rows2 Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Int -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
cols2
      ncols :: Int
ncols | Int
cols1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0                = Int
cols2
            | Int
rows2 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0                = Int
cols1
            | Rational
a1 Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Rational
aspect Rational -> Rational -> Bool
forall a. Ord a => a -> a -> Bool
< Rational
aspect Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Rational
a2 = Int
cols1
            | Bool
otherwise                 = Int
cols2

arrangeGrid :: Rectangle -> Int -> Int -> [Rectangle]
arrangeGrid :: Rectangle -> Int -> Int -> [Rectangle]
arrangeGrid (Rectangle Position
rx Position
ry Dimension
rw Dimension
rh) Int
nwins Int
ncols =
    [Position -> Position -> Dimension -> Dimension -> Rectangle
Rectangle (Int -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
x Position -> Position -> Position
forall a. Num a => a -> a -> a
+ Position
rx) (Int -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
y Position -> Position -> Position
forall a. Num a => a -> a -> a
+ Position
ry) (Int -> Dimension
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
w) (Int -> Dimension
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
h)
     | (Int
x, Int
y, Int
w, Int
h) <- [(Int, Int, Int, Int)]
rects]
    where
      nrows_in_cols :: [Int]
nrows_in_cols = [Int] -> [Int]
listDifference ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ Int -> Int -> [Int]
splitEvenly Int
nwins Int
ncols
      x_slabs :: [(Int, Int)]
x_slabs       = Int -> Int -> [(Int, Int)]
splitIntoSlabs (Dimension -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Dimension
rw) Int
ncols
      y_slabs :: [[(Int, Int)]]
y_slabs       = [Int -> Int -> [(Int, Int)]
splitIntoSlabs (Dimension -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Dimension
rh) Int
nrows | Int
nrows <- [Int]
nrows_in_cols]
      rects_in_cols :: [[(Int, Int, Int, Int)]]
rects_in_cols = [[(Int
x, Int
y, Int
w, Int
h) | (Int
y, Int
h) <- [(Int, Int)]
lst]
                       | ((Int
x, Int
w), [(Int, Int)]
lst) <- [(Int, Int)] -> [[(Int, Int)]] -> [((Int, Int), [(Int, Int)])]
forall a b. [a] -> [b] -> [(a, b)]
zip [(Int, Int)]
x_slabs [[(Int, Int)]]
y_slabs]
      rects :: [(Int, Int, Int, Int)]
rects         = [[(Int, Int, Int, Int)]] -> [(Int, Int, Int, Int)]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[(Int, Int, Int, Int)]]
rects_in_cols

splitIntoSlabs :: Int -> Int -> [(Int, Int)]
splitIntoSlabs :: Int -> Int -> [(Int, Int)]
splitIntoSlabs Int
width Int
nslabs = [Int] -> [Int] -> [(Int, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip (Int
0Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
:[Int]
xs) [Int]
widths
    where
      xs :: [Int]
xs = Int -> Int -> [Int]
splitEvenly Int
width Int
nslabs
      widths :: [Int]
widths = [Int] -> [Int]
listDifference [Int]
xs

listDifference :: [Int] -> [Int]
listDifference :: [Int] -> [Int]
listDifference [Int]
lst = [Int
curInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
pre | (Int
cur,Int
pre) <- [Int] -> [Int] -> [(Int, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int]
lst (Int
0Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
:[Int]
lst)]

splitEvenly :: Int -> Int -> [Int]
splitEvenly :: Int -> Int -> [Int]
splitEvenly Int
n Int
parts = [ Int
szInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
off | (Int
sz,Int
off) <- [Int] -> [Int] -> [(Int, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int]
sizes [Int]
offsets]
    where
      size :: Int
size    = Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
ceiling ( (Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
parts) :: Double )
      extra :: Int
extra   = Int
sizeInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
parts Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n
      sizes :: [Int]
sizes   = [Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
size | Int
i <- [Int
1..Int
parts]]
      offsets :: [Int]
offsets = Int -> [Int] -> [Int]
forall a. Int -> [a] -> [a]
take (Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
extra) [Int
1..] [Int] -> [Int] -> [Int]
forall a. [a] -> [a] -> [a]
++ [Int
extra,Int
extra..]

resizeMaster :: SplitGrid a -> Resize -> SplitGrid a
resizeMaster :: forall a. SplitGrid a -> Resize -> SplitGrid a
resizeMaster (SplitGrid Orientation
o Int
mrows Int
mcols Rational
mfrac Rational
saspect Rational
delta) Resize
Shrink =
    Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
forall a.
Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
SplitGrid Orientation
o Int
mrows Int
mcols (Rational -> Rational -> Rational
forall a. Ord a => a -> a -> a
max Rational
0 (Rational
mfrac Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
- Rational
delta)) Rational
saspect Rational
delta
resizeMaster (SplitGrid Orientation
o Int
mrows Int
mcols Rational
mfrac Rational
saspect Rational
delta) Resize
Expand =
    Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
forall a.
Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
SplitGrid Orientation
o Int
mrows Int
mcols (Rational -> Rational -> Rational
forall a. Ord a => a -> a -> a
min Rational
1 (Rational
mfrac Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Rational
delta)) Rational
saspect Rational
delta

changeMasterGrid :: SplitGrid a -> ChangeMasterGridGeom -> SplitGrid a
changeMasterGrid :: forall a. SplitGrid a -> ChangeMasterGridGeom -> SplitGrid a
changeMasterGrid (SplitGrid Orientation
o Int
mrows Int
mcols Rational
mfrac Rational
saspect Rational
delta) (IncMasterRows Int
d) =
    Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
forall a.
Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
SplitGrid Orientation
o (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int
mrows Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
d)) Int
mcols Rational
mfrac Rational
saspect Rational
delta
changeMasterGrid (SplitGrid Orientation
o Int
mrows Int
mcols Rational
mfrac Rational
saspect Rational
delta) (IncMasterCols Int
d) =
    Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
forall a.
Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
SplitGrid Orientation
o Int
mrows (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int
mcols Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
d)) Rational
mfrac Rational
saspect Rational
delta
changeMasterGrid (SplitGrid Orientation
o Int
_ Int
mcols Rational
mfrac Rational
saspect Rational
delta) (SetMasterRows Int
mrows) =
    Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
forall a.
Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
SplitGrid Orientation
o (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 Int
mrows) Int
mcols Rational
mfrac Rational
saspect Rational
delta
changeMasterGrid (SplitGrid Orientation
o Int
mrows Int
_ Rational
mfrac Rational
saspect Rational
delta) (SetMasterCols Int
mcols) =
    Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
forall a.
Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
SplitGrid Orientation
o Int
mrows (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 Int
mcols) Rational
mfrac Rational
saspect Rational
delta
changeMasterGrid (SplitGrid Orientation
o Int
mrows Int
mcols Rational
_ Rational
saspect Rational
delta) (SetMasterFraction Rational
mfrac) =
    Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
forall a.
Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
SplitGrid Orientation
o Int
mrows Int
mcols Rational
mfrac Rational
saspect Rational
delta

changeSlaveGridAspect :: SplitGrid a -> ChangeGridGeom -> SplitGrid a
changeSlaveGridAspect :: forall a. SplitGrid a -> ChangeGridGeom -> SplitGrid a
changeSlaveGridAspect (SplitGrid Orientation
o Int
mrows Int
mcols Rational
mfrac Rational
_ Rational
delta) (SetGridAspect Rational
saspect) =
    Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
forall a.
Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
SplitGrid Orientation
o Int
mrows Int
mcols Rational
mfrac Rational
saspect Rational
delta
changeSlaveGridAspect (SplitGrid Orientation
o Int
mrows Int
mcols Rational
mfrac Rational
saspect Rational
delta) (ChangeGridAspect Rational
sdelta) =
    Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
forall a.
Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
SplitGrid Orientation
o Int
mrows Int
mcols Rational
mfrac (Rational -> Rational -> Rational
forall a. Ord a => a -> a -> a
max Rational
0.00001 (Rational
saspect Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Rational
sdelta)) Rational
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 (ReadPrec [TallGrid a]
ReadPrec (TallGrid a)
Int -> ReadS (TallGrid a)
ReadS [TallGrid a]
(Int -> ReadS (TallGrid a))
-> ReadS [TallGrid a]
-> ReadPrec (TallGrid a)
-> ReadPrec [TallGrid a]
-> Read (TallGrid a)
forall a. ReadPrec [TallGrid a]
forall a. ReadPrec (TallGrid a)
forall a. Int -> ReadS (TallGrid a)
forall a. ReadS [TallGrid a]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: forall a. Int -> ReadS (TallGrid a)
readsPrec :: Int -> ReadS (TallGrid a)
$creadList :: forall a. ReadS [TallGrid a]
readList :: ReadS [TallGrid a]
$creadPrec :: forall a. ReadPrec (TallGrid a)
readPrec :: ReadPrec (TallGrid a)
$creadListPrec :: forall a. ReadPrec [TallGrid a]
readListPrec :: ReadPrec [TallGrid a]
Read, Int -> TallGrid a -> ShowS
[TallGrid a] -> ShowS
TallGrid a -> String
(Int -> TallGrid a -> ShowS)
-> (TallGrid a -> String)
-> ([TallGrid a] -> ShowS)
-> Show (TallGrid a)
forall a. Int -> TallGrid a -> ShowS
forall a. [TallGrid a] -> ShowS
forall a. TallGrid a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Int -> TallGrid a -> ShowS
showsPrec :: Int -> TallGrid a -> ShowS
$cshow :: forall a. TallGrid a -> String
show :: TallGrid a -> String
$cshowList :: forall a. [TallGrid a] -> ShowS
showList :: [TallGrid a] -> ShowS
Show)

instance LayoutClass TallGrid a where

    pureLayout :: TallGrid a -> Rectangle -> Stack a -> [(a, Rectangle)]
pureLayout (TallGrid Int
mrows Int
mcols Rational
mfrac Rational
saspect Rational
_) Rectangle
rect Stack a
st = [a] -> [Rectangle] -> [(a, Rectangle)]
forall a b. [a] -> [b] -> [(a, b)]
zip [a]
wins [Rectangle]
rects
        where
          wins :: [a]
wins  = Stack a -> [a]
forall a. Stack a -> [a]
W.integrate Stack a
st
          nwins :: Int
nwins = [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
wins
          rects :: [Rectangle]
rects = Rectangle
-> Orientation
-> Int
-> Int
-> Int
-> Rational
-> Rational
-> [Rectangle]
arrangeSplitGrid Rectangle
rect Orientation
L Int
nwins Int
mrows Int
mcols Rational
mfrac Rational
saspect

    pureMessage :: TallGrid a -> SomeMessage -> Maybe (TallGrid a)
pureMessage TallGrid a
layout SomeMessage
msg =
        [Maybe (TallGrid a)] -> Maybe (TallGrid a)
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum [ (Resize -> TallGrid a) -> Maybe Resize -> Maybe (TallGrid a)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((SplitGrid a -> Resize -> SplitGrid a)
-> TallGrid a -> Resize -> TallGrid a
forall a b.
(SplitGrid a -> b -> SplitGrid a) -> TallGrid a -> b -> TallGrid a
tallGridAdapter SplitGrid a -> Resize -> SplitGrid a
forall a. SplitGrid a -> Resize -> SplitGrid a
resizeMaster TallGrid a
layout) (SomeMessage -> Maybe Resize
forall m. Message m => SomeMessage -> Maybe m
fromMessage SomeMessage
msg)
             , (ChangeMasterGridGeom -> TallGrid a)
-> Maybe ChangeMasterGridGeom -> Maybe (TallGrid a)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((SplitGrid a -> ChangeMasterGridGeom -> SplitGrid a)
-> TallGrid a -> ChangeMasterGridGeom -> TallGrid a
forall a b.
(SplitGrid a -> b -> SplitGrid a) -> TallGrid a -> b -> TallGrid a
tallGridAdapter SplitGrid a -> ChangeMasterGridGeom -> SplitGrid a
forall a. SplitGrid a -> ChangeMasterGridGeom -> SplitGrid a
changeMasterGrid TallGrid a
layout) (SomeMessage -> Maybe ChangeMasterGridGeom
forall m. Message m => SomeMessage -> Maybe m
fromMessage SomeMessage
msg) ]

    description :: TallGrid a -> String
description TallGrid a
_ = String
"TallGrid"

tallGridAdapter :: (SplitGrid a -> b -> SplitGrid a) -> TallGrid a -> b -> TallGrid a
tallGridAdapter :: forall a b.
(SplitGrid a -> b -> SplitGrid a) -> TallGrid a -> b -> TallGrid a
tallGridAdapter SplitGrid a -> b -> SplitGrid a
f (TallGrid Int
mrows Int
mcols Rational
mfrac Rational
saspect Rational
delta) b
msg =
    Int -> Int -> Rational -> Rational -> Rational -> TallGrid a
forall a.
Int -> Int -> Rational -> Rational -> Rational -> TallGrid a
TallGrid Int
mrows' Int
mcols' Rational
mfrac' Rational
saspect' Rational
delta'
    where
      SplitGrid Orientation
_ Int
mrows' Int
mcols' Rational
mfrac' Rational
saspect' Rational
delta' =
          SplitGrid a -> b -> SplitGrid a
f (Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
forall a.
Orientation
-> Int -> Int -> Rational -> Rational -> Rational -> SplitGrid a
SplitGrid Orientation
L Int
mrows Int
mcols Rational
mfrac Rational
saspect Rational
delta) b
msg