aboutsummaryrefslogtreecommitdiffstats
path: root/DragPane.hs
blob: 8207be8844b57f3912caf766944d9fad101a537e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
-----------------------------------------------------------------------------
-- |
-- Module      :  XMonadContrib.DragPane
-- Copyright   :  (c) Spencer Janssen <sjanssen@cse.unl.edu>
--                    David Roundy <droundy@darcs.net>,
-- License     :  BSD3-style (see LICENSE)
-- 
-- Maintainer  :  David Roundy <droundy@darcs.net>
-- Stability   :  unstable
-- Portability :  unportable
--
-- Layouts that splits the screen either horizontally or vertically and
-- shows two windows.  The first window is always the master window, and
-- the other is either the currently focused window or the second window in
-- layout order.

-----------------------------------------------------------------------------

module XMonadContrib.DragPane (
                               -- * Usage
                               -- $usage
                               dragPane, dragUpDownPane
                              ) where

import Control.Monad.Reader ( asks )
import Graphics.X11.Xlib ( Rectangle( Rectangle ) )
import XMonad
import XMonadContrib.Decoration ( newDecoration )
import Operations ( Resize(..), splitHorizontallyBy, splitVerticallyBy, initColor, mouseDrag, sendMessage )
import StackSet ( focus, up, down)

-- $usage
--
-- You can use this module with the following in your Config.hs file:
--
-- > import XMonadContrib.DragPane
--
--  and add, to the list of layouts:
--
-- > dragPane "" (fromRational delta) (fromRational delta)

halfHandleWidth :: Integral a => a
halfHandleWidth = 2

handleColor :: String
handleColor = "#000000"

dragPane :: String -> Double -> Double -> Layout a
dragPane ident delta split = Layout { doLayout = dolay, modifyLayout = return . message }
 where
    dolay r s = do handlec <- withDisplay $ \dpy -> io $ initColor dpy handleColor
                   root <- asks theRoot
                   let (left', right') = splitHorizontallyBy split r
                       leftmost = fromIntegral $ case r of Rectangle x _ _ _ -> x
                       widt = fromIntegral $ case r of Rectangle _ _ w _ -> w
                       left = case left' of Rectangle x y w h -> Rectangle x y (w-halfHandleWidth) h
                       right = case right' of
                               Rectangle x y w h -> Rectangle (x+halfHandleWidth) y (w-halfHandleWidth) h
                       handr = case left' of
                               Rectangle x y w h ->
                                 Rectangle (x + fromIntegral w - halfHandleWidth) y (2*halfHandleWidth) h
                       wrs = case reverse (up s) of
                             (master:_) -> [(master,left),(focus s,right)]
                             [] -> case down s of
                                   (next:_) -> [(focus s,left),(next,right)]
                                   [] -> [(focus s, r)]
                       handle = newDecoration root handr 0 handlec handlec
                                "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
                                (const $ const $ const $ const $ return ()) (doclick)
                       doclick = mouseDrag (\ex _ ->
                                        sendMessage (SetFrac ident ((fromIntegral ex - leftmost)/widt)))
                                        (return ())
                                        
                   ml' <- if length wrs > 1 then Just `fmap` handle (dragPane ident delta split)
                                            else return Nothing
                   return (wrs, ml')
    message x | Just Shrink <- fromMessage x = Just (dragPane ident delta (split - delta))
              | Just Expand <- fromMessage x = Just (dragPane ident delta (split + delta))
              | Just (SetFrac ident' frac) <- fromMessage x, ident' == ident =
                                              Just (dragPane ident delta frac)
    message _ = Nothing

dragUpDownPane :: String -> Double -> Double -> Layout a
dragUpDownPane ident delta split = Layout { doLayout = dolay, modifyLayout = return . message }
 where
    dolay r s = do handlec <- withDisplay $ \dpy -> io $ initColor dpy handleColor
                   root <- asks theRoot
                   let (left', right') = splitVerticallyBy split r
                       leftmost = fromIntegral $ case r of Rectangle _ x _ _ -> x
                       widt = fromIntegral $ case r of Rectangle _ _ _ w -> w
                       left = case left' of Rectangle x y w h -> Rectangle x y w (h-halfHandleWidth)
                       right = case right' of
                               Rectangle x y w h -> Rectangle x (y+halfHandleWidth) w (h-halfHandleWidth)
                       handr = case left' of
                               Rectangle x y w h ->
                                 Rectangle x (y + fromIntegral h - halfHandleWidth) w (2*halfHandleWidth)
                       wrs = case reverse (up s) of
                             (master:_) -> [(master,left),(focus s,right)]
                             [] -> case down s of
                                   (next:_) -> [(focus s,left),(next,right)]
                                   [] -> [(focus s, r)]
                       handle = newDecoration root handr 0 handlec handlec
                                "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
                                (const $ const $ const $ const $ return ()) (doclick)
                       doclick = mouseDrag (\_ ey ->
                                        sendMessage (SetFrac ident ((fromIntegral ey - leftmost)/widt)))
                                        (return ())
                                        
                   ml' <- if length wrs > 1 then Just `fmap` handle (dragUpDownPane ident delta split)
                                            else return Nothing
                   return (wrs, ml')
    message x | Just Shrink <- fromMessage x = Just (dragUpDownPane ident delta (split - delta))
              | Just Expand <- fromMessage x = Just (dragUpDownPane ident delta (split + delta))
              | Just (SetFrac ident' frac) <- fromMessage x, ident' == ident =
                                              Just (dragUpDownPane ident delta frac)
    message _ = Nothing

data SetFrac = SetFrac String Double deriving ( Show, Read, Eq, Typeable )
instance Message SetFrac