]> 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:

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