]> git.madduck.net Git - etc/awesome.git/blob - layout/termfair.lua

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Fix bugs with v4 API update
[etc/awesome.git] / layout / termfair.lua
1
2 --[[
3                                                   
4      Licensed under GNU General Public License v2 
5       * (c) 2014,      projektile                 
6       * (c) 2013,      Luke Bonham                
7       * (c) 2010,      Nicolas Estibals           
8       * (c) 2010-2012, Peter Hofmann              
9                                                   
10 --]]
11
12 local scr      = require("awful.screen")
13 local math     = { ceil  = math.ceil,
14                    floor = math.floor,
15                    max   = math.max }
16 local tonumber = tonumber
17
18 local termfair  = { name = "termfair" }
19 termfair.center = { name = "centerfair" }
20
21 local function do_fair(p, orientation)
22     -- Screen.
23     local wa  = p.workarea
24     local cls = p.clients
25     local ta = scr.focused().selected_tag
26
27     if not ta then return end
28
29     if #cls <= 0 then return end
30
31     -- Useless gaps.
32     local useless_gap = p.useless_gap or 0
33
34     if orientation == "west" then
35         -- Layout with fixed number of vertical columns (read from nmaster).
36         -- New windows align from left to right. When a row is full, a now
37         -- one above it is created. Like this:
38
39         --        (1)                (2)                (3)
40         --   +---+---+---+      +---+---+---+      +---+---+---+
41         --   |   |   |   |      |   |   |   |      |   |   |   |
42         --   | 1 |   |   |  ->  | 2 | 1 |   |  ->  | 3 | 2 | 1 |  ->
43         --   |   |   |   |      |   |   |   |      |   |   |   |
44         --   +---+---+---+      +---+---+---+      +---+---+---+
45
46         --        (4)                (5)                (6)
47         --   +---+---+---+      +---+---+---+      +---+---+---+
48         --   | 4 |   |   |      | 5 | 4 |   |      | 6 | 5 | 4 |
49         --   +---+---+---+  ->  +---+---+---+  ->  +---+---+---+
50         --   | 3 | 2 | 1 |      | 3 | 2 | 1 |      | 3 | 2 | 1 |
51         --   +---+---+---+      +---+---+---+      +---+---+---+
52
53         if #cls <= 0 then return end
54
55         -- How many vertical columns? Read from nmaster on the tag.
56         local num_x = tonumber(termfair.nmaster) or ta.master_count
57         local ncol  = tonumber(termfair.ncol) or ta.column_count
58
59         if num_x <= 2 then num_x = 2 end
60         if ncol  <= 1 then ncol  = 1 end
61         local width = math.floor((wa.width - (num_x + 1)*useless_gap) / num_x)
62
63         local num_y     = math.max(math.ceil(#cls / num_x), ncol)
64         local height    = math.floor((wa.height - (num_y + 1)*useless_gap) / num_y)
65         local cur_num_x = num_x
66         local at_x      = 0
67         local at_y      = 0
68
69         local remaining_clients = #cls
70
71         -- We start the first row. Left-align by limiting the number of
72         -- available slots.
73         if remaining_clients < num_x then
74             cur_num_x = remaining_clients
75         end
76
77         -- Iterate in reversed order.
78         for i = #cls,1,-1 do
79             -- Get x and y position.
80             local c = cls[i]
81             local this_x = cur_num_x - at_x - 1
82             local this_y = num_y - at_y - 1
83
84             -- Calculate geometry.
85             local g = {}
86             if this_x == (num_x - 1) then
87                 g.width = wa.width - (num_x - 1)*width - (num_x + 1)*useless_gap - 2*c.border_width
88             else
89                 g.width = width - 2*c.border_width
90             end
91
92             if this_y == (num_y - 1) then
93                 g.height = wa.height - (num_y - 1)*height - (num_y + 1)*useless_gap - 2*c.border_width
94             else
95                 g.height = height - 2*c.border_width
96             end
97
98             g.x = wa.x + this_x*width
99             g.y = wa.y + this_y*height
100
101             if useless_gap > 0 then
102                 -- All clients tile evenly.
103                 g.x = g.x + (this_x + 1)*useless_gap
104                 g.y = g.y + (this_y + 1)*useless_gap
105             end
106
107             if g.width < 1 then g.width = 1 end
108             if g.height < 1 then g.height = 1 end
109
110             c:geometry(g)
111
112             remaining_clients = remaining_clients - 1
113
114             -- Next grid position.
115             at_x = at_x + 1
116             if at_x == num_x then
117                 -- Row full, create a new one above it.
118                 at_x = 0
119                 at_y = at_y + 1
120
121                 -- We start a new row. Left-align.
122                 if remaining_clients < num_x then
123                     cur_num_x = remaining_clients
124                 end
125             end
126         end
127     elseif orientation == "center" then
128         -- Layout with fixed number of vertical columns (read from nmaster).
129         -- Cols are centerded until there is nmaster columns, then windows
130         -- are stacked in the slave columns, with at most ncol clients per
131         -- column if possible.
132
133         -- with nmaster=3 and ncol=1 you'll have
134         --        (1)                (2)                (3)
135         --   +---+---+---+      +-+---+---+-+      +---+---+---+
136         --   |   |   |   |      | |   |   | |      |   |   |   |
137         --   |   | 1 |   |  ->  | | 1 | 2 | | ->   | 1 | 2 | 3 |  ->
138         --   |   |   |   |      | |   |   | |      |   |   |   |
139         --   +---+---+---+      +-+---+---+-+      +---+---+---+
140
141         --        (4)                (5)
142         --   +---+---+---+      +---+---+---+
143         --   |   |   | 3 |      |   | 2 | 4 |
144         --   + 1 + 2 +---+  ->  + 1 +---+---+
145         --   |   |   | 4 |      |   | 3 | 5 |
146         --   +---+---+---+      +---+---+---+
147
148         -- How many vertical columns? Read from nmaster on the tag.
149         local num_x = tonumber(termfair.center.nmaster) or ta.master_count
150         local ncol  = tonumber(termfair.center.ncol) or ta.column_count
151
152         if num_x <= 2 then num_x = 2 end
153         if ncol  <= 1 then ncol  = 1 end
154
155         local width = math.floor((wa.width - (num_x + 1)*useless_gap) / num_x)
156
157         if #cls < num_x then
158             -- Less clients than the number of columns, let's center it!
159             local offset_x = wa.x + (wa.width - #cls*width - (#cls - 1)*useless_gap) / 2
160             local g = {}
161             g.y = wa.y + useless_gap
162             for i = 1, #cls do
163                 local c = cls[i]
164                 g.width = width - 2*c.border_width
165                 g.height = wa.height - 2*useless_gap - 2*c.border_width
166                 if g.width < 1 then g.width = 1 end
167                 if g.height < 1 then g.height = 1 end
168                 g.x = offset_x + (i - 1) * (width + useless_gap)
169                 c:geometry(g)
170             end
171         else
172             -- More clients than the number of columns, let's arrange it!
173             -- Master client deserves a special treatement
174             local c = cls[1]
175             local g = {}
176             g.width = wa.width - (num_x - 1)*width - (num_x + 1)*useless_gap - 2*c.border_width
177             g.height = wa.height - 2*useless_gap - 2*c.border_width
178             if g.width < 1 then g.width = 1 end
179             if g.height < 1 then g.height = 1 end
180             g.x = wa.x + useless_gap
181             g.y = wa.y + useless_gap
182
183             c:geometry(g)
184
185             -- Treat the other clients
186
187             -- Compute distribution of clients among columns
188             local num_y ={}
189             do
190                 local remaining_clients = #cls-1
191                 local ncol_min = math.ceil(remaining_clients/(num_x-1))
192                 if ncol >= ncol_min then
193                     for i = (num_x-1), 1, -1 do
194                         if (remaining_clients-i+1) < ncol then
195                             num_y[i] = remaining_clients-i + 1
196                         else
197                             num_y[i] = ncol
198                         end
199                         remaining_clients = remaining_clients - num_y[i]
200                     end
201                 else
202                     local rem = remaining_clients % (num_x-1)
203                     if rem == 0 then
204                         for i = 1, num_x-1 do
205                             num_y[i] = ncol_min
206                         end
207                     else
208                         for i = 1, num_x-1 do
209                             num_y[i] = ncol_min - 1
210                         end
211                         for i = 0, rem-1 do
212                             num_y[num_x-1-i] = num_y[num_x-1-i] + 1
213                         end
214                     end
215                 end
216             end
217
218             -- Compute geometry of the other clients
219             local nclient = 2 -- we start with the 2nd client
220             g.x = g.x + g.width + useless_gap + 2*c.border_width
221
222             for i = 1, (num_x-1) do
223                 local height = math.floor((wa.height - (num_y[i] + 1)*useless_gap) / num_y[i])
224                 g.y = wa.y + useless_gap
225                 for j = 0, (num_y[i]-2) do
226                     local c = cls[nclient]
227                     g.height = height - 2*c.border_width
228                     g.width = width - 2*c.border_width
229                     if g.width < 1 then g.width = 1 end
230                     if g.height < 1 then g.height = 1 end
231                     c:geometry(g)
232                     nclient = nclient + 1
233                     g.y = g.y + height + useless_gap
234                 end
235                 local c = cls[nclient]
236                 g.height = wa.height - (num_y[i] + 1)*useless_gap - (num_y[i] - 1)*height - 2*c.border_width
237                 g.width = width - 2*c.border_width
238                 if g.width < 1 then g.width = 1 end
239                 if g.height < 1 then g.height = 1 end
240                 c:geometry(g)
241                 nclient = nclient + 1
242                 g.x = g.x + width + useless_gap
243             end
244         end
245     end
246 end
247
248 function termfair.center.arrange(p)
249     return do_fair(p, "center")
250 end
251
252 function termfair.arrange(p)
253     return do_fair(p, "west")
254 end
255
256 return termfair