]> git.madduck.net Git - etc/awesome.git/blob - layout/uselesstile.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:

#139 proposed fix
[etc/awesome.git] / layout / uselesstile.lua
1
2 --[[
3                                                   
4      Licensed under GNU General Public License v2 
5       * (c) 2014, projektile, worron              
6       * (c) 2013, Luke Bonham                     
7       * (c) 2009, Donald Ephraim Curtis           
8       * (c) 2008, Julien Danjolu                  
9                                                   
10 --]]
11
12 local tag       = require("awful.tag")
13 local beautiful = require("beautiful")
14 local ipairs    = ipairs
15 local math      = { floor = math.floor,
16                     ceil  = math.ceil,
17                     max   = math.max,
18                     min   = math.min }
19 local tonumber  = tonumber
20
21 local uselesstile = {}
22
23 -- Transformation functions
24 local function flip(canvas, geometry)
25     return {
26         -- vertical only
27         x = 2 * canvas.x + canvas.width - geometry.x - geometry.width,
28         y = geometry.y,
29         width = geometry.width,
30         height = geometry.height
31     }
32 end
33
34 local function swap(geometry)
35     return { x = geometry.y, y = geometry.x, width = geometry.height, height = geometry.width }
36 end
37
38 -- Find geometry for secondary windows column
39 local function cut_column(wa, n, index)
40     local width = math.floor(wa.width / n)
41     local area = { x = wa.x + (index - 1) * width, y = wa.y, width = width, height = wa.height }
42
43     return area
44 end
45
46 -- Find geometry for certain window in column
47 local function cut_row(wa, factor, index, used)
48     local height = math.floor(wa.height * factor.window[index] / factor.total)
49     local area = { x = wa.x, y = wa.y + used, width = wa.width, height = height }
50
51     return area
52 end
53
54 -- Client geometry correction depending on useless gap and window border
55 local function size_correction(c, geometry, useless_gap)
56     geometry.width  = math.max(geometry.width  - 2 * c.border_width - useless_gap, 1)
57     geometry.height = math.max(geometry.height - 2 * c.border_width - useless_gap, 1)
58     geometry.x = math.floor(geometry.x + useless_gap / 2)
59     geometry.y = math.floor(geometry.y + useless_gap / 2)
60 end
61
62 -- Check size factor for group of clients and calculate total
63 local function calc_factor(n, winfactors)
64     local factor = { window = winfactors, total = 0, min = 1 }
65
66     for i = 1, n do
67         if not factor.window[i] then
68             factor.window[i] = factor.min
69         else
70             factor.min = math.min(factor.window[i], factor.min)
71             if factor.window[i] < 0.05 then factor.window[i] = 0.05 end
72         end
73         factor.total = factor.total + factor.window[i]
74     end
75
76     return factor
77 end
78
79 -- Tile group of clients in given area
80 -- @canvas need for proper transformation only
81 -- @winfactors table with clients size factors
82 local function tile_column(canvas, area, list, useless_gap, transformation, winfactors)
83     local used = 0
84     local factor = calc_factor(#list, winfactors)
85
86     for i, c in ipairs(list) do
87         local g = cut_row(area, factor, i, used)
88         if i == #list then g.height = area.height - used end
89         used = used + g.height
90
91         -- swap workarea dimensions
92         if transformation.flip then g = flip(canvas, g) end
93         if transformation.swap then g = swap(g) end
94
95         -- useless gap and border correction
96         size_correction(c, g, useless_gap)
97
98
99         c:geometry(g)
100     end
101 end
102
103 --Main tile function
104 local function tile(p, orientation)
105
106     -- Theme vars
107     local useless_gap = beautiful.useless_gap_width or 0
108     local global_border = beautiful.global_border_width or 0
109
110     -- Aliases
111     local wa = p.workarea
112     local cls = p.clients
113     local t = tag.selected(p.screen)
114
115     -- Nothing to tile here
116     if #cls == 0 then return end
117
118     -- Get tag prop
119     local nmaster = math.min(tag.getnmaster(t), #cls)
120     local mwfact = tag.getmwfact(t)
121
122     if nmaster == 0 then
123         mwfact = 0
124     elseif nmaster == #cls then
125         mwfact = 1
126     end
127
128     -- clients size factor
129     local data = tag.getdata(t).windowfact
130
131     if not data then
132         data = {}
133         tag.getdata(t).windowfact = data
134     end
135
136     -- Workarea size correction depending on useless gap and global border
137     wa.height = wa.height - 2 * global_border - useless_gap
138     wa.width  = wa.width -  2 * global_border - useless_gap
139     wa.x = wa.x + useless_gap / 2 + global_border
140     wa.y = wa.y + useless_gap / 2 + global_border
141
142     -- Find which transformation we need for given orientation
143     local transformation = {
144         swap = orientation == 'top' or orientation == 'bottom',
145         flip = orientation == 'left' or orientation == 'top'
146     }
147
148     -- Swap workarea dimensions if orientation vertical
149     if transformation.swap then wa = swap(wa) end
150
151     -- Split master and other windows
152     local cls_master, cls_other = {}, {}
153
154     for i, c in ipairs(cls) do
155         if i <= nmaster then
156             table.insert(cls_master, c)
157         else
158             table.insert(cls_other, c)
159         end
160     end
161
162     -- Tile master windows
163     local master_area = {
164         x = wa.x,
165         y = wa.y,
166         width  = nmaster > 0 and math.floor(wa.width * mwfact) or 0,
167         height = wa.height
168     }
169
170     if not data[0] then data[0] = {} end
171     tile_column(wa, master_area, cls_master, useless_gap, transformation, data[0])
172
173     -- Tile other windows
174     local other_area = {
175         x = wa.x + master_area.width,
176         y = wa.y,
177         width  = wa.width - master_area.width,
178         height = wa.height
179     }
180
181     -- get column number for other windows
182     local ncol = math.min(tag.getncol(t), #cls_other)
183
184     if ncol == 0 then ncol = 1 end
185
186     -- split other windows to column groups
187     local last_small_column = ncol - #cls_other % ncol
188     local rows_min = math.floor(#cls_other / ncol)
189
190     local client_index = 1
191     local used = 0
192     for i = 1, ncol do
193         local position = transformation.flip and ncol - i + 1 or i
194         local rows = i <= last_small_column and rows_min or rows_min + 1
195         local column = {}
196
197         for j = 1, rows do
198             table.insert(column, cls_other[client_index])
199             client_index = client_index + 1
200         end
201
202         -- and tile
203         local column_area = cut_column(other_area, ncol, position)
204         if i == ncol then column_area.width = other_area.width - used end
205         used = used + column_area.width
206
207         if not data[i] then data[i] = {} end
208         tile_column(wa, column_area, column, useless_gap, transformation, data[i])
209     end
210 end
211
212 -- Layout constructor
213 local function construct_layout(name, orientation)
214     return {
215         name = name,
216         -- @p screen number to tile
217         arrange = function(p) return tile(p, orientation) end
218     }
219 end
220
221 -- Build layouts with different tile direction
222 uselesstile.right  = construct_layout("uselesstile", "right")
223 uselesstile.left   = construct_layout("uselesstileleft", "left")
224 uselesstile.bottom = construct_layout("uselesstilebottom", "bottom")
225 uselesstile.top    = construct_layout("uselesstiletop", "top")
226
227 -- Module aliase
228 uselesstile.arrange = uselesstile.right.arrange
229 uselesstile.name = uselesstile.right.name
230
231 return uselesstile