awesome/lib/awful/widget/layout/grid.lua.in

201 lines
7.3 KiB
Lua

-------------------------------------------------
-- @author Lukas Hrazky <lukkash@email.cz>
-- @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
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
function M.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
return M
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80