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

291 lines
13 KiB
Lua

-------------------------------------------------
-- @author Gregor Best <farhaven@googlemail.com>, Lukas Hrazky <lukkash@email.cz>
-- @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
local 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