{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  XMonad.Layout.Accordion
-- Description :  Put non-focused windows in ribbons at the top and bottom of the screen.
-- Copyright   :  (c) glasser@mit.edu
-- License     :  BSD
--
-- Maintainer  :  glasser@mit.edu
-- Stability   :  stable
-- Portability :  unportable
--
-- LayoutClass that puts non-focused windows in ribbons at the top and bottom
-- of the screen.
-----------------------------------------------------------------------------

module XMonad.Layout.Accordion (
    -- * Usage
    -- $usage
    Accordion(Accordion)) where

import XMonad
import qualified XMonad.StackSet as W
import Data.Ratio

-- $usage
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Layout.Accordion
--
-- Then edit your @layoutHook@ by adding the Accordion layout:
--
-- > myLayout = Accordion ||| Full ||| etc..
-- > main = xmonad def { layoutHook = myLayout }
--
-- For more detailed instructions on editing the layoutHook see
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and
-- "XMonad.Doc.Extending#Editing_the_layout_hook".

data Accordion a = Accordion deriving ( ReadPrec [Accordion a]
ReadPrec (Accordion a)
Int -> ReadS (Accordion a)
ReadS [Accordion a]
(Int -> ReadS (Accordion a))
-> ReadS [Accordion a]
-> ReadPrec (Accordion a)
-> ReadPrec [Accordion a]
-> Read (Accordion a)
forall a. ReadPrec [Accordion a]
forall a. ReadPrec (Accordion a)
forall a. Int -> ReadS (Accordion a)
forall a. ReadS [Accordion a]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: forall a. Int -> ReadS (Accordion a)
readsPrec :: Int -> ReadS (Accordion a)
$creadList :: forall a. ReadS [Accordion a]
readList :: ReadS [Accordion a]
$creadPrec :: forall a. ReadPrec (Accordion a)
readPrec :: ReadPrec (Accordion a)
$creadListPrec :: forall a. ReadPrec [Accordion a]
readListPrec :: ReadPrec [Accordion a]
Read, Int -> Accordion a -> ShowS
[Accordion a] -> ShowS
Accordion a -> String
(Int -> Accordion a -> ShowS)
-> (Accordion a -> String)
-> ([Accordion a] -> ShowS)
-> Show (Accordion a)
forall a. Int -> Accordion a -> ShowS
forall a. [Accordion a] -> ShowS
forall a. Accordion a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Int -> Accordion a -> ShowS
showsPrec :: Int -> Accordion a -> ShowS
$cshow :: forall a. Accordion a -> String
show :: Accordion a -> String
$cshowList :: forall a. [Accordion a] -> ShowS
showList :: [Accordion a] -> ShowS
Show )

instance LayoutClass Accordion Window where
    pureLayout :: Accordion Window
-> Rectangle -> Stack Window -> [(Window, Rectangle)]
pureLayout Accordion Window
_ Rectangle
sc Stack Window
ws = [Window] -> [Rectangle] -> [(Window, Rectangle)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Window]
ups [Rectangle]
tops [(Window, Rectangle)]
-> [(Window, Rectangle)] -> [(Window, Rectangle)]
forall a. [a] -> [a] -> [a]
++ [(Stack Window -> Window
forall a. Stack a -> a
W.focus Stack Window
ws, Rectangle
mainPane)] [(Window, Rectangle)]
-> [(Window, Rectangle)] -> [(Window, Rectangle)]
forall a. [a] -> [a] -> [a]
++ [Window] -> [Rectangle] -> [(Window, Rectangle)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Window]
dns [Rectangle]
bottoms
     where
       ups :: [Window]
ups    = [Window] -> [Window]
forall a. [a] -> [a]
reverse ([Window] -> [Window]) -> [Window] -> [Window]
forall a b. (a -> b) -> a -> b
$ Stack Window -> [Window]
forall a. Stack a -> [a]
W.up Stack Window
ws
       dns :: [Window]
dns    = Stack Window -> [Window]
forall a. Stack a -> [a]
W.down Stack Window
ws
       (Rectangle
top,  Rectangle
allButTop) = Ratio Int -> Rectangle -> (Rectangle, Rectangle)
forall r. RealFrac r => r -> Rectangle -> (Rectangle, Rectangle)
splitVerticallyBy (Int
1Int -> Int -> Ratio Int
forall a. Integral a => a -> a -> Ratio a
%Int
8 :: Ratio Int) Rectangle
sc
       (Rectangle
center,  Rectangle
bottom) = Ratio Int -> Rectangle -> (Rectangle, Rectangle)
forall r. RealFrac r => r -> Rectangle -> (Rectangle, Rectangle)
splitVerticallyBy (Int
6Int -> Int -> Ratio Int
forall a. Integral a => a -> a -> Ratio a
%Int
7 :: Ratio Int) Rectangle
allButTop
       (Rectangle
allButBottom, Rectangle
_) = Ratio Int -> Rectangle -> (Rectangle, Rectangle)
forall r. RealFrac r => r -> Rectangle -> (Rectangle, Rectangle)
splitVerticallyBy (Int
7Int -> Int -> Ratio Int
forall a. Integral a => a -> a -> Ratio a
%Int
8 :: Ratio Int) Rectangle
sc
       mainPane :: Rectangle
mainPane | [Window]
ups [Window] -> [Window] -> Bool
forall a. Eq a => a -> a -> Bool
/= [] Bool -> Bool -> Bool
&& [Window]
dns [Window] -> [Window] -> Bool
forall a. Eq a => a -> a -> Bool
/= [] = Rectangle
center
                | [Window]
ups [Window] -> [Window] -> Bool
forall a. Eq a => a -> a -> Bool
/= []              = Rectangle
allButTop
                | [Window]
dns [Window] -> [Window] -> Bool
forall a. Eq a => a -> a -> Bool
/= []              = Rectangle
allButBottom
                | Bool
otherwise              = Rectangle
sc
       tops :: [Rectangle]
tops    = if [Window]
ups [Window] -> [Window] -> Bool
forall a. Eq a => a -> a -> Bool
/= [] then Int -> Rectangle -> [Rectangle]
splitVertically ([Window] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Window]
ups) Rectangle
top    else []
       bottoms :: [Rectangle]
bottoms = if [Window]
dns [Window] -> [Window] -> Bool
forall a. Eq a => a -> a -> Bool
/= [] then Int -> Rectangle -> [Rectangle]
splitVertically ([Window] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Window]
dns) Rectangle
bottom else []