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

e48c85d4b9132f096de26a0a0b6985c5f1584505
[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 = 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 = 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 = geometry.x + useless_gap / 2
59     geometry.y = 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         used = used + g.height
89
90         -- swap workarea dimensions
91         if transformation.flip then g = flip(canvas, g) end
92         if transformation.swap then g = swap(g) end
93
94         -- useless gap and border correction
95         size_correction(c, g, useless_gap)
96
97         c:geometry(g)
98     end
99 end
100
101 --Main tile function
102 local function tile(p, orientation)
103
104     -- Theme vars
105     local useless_gap = beautiful.useless_gap_width or 0
106     local global_border = beautiful.global_border_width or 0
107
108     -- Aliases
109     local wa = p.workarea
110     local cls = p.clients
111     local t = tag.selected(p.screen)
112
113     -- Nothing to tile here
114     if #cls == 0 then return end
115
116     -- Get tag prop
117     local nmaster = math.min(tag.getnmaster(t), #cls)
118     local mwfact = tag.getmwfact(t)
119
120     if nmaster == 0 then
121         mwfact = 0
122     elseif nmaster == #cls then
123         mwfact = 1
124     end
125
126     -- clients size factor
127     local data = tag.getdata(t).windowfact
128
129     if not data then
130         data = {}
131         tag.getdata(t).windowfact = data
132     end
133
134     -- Workarea size correction depending on useless gap and global border
135     wa.height = wa.height - 2 * global_border - useless_gap
136     wa.width  = wa.width -  2 * global_border - useless_gap
137     wa.x = wa.x + useless_gap / 2 + global_border
138     wa.y = wa.y + useless_gap / 2 + global_border
139
140     -- Find which transformation we need for given orientation
141     local transformation = {
142         swap = orientation == 'top' or orientation == 'bottom',
143         flip = orientation == 'left' or orientation == 'top'
144     }
145
146     -- Swap workarea dimensions if orientation vertical
147     if transformation.swap then wa = swap(wa) end
148
149     -- Split master and other windows
150     local cls_master, cls_other = {}, {}
151
152     for i, c in ipairs(cls) do
153         if i <= nmaster then
154             table.insert(cls_master, c)
155         else
156             table.insert(cls_other, c)
157         end
158     end
159
160     -- Tile master windows
161     local master_area = {
162         x = wa.x,
163         y = wa.y,
164         width  = nmaster > 0 and wa.width * mwfact or 0,
165         height = wa.height
166     }
167
168     if not data[0] then data[0] = {} end
169     tile_column(wa, master_area, cls_master, useless_gap, transformation, data[0])
170
171     -- Tile other windows
172     local other_area = {
173         x = wa.x + master_area.width,
174         y = wa.y,
175         width  = wa.width - master_area.width,
176         height = wa.height
177     }
178
179     -- get column number for other windows
180     local ncol = math.min(tag.getncol(t), #cls_other)
181
182     if ncol == 0 then ncol = 1 end
183
184     -- split other windows to column groups
185     local last_small_column = ncol - #cls_other % ncol
186     local rows_min = math.floor(#cls_other / ncol)
187
188     local client_index = 1
189     for i = 1, ncol do
190         local position = transformation.flip and ncol - i + 1 or i
191         local rows = i <= last_small_column and rows_min or rows_min + 1
192         local column = {}
193
194         for j = 1, rows do
195             table.insert(column, cls_other[client_index])
196             client_index = client_index + 1
197         end
198
199         -- and tile
200         local column_area = cut_column(other_area, ncol, position)
201
202         if not data[i] then data[i] = {} end
203         tile_column(wa, column_area, column, useless_gap, transformation, data[i])
204     end
205 end
206
207 -- Layout constructor
208 local function construct_layout(name, orientation)
209     return {
210         name = name,
211         -- @p screen number to tile
212         arrange = function(p) return tile(p, orientation) end
213     }
214 end
215
216 -- Build layouts with different tile direction
217 uselesstile.right  = construct_layout("uselesstile", "right")
218 uselesstile.left   = construct_layout("uselesstileleft", "left")
219 uselesstile.bottom = construct_layout("uselesstilebottom", "bottom")
220 uselesstile.top    = construct_layout("uselesstiletop", "top")
221
222 -- Module aliase
223 uselesstile.arrange = uselesstile.right.arrange
224 uselesstile.name = uselesstile.right.name
225
226 return uselesstile