placement: Make sure `next_to` result is consistent across calls

It depended on a hash `pairs` iteration. This caused an issue only when
the primary position wasn't available.
This commit is contained in:
Emmanuel Lepage Vallee 2018-01-16 02:38:17 -05:00
parent f1145af49d
commit 33a39ce38d
1 changed files with 37 additions and 11 deletions

View File

@ -1432,39 +1432,65 @@ function placement.next_to(d, args)
local regions = get_relative_regions(wgeo, mode, is_absolute) local regions = get_relative_regions(wgeo, mode, is_absolute)
-- Order the regions with the preferred_positions, then the defaults
local sorted_regions, default_positions = {}, {"left", "right", "bottom", "top"}
for _, pos in ipairs(original_pos or {}) do
for idx, def in ipairs(default_positions) do
if def == pos then
table.remove(default_positions, idx)
break
end
end
table.insert(sorted_regions, {name = pos, region = regions[pos]})
end
for _, pos in ipairs(default_positions) do
table.insert(sorted_regions, {name = pos, region = regions[pos]})
end
-- Check each possible slot around the drawable (8 total), see what fits -- Check each possible slot around the drawable (8 total), see what fits
-- and order them by preferred_positions -- and order them by preferred_positions
local does_fit = {} local does_fit = {}
for k,v in pairs(regions) do for _, pos in ipairs(sorted_regions) do
local geo, dir, fit local geo, dir, fit
-- Try each anchor until one that fits is found -- Try each anchor until one that fits is found
for _, anchor in ipairs(preferred_anchors) do for _, anchor in ipairs(preferred_anchors) do
geo, dir = outer_positions[k.."_"..anchor](v, dgeo.width, dgeo.height) geo, dir = outer_positions[pos.name.."_"..anchor](pos.region, dgeo.width, dgeo.height)
geo.width, geo.height = dgeo.width, dgeo.height geo.width, geo.height = dgeo.width, dgeo.height
fit = fit_in_bounding(v.screen, geo, args)
fit = fit_in_bounding(pos.region.screen, geo, args)
if fit then break end if fit then break end
end end
does_fit[k] = fit and {geo, dir} or nil does_fit[pos.name] = fit and {geo, dir} or nil
if fit and preferred_positions[k] and preferred_positions[k] < pref_idx then if fit and preferred_positions[pos.name] and preferred_positions[pos.name] < pref_idx then
pref_idx = preferred_positions[k] pref_idx = preferred_positions[pos.name]
pref_name = k pref_name = pos.name
end end
-- No need to continue -- No need to continue
if fit and preferred_positions[k] == 1 then break end if fit then break end
end end
local pos_name = pref_name or next(does_fit) local ngeo, dir = unpack(does_fit[pref_name] or {}) --FIXME why does this happen
local ngeo, dir = unpack(does_fit[pos_name] or {}) --FIXME why does this happen
-- The requested placement isn't possible due to the lack of space, better
-- do nothing an try random things
if not ngeo then return end
remove_border(d, args, ngeo)
geometry_common(d, args, ngeo) geometry_common(d, args, ngeo)
attach(d, placement.next_to, args) attach(d, placement.next_to, args)
return fix_new_geometry(ngeo, args, true), pos_name, dir return fix_new_geometry(ngeo, args, true), pref_name, dir
end end
--- Restore the geometry. --- Restore the geometry.