summaryrefslogtreecommitdiff
path: root/lain/layout/centerfair.lua
blob: 1e8915d0c494c178af3b7ab6e9926f33a5cf5db5 (plain)
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

--[[
                                                 
     Licensed under GNU General Public License v2
      * (c) 2014,      projektile                
      * (c) 2013,      Luke Bonham               
      * (c) 2010,      Nicolas Estibals          
      * (c) 2010-2012, Peter Hofmann             
                                                 
--]]

local tag       = require("awful.tag")
local beautiful = require("beautiful")
local math      = { ceil  = math.ceil,
                    floor = math.floor,
                    max   = math.max }
local tonumber  = tonumber

local centerfair  = { name = "centerfair" }

function centerfair.arrange(p)
    -- Layout with fixed number of vertical columns (read from nmaster).
    -- Cols are centerded until there is nmaster columns, then windows
    -- are stacked in the slave columns, with at most ncol clients per
    -- column if possible.

    -- with nmaster=3 and ncol=1 you'll have
    --        (1)                (2)                (3)
    --   +---+---+---+      +-+---+---+-+      +---+---+---+
    --   |   |   |   |      | |   |   | |      |   |   |   |
    --   |   | 1 |   |  ->  | | 1 | 2 | | ->   | 1 | 2 | 3 |  ->
    --   |   |   |   |      | |   |   | |      |   |   |   |
    --   +---+---+---+      +-+---+---+-+      +---+---+---+

    --        (4)                (5)
    --   +---+---+---+      +---+---+---+
    --   |   |   | 3 |      |   | 2 | 4 |
    --   + 1 + 2 +---+  ->  + 1 +---+---+
    --   |   |   | 4 |      |   | 3 | 5 |
    --   +---+---+---+      +---+---+---+

    -- A useless gap (like the dwm patch) can be defined with
    -- beautiful.useless_gap_width .
    local useless_gap = tonumber(beautiful.useless_gap_width) or 0
    if useless_gap < 0 then useless_gap = 0 end

    -- A global border can be defined with
    -- beautiful.global_border_width
    local global_border = tonumber(beautiful.global_border_width) or 0
    if global_border < 0 then global_border = 0 end

    -- Themes border width requires an offset
    local bw = tonumber(beautiful.border_width) or 0

    -- Screen.
    local wa = p.workarea
    local cls = p.clients

    -- Borders are factored in.
    wa.height = wa.height - ((global_border * 2) + (bw * 2))
    wa.width = wa.width - ((global_border * 2) + (bw * 2))

    -- How many vertical columns? Read from nmaster on the tag.
    local t = tag.selected(p.screen)
    local num_x = centerfair.nmaster or tag.getnmaster(t)
    local ncol = centerfair.ncol or tag.getncol(t)
    if num_x <= 2 then num_x = 2 end

    local width = math.floor((wa.width-(num_x+1)*useless_gap) / num_x)

    local offset_y = wa.y + useless_gap
    if #cls < num_x
    then
        -- Less clients than the number of columns, let's center it!
        local offset_x = wa.x + useless_gap + (wa.width - #cls*width - (#cls+1)*useless_gap) / 2
        local g = {}
        g.width = width
        g.height = wa.height - 2*useless_gap - 2
        g.y = offset_y + global_border
        for i = 1, #cls do
            g.x = offset_x + (#cls - i) * (width + useless_gap + 2) + global_border
            cls[i]:geometry(g)
        end
    else
        -- More clients than the number of columns, let's arrange it!
        local offset_x = wa.x
        if useless_gap > 0 then
           offset_x = offset_x
        end

        -- Master client deserves a special treatement
        local g = {}
        g.width = wa.width - (num_x  - 1) * width - num_x * 2*useless_gap - 2
        g.height = wa.height - 2*useless_gap - 2
        g.x = offset_x + useless_gap + global_border
        g.y = offset_y + global_border

        cls[#cls]:geometry(g)

        -- Treat the other clients

        -- Compute distribution of clients among columns
        local num_y ={}
        do
            local remaining_clients = #cls-1
            local ncol_min = math.ceil(remaining_clients/(num_x-1))
            if ncol >= ncol_min
            then
                for i = (num_x-1), 1, -1 do
                    if (remaining_clients-i+1) < ncol
                    then
                        num_y[i] = remaining_clients-i + 1
                    else
                        num_y[i] = ncol
                    end
                    remaining_clients = remaining_clients - num_y[i]
                end
            else
                local rem = remaining_clients % (num_x-1)
                if rem ==0
                then
                    for i = 1, num_x-1 do
                        num_y[i] = ncol_min
                    end
                else
                    for i = 1, num_x-1 do
                        num_y[i] = ncol_min - 1
                    end
                    for i = 0, rem-1 do
                        num_y[num_x-1-i] = num_y[num_x-1-i] + 1
                    end
                end
            end
        end

        -- Compute geometry of the other clients
        local nclient = #cls-1 -- we start with the 2nd client
        g.x = g.x + g.width+useless_gap + 2
        g.width = width

        if useless_gap > 0 then
            g.width = g.width + useless_gap - 2
        end

        for i = 1, (num_x-1) do
            to_remove = 2
            g.height = math.floor((wa.height - (num_y[i] * useless_gap)) / num_y[i])
            g.y = offset_y + global_border
            for j = 0, (num_y[i]-2) do
                cls[nclient]:geometry(g)
                nclient = nclient - 1
                g.y = g.y + g.height+useless_gap + 2
                to_remove = to_remove + 2
            end
            g.height = wa.height - num_y[i]*useless_gap - (num_y[i]-1)*g.height - useless_gap - to_remove
            cls[nclient]:geometry(g)
            nclient = nclient - 1
            g.x = g.x+g.width+useless_gap + 2
        end
    end
end

return centerfair