placement: Allow to configure the next_to anchors

They were previously hardcoded to match the classic context menu
behavior. It isn't flexible enough for some popup type.
This commit is contained in:
Emmanuel Lepage Vallee 2018-01-09 08:40:19 -05:00
parent 3fa42f3b1a
commit f1145af49d
1 changed files with 49 additions and 20 deletions

View File

@ -262,16 +262,19 @@ local resize_to_point_map = {
}
-- Outer position matrix
-- 1=best case, 2=fallback
local outer_positions = {
left1 = function(r, w, _) return {x=r.x-w , y=r.y }, "down" end,
left2 = function(r, w, h) return {x=r.x-w , y=r.y-h+r.height }, "up" end,
right1 = function(r, _, _) return {x=r.x , y=r.y }, "down" end,
right2 = function(r, _, h) return {x=r.x , y=r.y-h+r.height }, "up" end,
top1 = function(r, _, h) return {x=r.x , y=r.y-h }, "right" end,
top2 = function(r, w, h) return {x=r.x-w+r.width, y=r.y-h }, "left" end,
bottom1 = function(r, _, _) return {x=r.x , y=r.y }, "right" end,
bottom2 = function(r, w, _) return {x=r.x-w+r.width, y=r.y }, "left" end,
left_front = function(r, w, _) return {x=r.x-w , y=r.y }, "front" end,
left_back = function(r, w, h) return {x=r.x-w , y=r.y-h+r.height }, "back" end,
left_middle = function(r, w, h) return {x=r.x-w , y=r.y-h/2+r.height/2 }, "middle" end,
right_front = function(r, _, _) return {x=r.x , y=r.y }, "front" end,
right_back = function(r, _, h) return {x=r.x , y=r.y-h+r.height }, "back" end,
right_middle = function(r, _, h) return {x=r.x , y=r.y-h/2+r.height/2 }, "middle" end,
top_front = function(r, _, h) return {x=r.x , y=r.y-h }, "front" end,
top_back = function(r, w, h) return {x=r.x-w+r.width , y=r.y-h }, "back" end,
top_middle = function(r, w, h) return {x=r.x-w/2+r.width/2, y=r.y-h }, "middle" end,
bottom_front = function(r, _, _) return {x=r.x , y=r.y }, "front" end,
bottom_back = function(r, w, _) return {x=r.x-w+r.width , y=r.y }, "back" end,
bottom_middle = function(r, w, _) return {x=r.x-w/2+r.width/2, y=r.y }, "middle" end,
}
--- Add a context to the arguments.
@ -1353,28 +1356,55 @@ end
--- Move a drawable to a relative position next to another one.
--
-- This placement function offers two additional settings to align the drawable
-- alongside the parent geometry. The first one, the position, sets the side
-- relative to the parent. The second one, the anchor, set the alignment within
-- the side selected by the `preferred_positions`. Both settings are tables of
-- priorities. The first available slot will be used. If there isn't enough
-- space, then it will fallback to the next until it is possible to fit the
-- drawable. This is meant to avoid going offscreen.
--
-- The `args.preferred_positions` look like this:
--
-- {"top", "right", "left", "bottom"}
--
-- The `args.preferred_anchors` are:
--
-- * "front": The closest to the origin (0,0)
-- * "middle": Centered aligned with the parent
-- * "back": The opposite side compared to `front`
--
-- In that case, if there is room on the top of the geometry, then it will have
-- priority, followed by all the others, in order.
--
-- @tparam drawable d A wibox or client
-- @tparam table args
-- @tparam string args.mode The mode
-- @tparam string args.preferred_positions The preferred positions (in order)
-- @tparam string|table args.preferred_positions The preferred positions (in order)
-- @tparam string|table args.preferred_anchors The preferred anchor(s) (in order)
-- @tparam string args.geometry A geometry inside the other drawable
-- @treturn table The new geometry
-- @treturn string The choosen position
-- @treturn string The choosen direction
-- @treturn string The choosen position ("left", "right", "top" or "bottom")
-- @treturn string The choosen anchor ("front", "middle" or "back")
function placement.next_to(d, args)
args = add_context(args, "next_to")
d = d or capi.client.focus
local preferred_positions = {}
local original_pos, original_anchors = args.preferred_positions, args.preferred_anchors
for k, v in ipairs(args.preferred_positions or {}) do
if type(original_pos) == "string" then
original_pos = {original_pos}
end
if type(original_anchors) == "string" then
original_anchors = {original_anchors}
end
local preferred_positions = {}
local preferred_anchors = #(original_anchors or {}) > 0 and
original_anchors or {"front", "back", "middle"}
for k, v in ipairs(original_pos or {}) do
preferred_positions[v] = k
end
@ -1406,15 +1436,14 @@ function placement.next_to(d, args)
-- and order them by preferred_positions
local does_fit = {}
for k,v in pairs(regions) do
local geo, dir = outer_positions[k.."1"](v, dgeo.width, dgeo.height)
geo.width, geo.height = dgeo.width, dgeo.height
local fit = fit_in_bounding(v.screen, geo, args)
local geo, dir, fit
-- Try the other compatible geometry
if not fit then
geo, dir = outer_positions[k.."2"](v, dgeo.width, dgeo.height)
-- Try each anchor until one that fits is found
for _, anchor in ipairs(preferred_anchors) do
geo, dir = outer_positions[k.."_"..anchor](v, dgeo.width, dgeo.height)
geo.width, geo.height = dgeo.width, dgeo.height
fit = fit_in_bounding(v.screen, geo, args)
if fit then break end
end
does_fit[k] = fit and {geo, dir} or nil