{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving, MultiParamTypeClasses, TypeSynonymInstances #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  XMonad.Layout.MosaicAlt
-- Copyright   :  (c) 2007 James Webb
-- License     :  BSD-style (see xmonad/LICENSE)
--
-- Maintainer  :  xmonad#jwebb,sygneca,com
-- Stability   :  unstable
-- Portability :  unportable
--
-- A layout which gives each window a specified amount of screen space
-- relative to the others. Compared to the 'Mosaic' layout, this one
-- divides the space in a more balanced way.
--
-----------------------------------------------------------------------------

module XMonad.Layout.MosaicAlt (
        -- * Usage:
        -- $usage
        MosaicAlt(..)
        , shrinkWindowAlt
        , expandWindowAlt
        , tallWindowAlt
        , wideWindowAlt
        , resetAlt

        , Params, Param
        , HandleWindowAlt
    ) where

import XMonad
import qualified XMonad.StackSet as W
import qualified Data.Map as M
import Data.List ( sortBy )
import Data.Ratio

-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.MosaicAlt
-- > import qualified Data.Map as M
--
-- Then edit your @layoutHook@ by adding the MosaicAlt layout:
--
-- > myLayout = MosaicAlt M.empty ||| Full ||| etc..
-- > main = xmonad def { layoutHook = myLayout }
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
--
-- In the key-bindings, do something like:
--
-- >     , ((modm .|. shiftMask  , xK_a    ), withFocused (sendMessage . expandWindowAlt))
-- >     , ((modm .|. shiftMask  , xK_z    ), withFocused (sendMessage . shrinkWindowAlt))
-- >     , ((modm .|. shiftMask  , xK_s    ), withFocused (sendMessage . tallWindowAlt))
-- >     , ((modm .|. shiftMask  , xK_d    ), withFocused (sendMessage . wideWindowAlt))
-- >     , ((modm .|. controlMask, xK_space), sendMessage resetAlt)
-- >     ...
--
-- For detailed instruction on editing the key binding see:
--
-- "XMonad.Doc.Extending#Editing_key_bindings".

data HandleWindowAlt =
    ShrinkWindowAlt Window
    | ExpandWindowAlt Window
    | TallWindowAlt Window
    | WideWindowAlt Window
    | ResetAlt
    deriving ( Typeable, HandleWindowAlt -> HandleWindowAlt -> Bool
(HandleWindowAlt -> HandleWindowAlt -> Bool)
-> (HandleWindowAlt -> HandleWindowAlt -> Bool)
-> Eq HandleWindowAlt
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: HandleWindowAlt -> HandleWindowAlt -> Bool
$c/= :: HandleWindowAlt -> HandleWindowAlt -> Bool
== :: HandleWindowAlt -> HandleWindowAlt -> Bool
$c== :: HandleWindowAlt -> HandleWindowAlt -> Bool
Eq )
instance Message HandleWindowAlt
shrinkWindowAlt, expandWindowAlt :: Window -> HandleWindowAlt
tallWindowAlt, wideWindowAlt :: Window -> HandleWindowAlt
shrinkWindowAlt :: Window -> HandleWindowAlt
shrinkWindowAlt = Window -> HandleWindowAlt
ShrinkWindowAlt
expandWindowAlt :: Window -> HandleWindowAlt
expandWindowAlt = Window -> HandleWindowAlt
ExpandWindowAlt
tallWindowAlt :: Window -> HandleWindowAlt
tallWindowAlt = Window -> HandleWindowAlt
TallWindowAlt
wideWindowAlt :: Window -> HandleWindowAlt
wideWindowAlt = Window -> HandleWindowAlt
WideWindowAlt
resetAlt :: HandleWindowAlt
resetAlt :: HandleWindowAlt
resetAlt = HandleWindowAlt
ResetAlt

data Param = Param { Param -> Rational
area, Param -> Rational
aspect :: Rational } deriving ( Int -> Param -> ShowS
[Param] -> ShowS
Param -> String
(Int -> Param -> ShowS)
-> (Param -> String) -> ([Param] -> ShowS) -> Show Param
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Param] -> ShowS
$cshowList :: [Param] -> ShowS
show :: Param -> String
$cshow :: Param -> String
showsPrec :: Int -> Param -> ShowS
$cshowsPrec :: Int -> Param -> ShowS
Show, ReadPrec [Param]
ReadPrec Param
Int -> ReadS Param
ReadS [Param]
(Int -> ReadS Param)
-> ReadS [Param]
-> ReadPrec Param
-> ReadPrec [Param]
-> Read Param
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Param]
$creadListPrec :: ReadPrec [Param]
readPrec :: ReadPrec Param
$creadPrec :: ReadPrec Param
readList :: ReadS [Param]
$creadList :: ReadS [Param]
readsPrec :: Int -> ReadS Param
$creadsPrec :: Int -> ReadS Param
Read )
type Params = M.Map Window Param
data MosaicAlt a = MosaicAlt Params deriving ( Int -> MosaicAlt a -> ShowS
[MosaicAlt a] -> ShowS
MosaicAlt a -> String
(Int -> MosaicAlt a -> ShowS)
-> (MosaicAlt a -> String)
-> ([MosaicAlt a] -> ShowS)
-> Show (MosaicAlt a)
forall a. Int -> MosaicAlt a -> ShowS
forall a. [MosaicAlt a] -> ShowS
forall a. MosaicAlt a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [MosaicAlt a] -> ShowS
$cshowList :: forall a. [MosaicAlt a] -> ShowS
show :: MosaicAlt a -> String
$cshow :: forall a. MosaicAlt a -> String
showsPrec :: Int -> MosaicAlt a -> ShowS
$cshowsPrec :: forall a. Int -> MosaicAlt a -> ShowS
Show, ReadPrec [MosaicAlt a]
ReadPrec (MosaicAlt a)
Int -> ReadS (MosaicAlt a)
ReadS [MosaicAlt a]
(Int -> ReadS (MosaicAlt a))
-> ReadS [MosaicAlt a]
-> ReadPrec (MosaicAlt a)
-> ReadPrec [MosaicAlt a]
-> Read (MosaicAlt a)
forall a. ReadPrec [MosaicAlt a]
forall a. ReadPrec (MosaicAlt a)
forall a. Int -> ReadS (MosaicAlt a)
forall a. ReadS [MosaicAlt a]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [MosaicAlt a]
$creadListPrec :: forall a. ReadPrec [MosaicAlt a]
readPrec :: ReadPrec (MosaicAlt a)
$creadPrec :: forall a. ReadPrec (MosaicAlt a)
readList :: ReadS [MosaicAlt a]
$creadList :: forall a. ReadS [MosaicAlt a]
readsPrec :: Int -> ReadS (MosaicAlt a)
$creadsPrec :: forall a. Int -> ReadS (MosaicAlt a)
Read )

instance LayoutClass MosaicAlt Window where
    description :: MosaicAlt Window -> String
description _ = "MosaicAlt"
    doLayout :: MosaicAlt Window
-> Rectangle
-> Stack Window
-> X ([(Window, Rectangle)], Maybe (MosaicAlt Window))
doLayout (MosaicAlt params :: Params
params) rect :: Rectangle
rect stack :: Stack Window
stack =
            ([(Window, Rectangle)], Maybe (MosaicAlt Window))
-> X ([(Window, Rectangle)], Maybe (MosaicAlt Window))
forall (m :: * -> *) a. Monad m => a -> m a
return (Rectangle -> Stack Window -> Params -> [(Window, Rectangle)]
arrange Rectangle
rect Stack Window
stack Params
params', MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a. a -> Maybe a
Just (MosaicAlt Window -> Maybe (MosaicAlt Window))
-> MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a b. (a -> b) -> a -> b
$ Params -> MosaicAlt Window
forall a. Params -> MosaicAlt a
MosaicAlt Params
params')
        where
            params' :: Params
params' = [Window] -> Params -> Params
forall k. Ord k => [k] -> Map k Param -> Map k Param
ins (Stack Window -> [Window]
forall a. Stack a -> [a]
W.up Stack Window
stack) (Params -> Params) -> Params -> Params
forall a b. (a -> b) -> a -> b
$ [Window] -> Params -> Params
forall k. Ord k => [k] -> Map k Param -> Map k Param
ins (Stack Window -> [Window]
forall a. Stack a -> [a]
W.down Stack Window
stack) (Params -> Params) -> Params -> Params
forall a b. (a -> b) -> a -> b
$ [Window] -> Params -> Params
forall k. Ord k => [k] -> Map k Param -> Map k Param
ins [Stack Window -> Window
forall a. Stack a -> a
W.focus Stack Window
stack] Params
params
            ins :: [k] -> Map k Param -> Map k Param
ins wins :: [k]
wins as :: Map k Param
as = (Map k Param -> Map k Param -> Map k Param)
-> Map k Param -> [Map k Param] -> Map k Param
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Map k Param -> Map k Param -> Map k Param
forall k a. Ord k => Map k a -> Map k a -> Map k a
M.union Map k Param
as ([Map k Param] -> Map k Param) -> [Map k Param] -> Map k Param
forall a b. (a -> b) -> a -> b
$ (k -> Map k Param) -> [k] -> [Map k Param]
forall a b. (a -> b) -> [a] -> [b]
map (k -> Param -> Map k Param
forall k a. k -> a -> Map k a
`M.singleton` (Rational -> Rational -> Param
Param 1 1.5)) [k]
wins

    handleMessage :: MosaicAlt Window -> SomeMessage -> X (Maybe (MosaicAlt Window))
handleMessage (MosaicAlt params :: Params
params) msg :: SomeMessage
msg = Maybe (MosaicAlt Window) -> X (Maybe (MosaicAlt Window))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (MosaicAlt Window) -> X (Maybe (MosaicAlt Window)))
-> Maybe (MosaicAlt Window) -> X (Maybe (MosaicAlt Window))
forall a b. (a -> b) -> a -> b
$ case SomeMessage -> Maybe HandleWindowAlt
forall m. Message m => SomeMessage -> Maybe m
fromMessage SomeMessage
msg of
        Just (ShrinkWindowAlt w :: Window
w) -> MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a. a -> Maybe a
Just (MosaicAlt Window -> Maybe (MosaicAlt Window))
-> MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a b. (a -> b) -> a -> b
$ Params -> MosaicAlt Window
forall a. Params -> MosaicAlt a
MosaicAlt (Params -> MosaicAlt Window) -> Params -> MosaicAlt Window
forall a b. (a -> b) -> a -> b
$ Params -> Window -> Rational -> Rational -> Params
alter Params
params Window
w (4 Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% 5) 1
        Just (ExpandWindowAlt w :: Window
w) -> MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a. a -> Maybe a
Just (MosaicAlt Window -> Maybe (MosaicAlt Window))
-> MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a b. (a -> b) -> a -> b
$ Params -> MosaicAlt Window
forall a. Params -> MosaicAlt a
MosaicAlt (Params -> MosaicAlt Window) -> Params -> MosaicAlt Window
forall a b. (a -> b) -> a -> b
$ Params -> Window -> Rational -> Rational -> Params
alter Params
params Window
w (6 Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% 5) 1
        Just (TallWindowAlt w :: Window
w) -> MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a. a -> Maybe a
Just (MosaicAlt Window -> Maybe (MosaicAlt Window))
-> MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a b. (a -> b) -> a -> b
$ Params -> MosaicAlt Window
forall a. Params -> MosaicAlt a
MosaicAlt (Params -> MosaicAlt Window) -> Params -> MosaicAlt Window
forall a b. (a -> b) -> a -> b
$ Params -> Window -> Rational -> Rational -> Params
alter Params
params Window
w 1 (3 Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% 4)
        Just (WideWindowAlt w :: Window
w) -> MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a. a -> Maybe a
Just (MosaicAlt Window -> Maybe (MosaicAlt Window))
-> MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a b. (a -> b) -> a -> b
$ Params -> MosaicAlt Window
forall a. Params -> MosaicAlt a
MosaicAlt (Params -> MosaicAlt Window) -> Params -> MosaicAlt Window
forall a b. (a -> b) -> a -> b
$ Params -> Window -> Rational -> Rational -> Params
alter Params
params Window
w 1 (5 Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% 4)
        Just ResetAlt -> MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a. a -> Maybe a
Just (MosaicAlt Window -> Maybe (MosaicAlt Window))
-> MosaicAlt Window -> Maybe (MosaicAlt Window)
forall a b. (a -> b) -> a -> b
$ Params -> MosaicAlt Window
forall a. Params -> MosaicAlt a
MosaicAlt Params
forall k a. Map k a
M.empty
        _ -> Maybe (MosaicAlt Window)
forall a. Maybe a
Nothing

-- Change requested params for a window.
alter :: Params -> Window -> Rational -> Rational -> Params
alter :: Params -> Window -> Rational -> Rational -> Params
alter params :: Params
params win :: Window
win arDelta :: Rational
arDelta asDelta :: Rational
asDelta = case Window -> Params -> Maybe Param
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Window
win Params
params of
    Just (Param ar :: Rational
ar as :: Rational
as) -> Window -> Param -> Params -> Params
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Window
win (Rational -> Rational -> Param
Param (Rational
ar Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Rational
arDelta) (Rational
as Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Rational
asDelta)) Params
params
    Nothing -> Window -> Param -> Params -> Params
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Window
win (Rational -> Rational -> Param
Param Rational
arDelta (1.5 Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Rational
asDelta)) Params
params

-- Layout algorithm entry point.
arrange :: Rectangle -> W.Stack Window -> Params -> [(Window, Rectangle)]
arrange :: Rectangle -> Stack Window -> Params -> [(Window, Rectangle)]
arrange rect :: Rectangle
rect stack :: Stack Window
stack params :: Params
params = [(Window, Rectangle)]
r
    where
        (_, r :: [(Window, Rectangle)]
r) = Int
-> Rectangle -> Tree -> Params -> (Double, [(Window, Rectangle)])
findSplits 3 Rectangle
rect Tree
tree Params
params
        tree :: Tree
tree = [Window] -> Params -> Tree
makeTree ((Window -> Window -> Ordering) -> [Window] -> [Window]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy Window -> Window -> Ordering
areaCompare [Window]
wins) Params
params
        wins :: [Window]
wins = [Window] -> [Window]
forall a. [a] -> [a]
reverse (Stack Window -> [Window]
forall a. Stack a -> [a]
W.up Stack Window
stack) [Window] -> [Window] -> [Window]
forall a. [a] -> [a] -> [a]
++ Stack Window -> Window
forall a. Stack a -> a
W.focus Stack Window
stack Window -> [Window] -> [Window]
forall a. a -> [a] -> [a]
: Stack Window -> [Window]
forall a. Stack a -> [a]
W.down Stack Window
stack
        areaCompare :: Window -> Window -> Ordering
areaCompare a :: Window
a b :: Window
b = Window -> Rational
or1 Window
b Rational -> Rational -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` Window -> Rational
or1 Window
a
        or1 :: Window -> Rational
or1 w :: Window
w = Rational -> (Param -> Rational) -> Maybe Param -> Rational
forall b a. b -> (a -> b) -> Maybe a -> b
maybe 1 Param -> Rational
area (Maybe Param -> Rational) -> Maybe Param -> Rational
forall a b. (a -> b) -> a -> b
$ Window -> Params -> Maybe Param
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Window
w Params
params

-- Recursively group windows into a binary tree. Aim to balance the tree
-- according to the total requested area in each branch.
data Tree = Node (Rational, Tree) (Rational, Tree) | Leaf Window | None
makeTree :: [Window] -> Params -> Tree
makeTree :: [Window] -> Params -> Tree
makeTree wins :: [Window]
wins params :: Params
params = case [Window]
wins of
    [] -> Tree
None
    [x :: Window
x] -> Window -> Tree
Leaf Window
x
    _ -> (Rational, Tree) -> (Rational, Tree) -> Tree
Node (Rational
aArea, [Window] -> Params -> Tree
makeTree [Window]
aWins Params
params) (Rational
bArea, [Window] -> Params -> Tree
makeTree [Window]
bWins Params
params)
        where ((aWins :: [Window]
aWins, aArea :: Rational
aArea), (bWins :: [Window]
bWins, bArea :: Rational
bArea)) = Params -> [Window] -> (([Window], Rational), ([Window], Rational))
areaSplit Params
params [Window]
wins

-- Split a list of windows in half by area.
areaSplit :: Params -> [Window] -> (([Window], Rational), ([Window], Rational))
areaSplit :: Params -> [Window] -> (([Window], Rational), ([Window], Rational))
areaSplit params :: Params
params wins :: [Window]
wins = [Window]
-> Rational
-> [Window]
-> Rational
-> [Window]
-> (([Window], Rational), ([Window], Rational))
gather [] 0 [] 0 [Window]
wins
    where
        gather :: [Window]
-> Rational
-> [Window]
-> Rational
-> [Window]
-> (([Window], Rational), ([Window], Rational))
gather a :: [Window]
a aa :: Rational
aa b :: [Window]
b ba :: Rational
ba (r :: Window
r : rs :: [Window]
rs) =
            if Rational
aa Rational -> Rational -> Bool
forall a. Ord a => a -> a -> Bool
<= Rational
ba
                then [Window]
-> Rational
-> [Window]
-> Rational
-> [Window]
-> (([Window], Rational), ([Window], Rational))
gather (Window
r Window -> [Window] -> [Window]
forall a. a -> [a] -> [a]
: [Window]
a) (Rational
aa Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Window -> Rational
or1 Window
r) [Window]
b Rational
ba [Window]
rs
                else [Window]
-> Rational
-> [Window]
-> Rational
-> [Window]
-> (([Window], Rational), ([Window], Rational))
gather [Window]
a Rational
aa (Window
r Window -> [Window] -> [Window]
forall a. a -> [a] -> [a]
: [Window]
b) (Rational
ba Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Window -> Rational
or1 Window
r) [Window]
rs
        gather a :: [Window]
a aa :: Rational
aa b :: [Window]
b ba :: Rational
ba [] = (([Window] -> [Window]
forall a. [a] -> [a]
reverse [Window]
a, Rational
aa), ([Window]
b, Rational
ba))
        or1 :: Window -> Rational
or1 w :: Window
w = Rational -> (Param -> Rational) -> Maybe Param -> Rational
forall b a. b -> (a -> b) -> Maybe a -> b
maybe 1 Param -> Rational
area (Maybe Param -> Rational) -> Maybe Param -> Rational
forall a b. (a -> b) -> a -> b
$ Window -> Params -> Maybe Param
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Window
w Params
params

-- Figure out which ways to split the space, by exhaustive search.
-- Complexity is quadratic in the number of windows.
findSplits :: Int -> Rectangle -> Tree -> Params -> (Double, [(Window, Rectangle)])
findSplits :: Int
-> Rectangle -> Tree -> Params -> (Double, [(Window, Rectangle)])
findSplits _ _ None _ = (0, [])
findSplits _ rect :: Rectangle
rect (Leaf w :: Window
w) params :: Params
params = (Rectangle -> Window -> Params -> Double
aspectBadness Rectangle
rect Window
w Params
params, [(Window
w, Rectangle
rect)])
findSplits depth :: Int
depth rect :: Rectangle
rect (Node (aArea :: Rational
aArea, aTree :: Tree
aTree) (bArea :: Rational
bArea, bTree :: Tree
bTree)) params :: Params
params =
        if Double
hBadness Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
vBadness then (Double
hBadness, [(Window, Rectangle)]
hList) else (Double
vBadness, [(Window, Rectangle)]
vList)
    where
        (hBadness :: Double
hBadness, hList :: [(Window, Rectangle)]
hList) = (Rational -> Rectangle -> (Rectangle, Rectangle))
-> (Double, [(Window, Rectangle)])
trySplit Rational -> Rectangle -> (Rectangle, Rectangle)
forall r. RealFrac r => r -> Rectangle -> (Rectangle, Rectangle)
splitHorizontallyBy
        (vBadness :: Double
vBadness, vList :: [(Window, Rectangle)]
vList) = (Rational -> Rectangle -> (Rectangle, Rectangle))
-> (Double, [(Window, Rectangle)])
trySplit Rational -> Rectangle -> (Rectangle, Rectangle)
forall r. RealFrac r => r -> Rectangle -> (Rectangle, Rectangle)
splitVerticallyBy
        trySplit :: (Rational -> Rectangle -> (Rectangle, Rectangle))
-> (Double, [(Window, Rectangle)])
trySplit splitBy :: Rational -> Rectangle -> (Rectangle, Rectangle)
splitBy =
                (Double
aBadness Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
bBadness, [(Window, Rectangle)]
aList [(Window, Rectangle)]
-> [(Window, Rectangle)] -> [(Window, Rectangle)]
forall a. [a] -> [a] -> [a]
++ [(Window, Rectangle)]
bList)
            where
                (aBadness :: Double
aBadness, aList :: [(Window, Rectangle)]
aList) = Int
-> Rectangle -> Tree -> Params -> (Double, [(Window, Rectangle)])
findSplits (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1) Rectangle
aRect Tree
aTree Params
params
                (bBadness :: Double
bBadness, bList :: [(Window, Rectangle)]
bList) = Int
-> Rectangle -> Tree -> Params -> (Double, [(Window, Rectangle)])
findSplits (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1) Rectangle
bRect Tree
bTree Params
params
                (aRect :: Rectangle
aRect, bRect :: Rectangle
bRect) = Rational -> Rectangle -> (Rectangle, Rectangle)
splitBy Rational
ratio Rectangle
rect
        ratio :: Rational
ratio = Rational
aArea Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ (Rational
aArea Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Rational
bArea)

-- Decide how much we like this rectangle.
aspectBadness :: Rectangle -> Window -> Params -> Double
aspectBadness :: Rectangle -> Window -> Params -> Double
aspectBadness rect :: Rectangle
rect win :: Window
win params :: Params
params =
        (if Double
a Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< 1 then Double
tall else Double
wide) Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double -> Double
forall a. Floating a => a -> a
sqrt(Double
w Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
h)
    where
        tall :: Double
tall = if Double
w Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< 700 then ((1 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
a) Double -> Double -> Double
forall a. Num a => a -> a -> a
* (700 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
w)) else 1 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
a
        wide :: Double
wide = if Double
w Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< 700 then Double
a else (Double
a Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
w Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ 700)
        a :: Double
a = (Double
w Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
h) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Rational -> Double
forall a. Fractional a => Rational -> a
fromRational (Rational -> (Param -> Rational) -> Maybe Param -> Rational
forall b a. b -> (a -> b) -> Maybe a -> b
maybe 1.5 Param -> Rational
aspect (Maybe Param -> Rational) -> Maybe Param -> Rational
forall a b. (a -> b) -> a -> b
$ Window -> Params -> Maybe Param
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Window
win Params
params)
        w :: Double
w = Window -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Window -> Double) -> Window -> Double
forall a b. (a -> b) -> a -> b
$ Rectangle -> Window
rect_width Rectangle
rect
        h :: Double
h = Window -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Window -> Double) -> Window -> Double
forall a b. (a -> b) -> a -> b
$ Rectangle -> Window
rect_height Rectangle
rect

-- vim: sw=4:et