------------------------------------------------- -- @author Gregor Best , Lukas Hrazky -- @copyright 2009 Gregor Best, Lukas Hrazky -- @release @AWESOME_VERSION@ ------------------------------------------------- local setmetatable = setmetatable local require = require local ipairs = ipairs local type = type local insert = table.insert local min = math.min local max = math.max local floor = math.floor local util = require("awful.util") local clone = util.table.clone local margins = awful.widget.layout.margins local layout = awful.widget.layout local linear_common = {} -- Calculates geometries for fixed layouts. -- This generic function is used for all layouts exept flex. -- It is written for horizontal layouts, but by using a special index 'idx' to access -- all the geometry attributes, it is used for vertical layouts too. In that case, 'idx' -- returns 'y' for 'x', 'width' for 'height', etc. -- @param idx An index table that defines whether horzintal or vertical arrangement will be -- calculated. See regular_index and switched_index tables. -- @param bounds The geometry of the bounds for the layout. -- @param widgets The table of the widgets to layout, can be nested. -- @param screen The screen of the wibox. -- @return A table of geometries of all the widgets. function linear_common.fixed(idx, bounds, widgets, screen) -- set bounds width and height to what is preset in the widgets table (if there is something) -- we don't need to use idx here since we're treating both directions the same way if widgets.width and widgets.width < bounds.width then bounds.width = widgets.width end if widgets.height and widgets.height < bounds.height then bounds.height = widgets.height end -- the table for the geometries which will be returned -- we clone the bounds to the 'total' attribute. bounds are used to keep the free space -- throughout this function. at the end, 'total' is modified to represent the space taken -- by all widgets local geometries = {total = clone(bounds)} -- the height of the heighest widget, will be the height of the total space taken local maxh = 0 for _, v in ipairs(widgets) do if type(v) == "table" or type(v) == "widget" then local m = margins[v] -- we can shrink the bounds by the horizontal margins right now, they affect our free -- space directly (vertical don't, they are different for every item in 'widgets') bounds[idx.width] = bounds[idx.width] - m[idx.left] - m[idx.right] bounds[idx.x] = bounds[idx.x] + m[idx.left] if type(v) == "table" then -- create new bounds for the table and shrink it by the vertical margins local t_bounds = clone(bounds) t_bounds[idx.height] = t_bounds[idx.height] - m[idx.top] - m[idx.bottom] t_bounds[idx.y] = t_bounds[idx.y] + m[idx.top] -- backup the width and height of the table so we can restore it local t_width = v.width local t_height = v.height -- if the 'widgets' table has height set and the table itself doesn't, we set it v[idx.height] = v[idx.height] or widgets[idx.height] -- call the layout function recursively on this table local layout = v.layout or layout.default local g = layout(t_bounds, v, screen) -- restore the table's original width and height v.width = t_width v.height = t_height -- subtract the space taken by the table from our bounds - only if the taken space -- is either on the left or on the right of our bounds (not in the middle) if g.total[idx.x] == bounds[idx.x] or g.total[idx.x] + g.total[idx.width] == bounds[idx.x] + bounds[idx.width] then bounds[idx.width] = bounds[idx.width] - g.total[idx.width] end -- we only move the 'x' coord if the taken space is on the left side of our bounds if g.total[idx.x] == bounds[idx.x] then bounds[idx.x] = bounds[idx.x] + g.total[idx.width] + m[idx.right] end -- update the maximum height with this new table maxh = max(maxh, g.total[idx.height] + m[idx.top] + m[idx.bottom]) -- insert all geometries from the table to our geometries for _, w in ipairs(g) do insert(geometries, w) end elseif type(v) == "widget" then local g = {x = 0, y = 0, width = 0, height = 0} if v.visible then -- get the geometry of the widget g = v:extents(screen) -- resize to fit the height available if requested if v.resize and g.width > 0 and g.height > 0 then local ratio = g[idx.width] / g[idx.height] g[idx.width] = floor(bounds[idx.height] * ratio) g[idx.height] = bounds[idx.height] end -- set the coords, apply the top margin g[idx.y] = bounds[idx.y] + m[idx.top] g[idx.x] = bounds[idx.x] -- limit the width of the widget to what's available g[idx.width] = min(g[idx.width], bounds[idx.width]) -- if the 'widgets' table has height set, we set it to the widget g[idx.height] = widgets[idx.height] and (widgets[idx.height] - m[idx.top] - m[idx.bottom]) or g[idx.height] -- limit the height of the widget to what's available g[idx.height] = min(g[idx.height], bounds[idx.height] - m[idx.top] - m[idx.bottom]) -- subtract the space taken by the widget from our bounds bounds[idx.width] = bounds[idx.width] - g[idx.width] -- move bounds right by the widget's width bounds[idx.x] = bounds[idx.x] + g[idx.width] + m[idx.right] -- update the maximum height with height of this widget maxh = max(maxh, g[idx.height] + m[idx.top] + m[idx.bottom]) end insert(geometries, g) end end end -- calculate the total space taken by the widgets geometries.total[idx.width] = geometries.total[idx.width] - bounds[idx.width] geometries.total[idx.height] = maxh -- if the bounds are on the left of what was empty in the beginning of this function, -- we move the total to the right. this, however, most probably happened cos of rightleft layout -- inside 'widgets', and only if there was nothing aligned to the left if geometries.total[idx.x] == bounds[idx.x] then geometries.total[idx.x] = geometries.total[idx.x] + bounds[idx.width] end return geometries end -- Calculates geometries for flex layouts. -- This generic function is used for all flex layouts. -- It is written for horizontal layouts, but by using special index 'idx' to access -- all the geometry attributes, it is used for vertical layouts too. In that case, 'idx' -- returns 'y' for 'x', 'width' for 'height', etc. -- @param idx An index table that defines whether horzintal or vertical arrangement will be -- calculated. See regular_index and switched_index tables. -- @param bounds The geometry of the bounds for the layout. -- @param widgets The table of the widgets to layout, can be nested. -- @param screen The screen of the wibox. -- @return A table of geometries of all the widgets. function linear_common.flex(idx, bounds, widgets, screen) -- set bounds width and height to what is preset in the widgets table (if there is something) -- we don't need to use idx here since we're treating both directions the same way if widgets.width and widgets.width < bounds.width then bounds.width = widgets.width end if widgets.height and widgets.height < bounds.height then bounds.height = widgets.height end -- the table for the geometries which will be returned -- we clone the bounds to the 'total' attribute. bounds are used to keep the free space -- throughout this function. at the end, 'total' is modified to represent the space taken -- by all widgets local geometries = {total = clone(bounds)} -- the height of the heighest widget, will be the height of the total space taken local maxh = 0 -- the number of widgets/tables in 'widgets' argument local n = 0 -- get the gap or set to 0 local gap = widgets.gap or 0 -- count the widgets/tables for _, v in ipairs(widgets) do if type(v) == "table" or (type(v) == "widget" and v.visible) then n = n + 1 end end -- calculate the width. these vars keep the floating numbers, while bounds keep the -- rounded ones and are set from these on each iteration to ensure proper rounding local width = (n > 0) and ((widgets[idx.width] or bounds[idx.width]) - gap * (n - 1)) / n or 0 local x = bounds[idx.x] -- if max_size is set and it is lower than the calculated width, use it width = (widgets.max_size and widgets.max_size < width) and widgets.max_size or width for _, v in ipairs(widgets) do -- someone give me freaking continue if type(v) == "widget" and not v.visible then insert(geometries, {x = 0, y = 0, width = 0, height = 0}) elseif type(v) == "widget" or type(v) == "table" then -- do the floating magic, calculate real_width which will be set to the geometries x = x + width local real_width = floor(x - bounds[idx.x] + 0.5) local m = margins[v] if type(v) == "table" then -- create new bounds for the table and shrink it by the margins local t_bounds = {} t_bounds[idx.x] = bounds[idx.x] + m[idx.left] t_bounds[idx.y] = bounds[idx.y] + m[idx.top] t_bounds[idx.width] = real_width - m[idx.left] - m[idx.right] t_bounds[idx.height] = bounds[idx.height] - m[idx.top] - m[idx.bottom] -- backup the width and height of the table so we can restore it local t_width = v.width local t_height = v.height -- set the table's width so it can flex what's inside it v[idx.width] = real_width -- if the 'widgets' table has height set and the table itself doesn't, we set it v[idx.height] = v[idx.height] or widgets[idx.height] -- call the layout function recursively on this table local layout = v.layout or layout.default local g = layout(t_bounds, v, screen) -- restore the table's original width and height v.width = t_width v.height = t_height -- update the maximum height with this new table maxh = max(maxh, g.total[idx.height] + m[idx.top] + m[idx.bottom]) for _, v in ipairs(g) do insert(geometries, v) end elseif type(v) == "widget" then g = v:extents(screen) -- resize to fit the width available if requested if v.resize and g.width > 0 and g.height > 0 then local ratio = g[idx.height] / g[idx.width] g[idx.height] = real_width * ratio end -- set the widget geometry g[idx.x] = bounds[idx.x] + m[idx.left] g[idx.width] = real_width - m[idx.left] - m[idx.right] g[idx.y] = bounds[idx.y] + m[idx.top] -- if the 'widgets' table has height set, we set it to the widget g[idx.height] = widgets[idx.height] and (widgets[idx.height] - m[idx.top] - m[idx.bottom]) or g[idx.height] -- limit the height of the widget to what's available g[idx.height] = min(g[idx.height], bounds[idx.height] - m[idx.top] - m[idx.bottom]) -- update the maximum height with height of this widget maxh = max(maxh, g[idx.height] + m[idx.top] + m[idx.bottom]) insert(geometries, g) end -- update the bounds (move it to the right by the widget's width) bounds[idx.width] = bounds[idx.width] - real_width - gap x = x + gap bounds[idx.x] = floor(x + 0.5) end end -- we have total already from the cloned bounds, just set the height to what we got geometries.total[idx.width] = geometries.total[idx.width] - bounds[idx.width] geometries.total[idx.height] = maxh return geometries end return linear_common -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80