------------------------------------------------- -- @author Lukas Hrazky -- @copyright 2009 Gregor Best, Lukas Hrazky -- @release @AWESOME_VERSION@ ------------------------------------------------- local setmetatable = setmetatable local require = require local ipairs = ipairs local pairs = pairs local type = type local insert = table.insert local min = math.min local max = math.max local util = require("awful.util") local clone = util.table.clone local margins = awful.widget.layout.margins local layout = awful.widget.layout --module("awful.widget.layout.grid") local M = {} -- Creates an iterator over the cell sizes from the direction string. -- It takes the bounds for the grid, the row/column sizes and a direction and returns an iterator -- over the slices of the bounds whose sizes are determined by 'widths' or 'heights'. The 'direction' -- determines which of these will be used and whether it will be in reverse or not. -- @param direction The direction in which to iterate: 'leftright', 'rightleft', 'topdown' or 'bottomup' -- @param bounds The bounds for the iterator, will be sliced according to direction -- @param widths The widths of the columns in the grid -- @param heights The heights of the rows in the grid -- @return An iterator over the slices of the bounds local function direction_iter(direction, bounds, widths, heights) local iter local i = 0 local idx, sizes -- preset the closure upvalues according to the direction if direction == "leftright" or direction == "rightleft" then idx = layout.regular_index sizes = widths elseif direction == "topdown" or direction == "bottomup" then idx = layout.switched_index sizes = heights end if direction == "leftright" or direction == "topdown" then -- the regular direction iterator iter = function(bounds) i = i + 1 if not sizes[i] then return end local b = clone(bounds) local width = min(sizes[i], b[idx.width]) b[idx.width] = width bounds[idx.x] = bounds[idx.x] + width + sizes.gap bounds[idx.width] = bounds[idx.width] - width return b end elseif direction == "rightleft" or direction == "bottomup" then -- the reverse direction iterator iter = function(bounds) i = i + 1 if not sizes[i] then return end local b = clone(bounds) local width = min(sizes[i], b[idx.width]) b[idx.x] = b[idx.x] + b[idx.width] - width + sizes.gap b[idx.width] = width bounds[idx.width] = bounds[idx.width] - width return b end end return iter, bounds end -- Places the widgets in a grid. -- @see awful.widget.layout for a luadoc local function grid(bounds, widgets, screen) local widths = {} local heights = {} -- we either have a table with the widths of the cells, or its a number and there is a col_count if type(widgets.cell_width) == "table" then widths = widgets.cell_width else for i = 1, widgets.col_count do widths[i] = widgets.cell_width end end -- we either have a table with the heights of the cells, or its a number and there is a row_count if type(widgets.cell_height) == "table" then heights = widgets.cell_height else for i = 1, widgets.row_count do heights[i] = widgets.cell_height end end widths.gap = widgets.col_gap or 0 heights.gap = widgets.row_gap or 0 -- calculate total space required for the grid local w = - widths.gap local h = - heights.gap for _, v in ipairs(widths) do w = w + v + widths.gap end for _, v in ipairs(heights) do h = h + v + heights.gap end bounds.width = min(bounds.width, w) bounds.height = min(bounds.height, h) -- 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)} -- i counts the widgets placed in the grid local i = 1 -- the iterators return the bounds for the cells of the table. first one in secondary direction -- returns rows or columns, second one returns cell bounds in that row/column for sb in direction_iter(widgets.secondary_dir or "topdown", bounds, widths, heights) do for b in direction_iter(widgets.primary_dir or "leftright", sb, widths, heights) do -- get the next widget, if there is none, we are done, some cells won't be filled local w = widgets[i] if not w then break end if type(w) == "table" or type(w) == "widget" then local m = margins[w] -- shrink the cell bounds by the margins b.width = b.width - m.left - m.right b.height = b.height - m.top - m.bottom b.x = b.x + m.left b.y = b.y + m.top if type(w) == "table" then -- backup the width and height of the table so we can restore it local t_width = w.width local t_height = w.height -- if the 'widgets' table has height set and the table itself doesn't, we set it if widgets.resize then w.width = b.width w.height = b.height end -- call the layout function recursively on this table local layout = w.layout or layout.default local g = layout(b, w, screen) -- restore the table's original width and height w.width = t_width w.height = t_height -- insert all geometries from the table to our geometries for _, w in ipairs(g) do insert(geometries, w) end elseif type(widgets[i]) == "widget" then local g = {x = 0, y = 0, width = 0, height = 0} if widgets[i].visible then -- get the geometry of the widget g = widgets[i]:extents(screen) -- set the coords g.x = b.x g.y = b.y -- if we are resizing or it doesn't fit inside the bounds, set width/height if widgets.resize or g.width > b.width then g.width = b.width end if widgets.resize or g.height > b.height then g.height = b.height end end insert(geometries, g) end i = i + 1 end end end -- set zero geometries for any leftover widgets -- Hack: if it has been registered as a widget in a wibox, -- it's w.len since __len meta does not work on table until Lua 5.2. -- Otherwise it's standard #w. local len = (widgets.len or #widgets) for j = i, len do insert(geometries, {x = 0, y = 0, width = 0, height = 0}) end return geometries end --setmetatable(_M, { __call = function(_, ...) return grid(...) end }) return grid -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80