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

b94a74d45c3eb1c4bf38e05a133838131e7e165e
[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     for i = 1, ncol do
192         local position = transformation.flip and ncol - i + 1 or i
193         local rows = i <= last_small_column and rows_min or rows_min + 1
194         local column = {}
195
196         for j = 1, rows do
197             table.insert(column, cls_other[client_index])
198             client_index = client_index + 1
199         end
200
201         -- and tile
202         local column_area = cut_column(other_area, ncol, position)
203
204         if not data[i] then data[i] = {} end
205         tile_column(wa, column_area, column, useless_gap, transformation, data[i])
206     end
207 end
208
209 -- Layout constructor
210 local function construct_layout(name, orientation)
211     return {
212         name = name,
213         -- @p screen number to tile
214         arrange = function(p) return tile(p, orientation) end
215     }
216 end
217
218 -- Build layouts with different tile direction
219 uselesstile.right  = construct_layout("uselesstile", "right")
220 uselesstile.left   = construct_layout("uselesstileleft", "left")
221 uselesstile.bottom = construct_layout("uselesstilebottom", "bottom")
222 uselesstile.top    = construct_layout("uselesstiletop", "top")
223
224 -- Module aliase
225 uselesstile.arrange = uselesstile.right.arrange
226 uselesstile.name = uselesstile.right.name
227
228 return uselesstile