awful.placement: Add `align` method
This allow to place a client, wibox or cursor at the edges, corners or center of the parent geometry. This also add code from `awful.wibox` to ajust the workarea. Future commit will use `awful.placement` to place `awful.wibox`.
This commit is contained in:
parent
61d143fe98
commit
456f0bb70c
|
@ -38,6 +38,25 @@ local corners3x3 = {{"top_left" , "top" , "top_right" },
|
||||||
local corners2x2 = {{"top_left" , "top_right" },
|
local corners2x2 = {{"top_left" , "top_right" },
|
||||||
{"bottom_left", "bottom_right"}}
|
{"bottom_left", "bottom_right"}}
|
||||||
|
|
||||||
|
-- Compute the new `x` and `y`.
|
||||||
|
-- The workarea position need to be applied by the caller
|
||||||
|
local align_map = {
|
||||||
|
top_left = function(_ , _ , _ , _ ) return {x=0 , y=0 } end,
|
||||||
|
top_right = function(sw, _ , dw, _ ) return {x=sw-dw , y=0 } end,
|
||||||
|
bottom_left = function(_ , sh, _ , dh) return {x=0 , y=sh-dh } end,
|
||||||
|
bottom_right = function(sw, sh, dw, dh) return {x=sw-dw , y=sh-dh } end,
|
||||||
|
left = function(_ , sh, _ , dh) return {x=0 , y=sh/2-dh/2} end,
|
||||||
|
right = function(sw, sh, dw, dh) return {x=sw-dw , y=sh/2-dh/2} end,
|
||||||
|
top = function(sw, _ , dw, _ ) return {x=sw/2-dw/2, y=0 } end,
|
||||||
|
bottom = function(sw, sh, dw, dh) return {x=sw/2-dw/2, y=sh-dh } end,
|
||||||
|
centered = function(sw, sh, dw, dh) return {x=sw/2-dw/2, y=sh/2-dh/2} end,
|
||||||
|
center_vertical = function(_ , sh, _ , dh) return {x= nil , y=sh-dh } end,
|
||||||
|
center_horizontal = function(sw, _ , dw, _ ) return {x=sw/2-dw/2, y= nil } end,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Store function -> keys
|
||||||
|
local reverse_align_map = {}
|
||||||
|
|
||||||
--- Get the area covered by a drawin.
|
--- Get the area covered by a drawin.
|
||||||
-- @param d The drawin
|
-- @param d The drawin
|
||||||
-- @tparam[opt=nil] table new_geo A new geometry
|
-- @tparam[opt=nil] table new_geo A new geometry
|
||||||
|
@ -116,21 +135,6 @@ local function get_parent_geometry(obj, args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Convert a rectangle and matrix coordinates info into a point.
|
|
||||||
-- This is useful along with matrixes like `corners3x3` to convert
|
|
||||||
-- indices into a geometry point.
|
|
||||||
-- @tparam table geo a geometry table
|
|
||||||
-- @tparam number corner_i The horizontal matrix index
|
|
||||||
-- @tparam number corner_j The vertical matrix index
|
|
||||||
-- @tparam number n The (square) matrix dimension
|
|
||||||
-- @treturn table A table with *x* and *y* keys
|
|
||||||
local function rect_to_point(geo, corner_i, corner_j, n)
|
|
||||||
return {
|
|
||||||
x = geo.x + corner_i * math.floor(geo.width / (n-1)),
|
|
||||||
y = geo.y + corner_j * math.floor(geo.height / (n-1)),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Move a point into an area.
|
--- Move a point into an area.
|
||||||
-- This doesn't change the *width* and *height* values, allowing the target
|
-- This doesn't change the *width* and *height* values, allowing the target
|
||||||
-- area to be smaller than the source one.
|
-- area to be smaller than the source one.
|
||||||
|
@ -157,6 +161,89 @@ local function move_into_geometry(source, target)
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Update the workarea
|
||||||
|
local function wibox_update_strut(d, position)
|
||||||
|
-- If the drawable isn't visible, remove the struts
|
||||||
|
if not d.visible then
|
||||||
|
d:struts { left = 0, right = 0, bottom = 0, top = 0 }
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Detect horizontal or vertical drawables
|
||||||
|
local geo = area_common(d)
|
||||||
|
local vertical = geo.width < geo.height
|
||||||
|
|
||||||
|
-- Look into the `position` string to find the relevants sides to crop from
|
||||||
|
-- the workarea
|
||||||
|
local struts = { left = 0, right = 0, bottom = 0, top = 0 }
|
||||||
|
|
||||||
|
if vertical then
|
||||||
|
for _, v in ipairs {"right", "left"} do
|
||||||
|
if (not position) or position:match(v) then
|
||||||
|
struts[v] = geo.width
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for _, v in ipairs {"top", "bottom"} do
|
||||||
|
if (not position) or position:match(v) then
|
||||||
|
struts[v] = geo.height
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update the workarea
|
||||||
|
d:struts(struts)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Pin a drawable to a placement function.
|
||||||
|
-- Automatically update the position when the size change.
|
||||||
|
-- All other arguments will be passed to the `position` function (if any)
|
||||||
|
-- @tparam[opt=client.focus] drawable d A drawable (like `client`, `mouse`
|
||||||
|
-- or `wibox`)
|
||||||
|
-- @param position_f A position name (see `align`) or a position function
|
||||||
|
-- @tparam[opt={}] table args Other arguments
|
||||||
|
local function attach(d, position_f, args)
|
||||||
|
args = args or {}
|
||||||
|
|
||||||
|
if not args.attach then return end
|
||||||
|
|
||||||
|
d = d or capi.client.focus
|
||||||
|
if not d then return end
|
||||||
|
|
||||||
|
if type(position_f) == "string" then
|
||||||
|
position_f = placement[position_f]
|
||||||
|
end
|
||||||
|
|
||||||
|
if not position_f then return end
|
||||||
|
|
||||||
|
local function tracker()
|
||||||
|
position_f(d, args)
|
||||||
|
end
|
||||||
|
|
||||||
|
d:connect_signal("property::width" , tracker)
|
||||||
|
d:connect_signal("property::height", tracker)
|
||||||
|
|
||||||
|
tracker()
|
||||||
|
|
||||||
|
if args.update_workarea then
|
||||||
|
local function tracker_struts()
|
||||||
|
--TODO this is too fragile and doesn't work with all methods.
|
||||||
|
wibox_update_strut(d, reverse_align_map[position_f])
|
||||||
|
end
|
||||||
|
|
||||||
|
d:connect_signal("property::geometry" , tracker_struts)
|
||||||
|
d:connect_signal("property::visible" , tracker_struts)
|
||||||
|
|
||||||
|
tracker_struts()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If there is a parent drawable, screen or mouse, also track it
|
||||||
|
local parent = args.parent or d.screen
|
||||||
|
if parent then
|
||||||
|
args.parent:connect_signal("property::geometry" , tracker)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Check if an area intersect another area.
|
--- Check if an area intersect another area.
|
||||||
-- @param a The area.
|
-- @param a The area.
|
||||||
-- @param b The other area.
|
-- @param b The other area.
|
||||||
|
@ -276,7 +363,7 @@ function placement.closest_corner(d, args)
|
||||||
|
|
||||||
-- Transpose the corner back to the original size
|
-- Transpose the corner back to the original size
|
||||||
local new_args = setmetatable({position = corner}, {__index=args})
|
local new_args = setmetatable({position = corner}, {__index=args})
|
||||||
geometry_common(d, new_args, rect_to_point(dgeo, corner_i, corner_j , n))
|
placement.align(d, new_args)
|
||||||
|
|
||||||
return corner
|
return corner
|
||||||
end
|
end
|
||||||
|
@ -409,6 +496,52 @@ function placement.next_to_mouse(c, offset)
|
||||||
return c:geometry({ x = x, y = y })
|
return c:geometry({ x = x, y = y })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Move the drawable (client or wibox) `d` to a screen position or side.
|
||||||
|
--
|
||||||
|
-- Supported args.positions are:
|
||||||
|
--
|
||||||
|
-- * top_left
|
||||||
|
-- * top_right
|
||||||
|
-- * bottom_left
|
||||||
|
-- * bottom_right
|
||||||
|
-- * left
|
||||||
|
-- * right
|
||||||
|
-- * top
|
||||||
|
-- * bottom
|
||||||
|
-- * centered
|
||||||
|
-- * center_vertical
|
||||||
|
-- * center_horizontal
|
||||||
|
--
|
||||||
|
--@DOC_awful_placement_align_EXAMPLE@
|
||||||
|
-- @tparam drawable d A drawable (like `client`, `mouse` or `wibox`)
|
||||||
|
-- @tparam[opt={}] table args Other arguments
|
||||||
|
function placement.align(d, args)
|
||||||
|
args = args or {}
|
||||||
|
d = d or capi.client.focus
|
||||||
|
|
||||||
|
if not d or not args.position then return end
|
||||||
|
|
||||||
|
local sgeo = get_parent_geometry(d, args)
|
||||||
|
local dgeo = geometry_common(d, args)
|
||||||
|
local bw = d.border_width or 0
|
||||||
|
|
||||||
|
local pos = align_map[args.position](
|
||||||
|
sgeo.width ,
|
||||||
|
sgeo.height,
|
||||||
|
dgeo.width ,
|
||||||
|
dgeo.height
|
||||||
|
)
|
||||||
|
|
||||||
|
geometry_common(d, args, {
|
||||||
|
x = (pos.x and math.ceil(sgeo.x + pos.x) or dgeo.x) + bw ,
|
||||||
|
y = (pos.y and math.ceil(sgeo.y + pos.y) or dgeo.y) + bw ,
|
||||||
|
width = math.ceil(dgeo.width ) - 2*bw,
|
||||||
|
height = math.ceil(dgeo.height ) - 2*bw,
|
||||||
|
})
|
||||||
|
|
||||||
|
attach(d, placement[args.position], args)
|
||||||
|
end
|
||||||
|
|
||||||
--- Place the client centered with respect to a parent or the clients screen.
|
--- Place the client centered with respect to a parent or the clients screen.
|
||||||
-- @param c The client.
|
-- @param c The client.
|
||||||
-- @param[opt] p The parent (nil for screen centering).
|
-- @param[opt] p The parent (nil for screen centering).
|
||||||
|
|
Loading…
Reference in New Issue